merge from eclair
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
@@ -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" />
|
||||
|
||||
20
samples/ApiDemos/res/anim/hold.xml
Normal file
@@ -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" />
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
28
samples/ApiDemos/res/anim/zoom_enter.xml
Normal file
@@ -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>
|
||||
33
samples/ApiDemos/res/anim/zoom_exit.xml
Normal file
@@ -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>
|
||||
BIN
samples/ApiDemos/res/drawable-hdpi/alert_dialog_icon.png
Executable file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/app_sample_code.png
Executable file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/arrow_down_float.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/arrow_up_float.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/btn_check_off.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/btn_check_on.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/btn_circle_normal.png
Executable file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/btn_default_normal.9.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/button.9.png
Executable file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/ic_popup_reminder.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/icon48x48_2.png
Executable file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/progress_circular_background.png
Executable file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/progress_particle.png
Executable file
|
After Width: | Height: | Size: 634 B |
BIN
samples/ApiDemos/res/drawable-hdpi/robot.png
Executable file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/scrollbar_state2.png
Executable file
|
After Width: | Height: | Size: 495 B |
BIN
samples/ApiDemos/res/drawable-hdpi/star_big_on.png
Executable file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
samples/ApiDemos/res/drawable-hdpi/stat_happy.png
Executable file
|
After Width: | Height: | Size: 634 B |
BIN
samples/ApiDemos/res/drawable-hdpi/stat_neutral.png
Executable file
|
After Width: | Height: | Size: 604 B |
BIN
samples/ApiDemos/res/drawable-hdpi/stat_sad.png
Executable file
|
After Width: | Height: | Size: 660 B |
BIN
samples/ApiDemos/res/drawable-hdpi/stat_sample.png
Executable file
|
After Width: | Height: | Size: 364 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 686 B After Width: | Height: | Size: 686 B |
|
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 683 B |
BIN
samples/ApiDemos/res/drawable-mdpi/btn_check_off.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
samples/ApiDemos/res/drawable-mdpi/btn_check_on.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
samples/ApiDemos/res/drawable-mdpi/btn_circle_normal.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
samples/ApiDemos/res/drawable-mdpi/btn_default_normal.9.png
Normal file
|
After Width: | Height: | Size: 763 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
42
samples/ApiDemos/res/layout/activity_animation.xml
Normal file
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -363,8 +370,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>
|
||||
@@ -633,13 +640,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -63,6 +64,14 @@ public class LocalService extends Service {
|
||||
showNotification();
|
||||
}
|
||||
|
||||
@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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
1
samples/ApiDemos/tests/build.properties
Normal file
@@ -0,0 +1 @@
|
||||
tested.project.dir=..
|
||||
36
samples/BrowserPlugin/Android.mk
Normal file
@@ -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))
|
||||
35
samples/BrowserPlugin/AndroidManifest.xml
Normal file
@@ -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>
|
||||
0
samples/BrowserPlugin/MODULE_LICENSE_APACHE2
Normal file
190
samples/BrowserPlugin/NOTICE
Normal file
@@ -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
|
||||
|
||||
173
samples/BrowserPlugin/README
Normal file
@@ -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.
|
||||
64
samples/BrowserPlugin/jni/Android.mk
Normal file
@@ -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)
|
||||
|
||||
177
samples/BrowserPlugin/jni/PluginObject.cpp
Normal file
@@ -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<6C>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;
|
||||
}
|
||||
85
samples/BrowserPlugin/jni/PluginObject.h
Normal file
@@ -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<6C>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
|
||||
197
samples/BrowserPlugin/jni/animation/AnimationPlugin.cpp
Normal file
@@ -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
|
||||
}
|
||||
52
samples/BrowserPlugin/jni/animation/AnimationPlugin.h
Normal file
@@ -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
|
||||
382
samples/BrowserPlugin/jni/audio/AudioPlugin.cpp
Normal file
@@ -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);
|
||||
}
|
||||
74
samples/BrowserPlugin/jni/audio/AudioPlugin.h
Normal file
@@ -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
|
||||
423
samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp
Normal file
@@ -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);
|
||||
}
|
||||
69
samples/BrowserPlugin/jni/background/BackgroundPlugin.h
Normal file
@@ -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
|
||||
381
samples/BrowserPlugin/jni/form/FormPlugin.cpp
Normal file
@@ -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;
|
||||
}
|
||||
72
samples/BrowserPlugin/jni/form/FormPlugin.h
Normal file
@@ -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
|
||||
48
samples/BrowserPlugin/jni/hello-jni.cpp
Normal file
@@ -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;
|
||||
}
|
||||
85
samples/BrowserPlugin/jni/jni-bridge.cpp
Normal file
@@ -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;
|
||||
}
|
||||
412
samples/BrowserPlugin/jni/main.cpp
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
32
samples/BrowserPlugin/jni/main.h
Normal file
@@ -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;
|
||||
388
samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
Normal file
@@ -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);
|
||||
}
|
||||
76
samples/BrowserPlugin/jni/paint/PaintPlugin.h
Normal file
@@ -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
|
||||
BIN
samples/BrowserPlugin/res/drawable-hdpi/sample_browser_plugin.png
Executable file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
samples/BrowserPlugin/res/drawable-mdpi/sample_browser_plugin.png
Executable file
|
After Width: | Height: | Size: 3.5 KiB |
19
samples/BrowserPlugin/res/values/strings.xml
Normal file
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
13
samples/BusinessCard/Android.mk
Normal file
@@ -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)
|
||||
33
samples/BusinessCard/AndroidManifest.xml
Normal file
@@ -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>
|
||||
27
samples/BusinessCard/res/layout/business_card.xml
Normal file
@@ -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>
|
||||
|
||||
24
samples/BusinessCard/res/values/strings.xml
Normal file
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||