merge from eclair

This commit is contained in:
Jean-Baptiste Queru
2009-11-15 12:05:38 -08:00
3240 changed files with 153711 additions and 72942 deletions

View File

@@ -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" />

View File

@@ -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

View File

@@ -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" />

View 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" />

View File

@@ -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>

View File

@@ -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>

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 686 B

After

Width:  |  Height:  |  Size: 686 B

View File

Before

Width:  |  Height:  |  Size: 683 B

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 B

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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>

View File

@@ -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>

View File

@@ -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 &amp; 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>

View File

@@ -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>

View File

@@ -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);
}
};
}

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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());
}
};
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -0,0 +1 @@
tested.project.dir=..

View 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))

View 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>

View 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

View 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.

View 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)

View 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;
}

View 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

View 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
}

View 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

View 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);
}

View 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

View 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);
}

View 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

View 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;
}

View 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

View 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;
}

View 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;
}

View 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;
}

View 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;

View 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);
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View 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>

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View 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)

View 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>

View 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>

View 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>

View File

@@ -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());
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

Some files were not shown because too many files have changed in this diff Show More