This commit is contained in:
filmaj 2010-03-04 15:11:49 -08:00
commit bdf01735cd
34 changed files with 2972 additions and 97 deletions

View File

@ -38,6 +38,6 @@
<action android:name="android.intent.action.PICK" />
</activity>
</application>
<uses-sdk android:minSdkVersion="5" />
<uses-sdk android:minSdkVersion="3" />
</manifest>

View File

@ -0,0 +1,33 @@
var Crypto = function()
{
}
Crypto.prototype.encrypt = function(seed, string, callback)
{
GapCrypto.encrypt(seed, string);
this.encryptWin = callback;
}
Crypto.prototype.decrypt = function(seed, string, callback)
{
GapCrypto.decrypt(seed, string);
this.decryptWin = callback;
}
Crypto.prototype.gotCryptedString = function(string)
{
this.encryptWin(string);
}
Crypto.prototype.getPlainString = function(string)
{
this.decryptWin(string);
}
PhoneGap.addConstructor(function() {
if (typeof navigator.Crypto == "undefined")
{
navigator.Crypto = new Crypto();
}
});

View File

@ -1,109 +1,226 @@
/**
* This class provides generic read and write access to the mobile device file system.
*/
function File() {
/**
* The data of a file.
*/
this.data = "";
/**
* The name of the file.
*/
this.name = "";
}
PhoneGap.addConstructor(function() { if (typeof navigator.fileMgr == "undefined") navigator.fileMgr = new FileMgr();});
/**
* Reads a file from the mobile device. This function is asyncronous.
* @param {String} fileName The name (including the path) to the file on the mobile device.
* The file name will likely be device dependent.
* @param {Function} successCallback The function to call when the file is successfully read.
* @param {Function} errorCallback The function to call when there is an error reading the file from the device.
* This class provides iPhone read and write access to the mobile device file system.
* Based loosely on http://www.w3.org/TR/2009/WD-FileAPI-20091117/#dfn-empty
*/
File.prototype.read = function(fileName, successCallback, errorCallback) {
function FileMgr()
{
this.fileWriters = {}; // empty maps
this.fileReaders = {};
this.docsFolderPath = "../../Documents";
this.tempFolderPath = "../../tmp";
this.freeDiskSpace = -1;
this.getFileBasePaths();
}
/**
* Writes a file to the mobile device.
* @param {File} file The file to write to the device.
*/
File.prototype.write = function(file) {
// private, called from Native Code
FileMgr.prototype._setPaths = function(docs,temp)
{
this.docsFolderPath = docs;
this.tempFolderPath = temp;
}
PhoneGap.addConstructor(function() {
if (typeof navigator.file == "undefined") navigator.file = new File();
});
// private, called from Native Code
FileMgr.prototype._setFreeDiskSpace = function(val)
{
this.freeDiskSpace = val;
}
File.prototype.read = function(fileName, successCallback, errorCallback) {
this.failCallback = errorCallback;
this.winCallback = successCallback;
// FileWriters add/remove
// called internally by writers
FileMgr.prototype.addFileWriter = function(filePath,fileWriter)
{
this.fileWriters[filePath] = fileWriter;
}
FileMgr.prototype.removeFileWriter = function(filePath)
{
this.fileWriters[filePath] = null;
}
// File readers add/remove
// called internally by readers
FileMgr.prototype.addFileReader = function(filePath,fileReader)
{
this.fileReaders[filePath] = fileReader;
}
FileMgr.prototype.removeFileReader = function(filePath)
{
this.fileReaders[filePath] = null;
}
/*******************************************
*
* private reader callback delegation
* called from native code
*/
FileMgr.prototype.reader_onloadstart = function(filePath,result)
{
this.fileReaders[filePath].onloadstart(result);
}
FileMgr.prototype.reader_onprogress = function(filePath,result)
{
this.fileReaders[filePath].onprogress(result);
}
FileMgr.prototype.reader_onload = function(filePath,result)
{
this.fileReaders[filePath].result = unescape(result);
this.fileReaders[filePath].onload(this.fileReaders[filePath].result);
}
FileMgr.prototype.reader_onerror = function(filePath,err)
{
this.fileReaders[filePath].result = err;
this.fileReaders[filePath].onerror(err);
}
FileMgr.prototype.reader_onloadend = function(filePath,result)
{
this.fileReaders[filePath].onloadend(result);
}
/*******************************************
*
* private writer callback delegation
* called from native code
*/
FileMgr.prototype.writer_onerror = function(filePath,err)
{
this.fileWriters[filePath].onerror(err);
}
FileMgr.prototype.writer_oncomplete = function(filePath,result)
{
this.fileWriters[filePath].oncomplete(result); // result contains bytes written
}
FileMgr.prototype.getFileBasePaths = function()
{
//PhoneGap.exec("File.getFileBasePaths");
}
FileMgr.prototype.testFileExists = function(fileName, successCallback, errorCallback)
{
var test = FileUtil.testFileExists(fileName);
test ? successCallback() : errorCallback();
}
FileMgr.prototype.testDirectoryExists = function(dirName, successCallback, errorCallback)
{
this.successCallback = successCallback;
this.errorCallback = errorCallback;
var test = FileUtil.testDirectoryExists(dirName);
test ? successCallback() : errorCallback();
}
FileMgr.prototype.createDirectory = function(dirName, successCallback, errorCallback)
{
this.successCallback = successCallback;
this.errorCallback = errorCallback;
var test = FileUtils.createDirectory(dirName);
test ? successCallback() : errorCallback();
}
FileMgr.prototype.deleteDirectory = function(dirName, successCallback, errorCallback)
{
this.successCallback = successCallback;
this.errorCallback = errorCallback;
var test = FileUtils.deleteDirectory(dirName);
test ? successCallback() : errorCallback();
}
FileMgr.prototype.deleteFile = function(fileName, successCallback, errorCallback)
{
this.successCallback = successCallback;
this.errorCallback = errorCallback;
FileUtils.deleteFile(fileName);
test ? successCallback() : errorCallback();
}
FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback)
{
if(this.freeDiskSpace > 0)
{
return this.freeDiskSpace;
}
else
{
this.successCallback = successCallback;
this.errorCallback = errorCallback;
this.freeDiskSpace = FileUtils.getFreeDiskSpace();
(this.freeDiskSpace > 0) ? successCallback() : errorCallback();
}
}
// File Reader
function FileReader()
{
this.fileName = "";
this.result = null;
this.onloadstart = null;
this.onprogress = null;
this.onload = null;
this.onerror = null;
this.onloadend = null;
}
FileReader.prototype.abort = function()
{
// Not Implemented
}
FileReader.prototype.readAsText = function(file)
{
if(this.fileName && this.fileName.length > 0)
{
navigator.fileMgr.removeFileReader(this.fileName,this);
}
this.fileName = file;
navigator.fileMgr.addFileReader(this.fileName,this);
return FileUtil.read(fileName);
}
File.prototype.hasRead = function(data)
// File Writer
function FileWriter()
{
if(data.substr("FAIL"))
this.failCallback(data);
else
this.winCallback(data);
this.fileName = "";
this.result = null;
this.readyState = 0; // EMPTY
this.result = null;
this.onerror = null;
this.oncomplete = null;
}
/**
* Writes a file to the mobile device.
* @param {File} file The file to write to the device.
*/
File.prototype.write = function(file, str, mode, successCallback, failCallback) {
this.winCallback = successCallback;
this.failCallback = failCallback;
var call = FileUtil.write(file, str, mode);
}
File.prototype.testFileExists = function(file, successCallback, failCallback)
FileWriter.prototype.writeAsText = function(file,text,bAppend)
{
var exists = FileUtil.testFileExists(file);
if(exists)
successCallback();
else
failCallback();
return exists;
}
File.prototype.testDirectoryExists = function(file, successCallback, failCallback)
{
var exists = FileUtil.testDirectoryExists(file);
if(exists)
successCallback();
else
failCallback();
return exists;
}
File.prototype.createDirectory = function(dir, successCallback, failCallback)
{
var good = FileUtils.createDirectory(dir);
good ? successCallback() : failCallback();
}
File.prototype.deleteDirectory = function(dir, successCallback, failCallback)
{
var good = FileUtils.deleteDirectory(dir);
good ? successCallback() : failCallback();
}
File.prototype.deleteFile = function(dir, successCallback, failCallback)
{
var good = FileUtils.deleteFile(dir);
good ? successCallback() : failCallback();
}
File.prototype.getFreeDiskSpace = function(successCallback, failCallback)
{
var diskSpace = FileUtils.getFreeDiskSpace();
if(diskSpace > 0)
successCallback();
else
failCallback();
return diskSpace;
if(this.fileName && this.fileName.length > 0)
{
navigator.fileMgr.removeFileWriter(this.fileName,this);
}
this.fileName = file;
if(bAppend != true)
{
bAppend = false; // for null values
}
navigator.fileMgr.addFileWriter(file,this);
this.readyState = 0; // EMPTY
var call = FileUtil.write(file, text, bAppend);
this.result = null;
}

View File

@ -0,0 +1,37 @@
package com.phonegap;
import android.webkit.WebView;
public class CryptoHandler {
WebView mView;
CryptoHandler(WebView view)
{
mView = view;
}
public void encrypt(String pass, String text)
{
try {
String encrypted = SimpleCrypto.encrypt(pass,text);
mView.loadUrl("javascript:Crypto.gotCryptedString('" + text + "')");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void decrypt(String pass, String text)
{
try {
String decrypted = SimpleCrypto.decrypt(pass,text);
mView.loadUrl("javascript:Crypto.gotPlainString('" + text + "')");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -60,8 +60,7 @@ public class DroidGap extends Activity {
private NetworkManager netMan;
private CompassListener mCompass;
private Storage cupcakeStorage;
private CryptoHandler crypto;
/** Called when the activity is first created. */
@Override
@ -88,8 +87,7 @@ public class DroidGap extends Activity {
WebViewReflect.checkCompatibility();
/* This changes the setWebChromeClient to log alerts to LogCat! Important for Javascript Debugging */
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ECLAIR)
if (android.os.Build.VERSION.RELEASE.startsWith("2."))
appView.setWebChromeClient(new EclairClient(this));
else
{
@ -110,6 +108,9 @@ public class DroidGap extends Activity {
WebViewReflect.setStorage(settings, true, "/data/data/" + appPackage + "/app_database/");
// Turn on DOM storage!
WebViewReflect.setDomStorage(settings);
/* Bind the appView object to the gap class methods */
bindBrowser(appView);
if(cupcakeStorage != null)
@ -135,6 +136,7 @@ public class DroidGap extends Activity {
fs = new FileUtils(appView);
netMan = new NetworkManager(this, appView);
mCompass = new CompassListener(this, appView);
crypto = new CryptoHandler(appView);
// This creates the new javascript interfaces for PhoneGap
appView.addJavascriptInterface(gap, "DroidGap");
@ -145,7 +147,10 @@ public class DroidGap extends Activity {
appView.addJavascriptInterface(fs, "FileUtil");
appView.addJavascriptInterface(netMan, "NetworkManager");
appView.addJavascriptInterface(mCompass, "CompassHook");
if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.DONUT)
appView.addJavascriptInterface(crypto, "GapCrypto");
if (android.os.Build.VERSION.RELEASE.startsWith("1."))
{
cupcakeStorage = new Storage(appView);
appView.addJavascriptInterface(cupcakeStorage, "droidStorage");
@ -214,6 +219,7 @@ public class DroidGap extends Activity {
public final class EclairClient extends GapClient
{
private String TAG = "PhoneGapLog";
private long MAX_QUOTA = 2000000;
public EclairClient(Context ctx) {
@ -237,6 +243,13 @@ public class DroidGap extends Activity {
quotaUpdater.updateQuota(currentQuota);
}
}
// This is a test of console.log, because we don't have this in Android 2.01
public void addMessageToConsole(String message, int lineNumber, String sourceID)
{
Log.d(TAG, sourceID + ": Line " + Integer.toString(lineNumber) + " : " + message);
}
}

View File

@ -97,7 +97,7 @@ public class FileUtils {
data = "FAIL: IO ERROR";
}
mView.loadUrl("javascript:navigator.file.hasRead('" + data + "')");
//mView.loadUrl("javascript:navigator.FileReader.hasRead('" + data + "')");
return data;
}
@ -113,9 +113,11 @@ public class FileUtils {
out.write(buff, 0, rawData.length);
out.flush();
out.close();
mView.loadUrl("javascript:navigator.file.winCallback('File written')");
//mView.loadUrl("javascript:navigator.FileReader.onsuccess('File written')");
} catch (Exception e) {
mView.loadUrl("javascript:navigator.file.failCallback('Fail')");
//mView.loadUrl("javascript:navigator.FileReader.onerror('Fail')");
// So, do we just return -1 at this point!
return -1;
}
return 0;
}

View File

@ -32,10 +32,9 @@ public class NetworkManager {
public boolean isWifiActive()
{
NetworkInfo info = sockMan.getActiveNetworkInfo();
String type = "";
if (info!=null)
if(info != null)
{
type = info.getTypeName();
String type = info.getTypeName();
return type.equals("WIFI");
}
return false;

View File

@ -0,0 +1,96 @@
/*
* Code originally found on Android Snippets
* Contributed to snippets Ferenc Hechler
* Copyright (c) 2009 Ferenc Hechler
*/
package com.phonegap;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class SimpleCrypto {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte [] rawKey = getRawKey(seed.getBytes());
byte [] enc = toByte(encrypted);
byte [] result = decrypt(rawKey, enc);
return new String(result);
}
public static byte[] getRawKey(byte [] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt)
{
return toHex(txt.getBytes());
}
public static String fromHex(String hex)
{
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; ++i)
{
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
}
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
{
return "";
}
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++)
{
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "01234567890ABCDEF";
private static void appendHex(StringBuffer sb, byte b)
{
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
}

View File

@ -9,6 +9,8 @@ import android.webkit.WebSettings;
public class WebViewReflect {
private static Method mWebSettings_setDatabaseEnabled;
private static Method mWebSettings_setDatabasePath;
private static Method mWebSettings_setDomStorageEnabled;
static
{
checkCompatibility();
@ -37,12 +39,15 @@ public class WebViewReflect {
}
}
public static void checkCompatibility() {
try {
mWebSettings_setDatabaseEnabled = WebSettings.class.getMethod(
"setDatabaseEnabled", new Class[] { boolean.class } );
mWebSettings_setDatabasePath = WebSettings.class.getMethod(
"setDatabasePath", new Class[] { String.class });
mWebSettings_setDomStorageEnabled = WebSettings.class.getMethod(
"setDomStorageEnabled", new Class[] { boolean.class });
/* success, this is a newer device */
} catch (NoSuchMethodException nsme) {
/* failure, must be older device */
@ -72,4 +77,31 @@ public class WebViewReflect {
System.out.println("dump not supported");
}
}
public static void setDomStorage(WebSettings setting)
{
if(mWebSettings_setDomStorageEnabled != null)
{
/* feature is supported */
try {
mWebSettings_setDomStorageEnabled.invoke(setting, true);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//setting.setDatabaseEnabled(enable);
//setting.setDatabasePath(path);
} else {
/* feature not supported, do something else */
System.out.println("dump not supported");
}
}
}

232
tutorial/accelerometer.html Executable file
View File

@ -0,0 +1,232 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
#playField
{
width: 295px;
height:295px;
background:rgba(64,64,64,0.5);
border: 1px solid rgba(128,128,128,0.5);
-webkit-border-radius: 5px;
border-radius: 5px;
clear:both;
margin:15px 6px 0;
padding:4px 0px 2px 10px;
}
#ball
{
-webkit-border-radius: 26px;
width: 52px;
height: 52px;
background:rgba(128,128,128,0.5);
border: 1px solid rgba(32,32,32,0.5);
position:absolute;
}
.btn
{
text-decoration: none;
padding: 8px 24px;
background:#fff;
color: #aaa;
font-weight: bold;
-webkit-border-radius: 10px;
}
.btn:hover
{
background: #6fd9f4;
color: #fff;
}
</style>
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
function preventBehavior(e) { e.preventDefault(); };
var ballSize = 52;
var fieldSize = 295;
var top = 150;
var bottom = 445;
var x = fieldSize / 2;
var y = fieldSize / 2;
var accelInputX = 0.01;
var accelInputY = 0.01;
var vx = 0;
var vy = 0;
var vLimit = 200;
var xMin = 6;
var xMax = xMin + fieldSize - ballSize;
var yMin = 32;
var yMax = yMin + fieldSize - ballSize;
var multiplier = 1.5;
var ball;
var timer = null;
var frameTimer = null;
var lastFrameTime = 0;
function watchAccel()
{
if(timer == null)
{
timer = navigator.accelerometer.watchAcceleration(onAccellUpdate,onAccelError,{frequency:50});
}
}
function onAccelError(e)
{
alert("fail: " + e );
}
function onAccellUpdate(accel)
{
accelInputX = accel.x;
accelInputY = accel.y;
}
function onFrameUpdate()
{
vx += accelInputX;
vy -= accelInputY;
if (vx > vLimit)
vx = vLimit;
if (vy > vLimit)
vy = vLimit;
//var now = new Date().getTime();
//var elapsed = now - lastFrameTime;
//lastFrameTime = now;
x += vx;
y += vy;
if (y > yMax)
{
y = yMax;
vy = -vy / 2;
}
else if (y < yMin)
{
y = yMin;
vy = -vy / 2;
}
if (x > xMax)
{
x = xMax;
vx = -vx / 2;
}
else if (x < xMin)
{
x = xMin;
vx = -vx / 2;
}
updateBallCordinates();
}
function updateBallCordinates()
{
ball.style.left = ( xMin + x ).toString() + 'px';
ball.style.top = ( yMin + y ).toString() + 'px';
}
function onWinLoad()
{
document.addEventListener("touchmove", preventBehavior, false);
document.addEventListener("deviceready",onDeviceReady,false);
}
function onStartButton()
{
if(frameTimer != null)
{
navigator.accelerometer.clearWatch(timer);
timer = null;
clearInterval(frameTimer);
frameTimer = null;
}
else
{
watchAccel();
frameTimer = setInterval(onFrameUpdate,20);
//lastFrameTime = new Date().getTime();
}
document.getElementById("btnText").innerHTML = ( frameTimer != null ) ? "Pause" : "Start";
}
function onDeviceReady()
{
ball = document.getElementById("ball");
updateBallCordinates();
updateBallCordinates(); // hack for the shadow
ball.style.display = "block";
document.getElementById("startBtn").addEventListener("touchstart",onStartButton,false);
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">Accelerometer</span>
</div>
<div id="playField" style="width:295px">
<div id="ball" style="display:none"></div>
</div>
<a href="#" id="startBtn">
<div class="item">
<h2 id="btnText">Start</h2>
</div></a>
</body>
</html>

BIN
tutorial/beep.wav Executable file

Binary file not shown.

176
tutorial/contacts.html Normal file
View File

@ -0,0 +1,176 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
.contact
{
padding: 8px;
background:rgba(64,64,64,0.5);
border: 1px solid rgba(128,128,128,0.5);
opacity: 0.8;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
margin-bottom: .5em;
}
</style>
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
var defaultContactTemplate = "<div class='item' onclick='onContactClick(CONTACTID);'><div>First Name : <strong>FNAME</strong></div><div>Last Name : <strong>LNAME</strong></div><div>Email : EMAIL</div><div>Tel : TELNO</div></div>";
var _anomFunkMap = {};
var _anomFunkMapNextId = 0;
function anomToNameFunk(fun)
{
var funkId = "f" + _anomFunkMapNextId++;
var funk = function()
{
fun.apply(this,arguments);
_anomFunkMap[funkId] = null;
};
_anomFunkMap[funkId] = funk;
return "_anomFunkMap." + funkId;
}
function GetFunctionName(fn)
{
if (fn)
{
var m = fn.toString().match(/^\s*function\s+([^\s\(]+)/);
return m ? m[1] : anomToNameFunk(fn);
} else {
return null;
}
}
function onGetTenBtn()
{
navigator.contacts.getAllContacts(onGetAllContacts,null,{pageSize:10});
}
function onGetAllContacts(res)
{
var child = document.getElementById('contactList');
var listMarkup = "";
for(var n = 0; n < res.length; n++)
{
listMarkup += getContactMarkup(res[n]);
}
child.innerHTML = listMarkup;
child.style.display = "block";
}
function onPickBtn()
{
navigator.contacts.chooseContact(onPickContactCallback);
}
function onPickContactCallback(contactObj)
{
var child = document.getElementById('contactPicked');
child.innerHTML = getContactMarkup(contactObj);
child.style.display = "block";
}
function getContactMarkup(contact)
{
var contactTemplate = defaultContactTemplate;
contactTemplate = contactTemplate.replace(/FNAME/g,contact.firstName);
contactTemplate = contactTemplate.replace(/LNAME/g,contact.lastName);
contactTemplate = contactTemplate.replace(/CONTACTID/g,contact.recordID);
if(contact.emails[0].value != null)
{
contactTemplate = contactTemplate.replace(/EMAIL/g,contact.emails[0].value);
}
else
{
contactTemplate = contactTemplate.replace(/EMAIL/g,"");
}
if(contact.phoneNumbers[0].value != null)
{
contactTemplate = contactTemplate.replace(/TELNO/g,contact.phoneNumbers[0].value);
}
else
{
contactTemplate = contactTemplate.replace(/TELNO/g,"");
}
return contactTemplate;
}
function onContactClick(id)
{
navigator.contacts.displayContact(id);
}
function onGotContactCount(num)
{
document.getElementById("contactCountDiv").innerHTML = "Contact Count : " + num;
}
function onGotContactCountError(err)
{
alert("error getting contacts :: " + err);
}
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
navigator.contacts.contactsCount(onGotContactCount,onGotContactCountError);
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">Contacts</span>
</div>
<h2 id="contactCountDiv">Getting contact count ...</h2>
<a href="#" onclick="onPickBtn();">
<div class="item">
<h2>Pick a Contact</h2>
</div>
</a>
<div id="contactPicked" style="display:none"></div>
<a href="#" onclick="onGetTenBtn();">
<div class="item">
<h2>Get first 10 contacts</h2>
</div>
</a>
<div id="contactList" style="display:none"></div>
</body>
</html>

176
tutorial/geolocation.html Executable file
View File

@ -0,0 +1,176 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
img {
border: 0;
}
#container {
}
#tweetList {
color: #ddd;
}
#tweetList .tweet {
padding: 8px;
background:rgba(64,64,64,0.5);
border: 1px solid rgba(128,128,128,0.5);
opacity: 0.8;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
margin-bottom: .5em;
}
#tweetList a {
color: #f30;
text-decoration: underline;
}
#tweetList .avatar {
float: left;
}
#tweetList .content {
padding-left: 55px;
}
#tweetList .extra {
color: #666;
font-size: 85%
}
</style>
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
var url = "http://search.twitter.com/search.json?callback=getTweets";
var intervalID;
function preventBehavior(e) { e.preventDefault(); };
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
var funk = function(position)
{
callback(position.coords.latitude, position.coords.longitude);
};
var fail = function(error)
{
alert("error :: " + error);
}
intervalID = navigator.geolocation.watchPosition(funk,fail);
window.addEventListener("unload",onWindowUnload,false);
}
function onBackBtn()
{
navigator.geolocation.clearWatch(intervalID);
}
function onWindowUnload()
{
}
function getCurrentLocation()
{
document.getElementById("location2").innerHTML = "Getting current location ...";
var funk = function(position)
{
document.getElementById("location2").innerHTML = "Lat: "+position.coords.latitude+ " Lon: " +position.coords.longitude;
};
var fail = function(error)
{
alert("error :: " + error);
}
navigator.geolocation.getCurrentPosition(funk,fail);
}
function callback(lat, lon)
{
//navigator.geolocation.stop();
//alert("Callback :: " + lat + "," + lon);
print(lat,lon);
var geocode = "&geocode=" + lat + "%2C" + lon + "%2C1mi";
var fullUrl = url + geocode;
var head = document.getElementsByTagName('head');
var script = document.createElement('script');
script.src = fullUrl;
head[0].appendChild(script);
}
function getTweets(json) {
var q;
var parent = document.getElementById('tweetList');
parent.innerHTML = '';
var child;
for (var i = 0; i < json.results.length; i++) {
q = json.results[i];
child = document.createElement("div");
child.setAttribute("class","tweet");
child.innerHTML = '<div class="avatar"><img src="'+q.profile_image_url+'" alt="avatar" width="48" height="48" /></div>';
child.innerHTML += '<div class="content"><a href="http://m.twitter.com/'+q.from_user+'">'+q.from_user+'</a> '+q.text+'<div class="extra">'+q.location+' ('+q.created_at+')</div></div>';
parent.appendChild(child);
}
}
function print(lat,lon)
{
document.getElementById("location1").innerHTML = "Lat: "+lat+ " Lon: " +lon;// + " TS: " + (new Date().getTime());
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html" onclick="onBackBtn()">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">GeoLocation</span>
</div>
<div id="container">
<div class="item" style="text-align:center;" id="location1">Getting your current location ...</div>
<p>Find who are tweeting within 1 mile radius of where you are!</p>
<div id="tweetList">
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
tutorial/images/TutBG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
tutorial/images/header.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
tutorial/images/header2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

BIN
tutorial/images/header3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

72
tutorial/index.html Executable file
View File

@ -0,0 +1,72 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
// do your thing!
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<span class="pageTitle">PhoneGap Tutorial</span>
</div>
<a href="accelerometer.html">
<div class="item">
<h2>Accelerometer</h2>
</div></a>
<a href="notification.html">
<div class="item">
<h2>Notification</h2>
</div>
</a>
<a href="contacts.html">
<div class="item">
<h2>Contacts</h2>
</div>
</a>
<a href="geolocation.html">
<div class="item">
<h2>GeoLocation</h2>
</div>
</a>
<a href="inputs.html">
<div class="item"
<h2>Form Inputs</h2>
</div>
</a>
<a href="media.html">
<div class="item">
<h2>Media</h2>
</div>
</a>
</body>
</html>

98
tutorial/inputs.html Executable file
View File

@ -0,0 +1,98 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
input
{
width: 180px;
margin-bottom: 18px;
margin-top: 4px;
-webkit-border-radius: 5px;
left:100px;
position:absolute;
}
input.disabled
{
opacity: 0.5;
}
label
{
margin-bottom: 18px;
line-height:36px;
}
</style>
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">Form Inputs</span>
</div>
<form action="/">
<br/>
<!-- display a standard keyboard -->
<label for="tiText">Text:</label>
<input type="text" id="tiText"/>
<br/>
<!-- display a telephone keypad -->
<label for="tiTel">Telephone:</label>
<input type="tel" id="tiTel"/>
<br/>
<!-- display a URL keyboard -->
<label for="tiUrl">URL:</label>
<input type="url" id="tiUrl"/>
<br/>
<!-- display an email keyboard -->
<label for="tiEmail">Email:</label>
<input type="email" id="tiEmail"/>
<br/>
<!-- display a numeric keyboard -->
<label for="tiZip">Zip Code:</label>
<input type="text" pattern="[0-9]*" id="tiZip"/>
<br/>
<label for="tiSearch">Search:</label>
<input type="search" id="tiSearch" style="width:192px;"/>
<br/>
</form>
</a>
</body>
</html>

304
tutorial/master.css Executable file
View File

@ -0,0 +1,304 @@
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6
{
margin: 0pt;
padding: 0pt;
}
body
{
background:#000 url(images/TutBG.png) repeat-y fixed 0 0;
color:#666;
font-family:Helvetica,'Lucida Grande',sans-serif;
line-height:1.5em;
margin:0px;
margin-bottom:20px;
}
#header{
position: relative;
left: 0px;
top: 0px;
height: 44px;
font-size: 16pt;
border-top-width: 0px;
border-right-width: 1px;
border-bottom-width: 0px;
border-left-width: 1px;
width: auto;
margin-right: 0px;
margin-left: 0px;
background: url( header.png );
}
.header_title{
text-align: center;
position: relative;
font-weight: bold;
color: rgb(255, 255, 255);
text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0px;
}
.view{
background: url( images/backgroundStripes.png );
background-repeat: repeat;
min-height: 406px;
}
.topBar
{
color:#eee;
font-size:1.2em;
text-align:center;
margin:0;
margin-top:0px;
padding:0;
background-image: url( 'images/header.png' );
background-repeat: repeat-x;
height:44px;
text-height:44px;
}
.pageTitle
{
text-align: center;
color:#FFF;
line-height:44px;
}
.back_button
{
font-weight: bold;
font-size: 12px;
color: rgb(255, 255, 255);
text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0px;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
height: 22px;
padding-top: 4px;
padding-bottom: 4px;
width: 60px;
line-height:22px;
right: auto;
bottom: auto;
margin-top: 0px;
position:absolute;
left:4px;
top:11px;
-webkit-border-image: url(images/back_button.png) 0 5 0 16 / 1px 5px 1px 16px stretch stretch;
}
.list
{
margin-top: 5px;
}
.list li{
width: 290px;
height: 20px;
background-color: #FFF;
border-left: 1px solid #AAA;
border-right: 1px solid #AAA;
border-bottom: 1px solid #AAA;
list-style-type: none;
padding: 12px 5px 10px 5px;
margin-left: -36px;
}
.list li.active{
background-image: url( 'selection.png' );
background-repeat: repeat-x;
background-color: #194fdb !important;
}
.list li:first-of-type{
border-top: 1px solid #AAA;
-webkit-border-top-right-radius: 8px 8px;
-webkit-border-top-left-radius: 8px 8px;
}
.list li:last-of-type{
border-top: none;
border-bottom: 1px solid #AAA;
-webkit-border-bottom-left-radius: 8px 8px;
-webkit-border-bottom-right-radius: 8px 8px;
}
.list li:only-of-type{
border-top: 1px solid #AAA;
border-bottom: 1px solid #AAA;
-webkit-border-top-right-radius: 8px 8px;
-webkit-border-top-left-radius: 8px 8px;
-webkit-border-bottom-left-radius: 8px 8px;
-webkit-border-bottom-right-radius: 8px 8px;
}
.list .list_label{
font-weight: bold;
color: #000;
text-align: left;
width: 145px;
float: left;
}
.list .list_value{
color: #6e82a8;
text-align: right;
width: 140px;
float: right;
}
.list .selected_item{
color: #4c566c;
}
.list_section_label{
font-size: 16px;
font-weight: bold;
margin-left: 15px;
text-shadow: rgba(255, 255, 255, 1) 0px 1px 0px;
color: #4c566c;
}
.list_section_note{
font-size: 14px;
margin-left: 15px;
text-shadow: rgba(255, 255, 255, 1) 0px 1px 0px;
color: #4c566c;
text-align: center;
margin-bottom: 15px;
margin-top: -5px;
}
.item
{
background:rgba(64,64,64,0.5);
border: 1px solid rgba(128,128,128,0.5);
-webkit-border-radius: 5px;
border-radius: 5px;
clear:both;
margin:15px 6px 0;
width:295px;
padding:4px 0px 2px 10px;
}
a
{
color:#FFF;
text-decoration:none;
}
#info{
background:#ffa;
border: 1px solid #ffd324;
-webkit-border-radius: 5px;
border-radius: 5px;
clear:both;
margin:15px 6px 0;
width:295px;
padding:4px 0px 2px 10px;
}
#info h4{
font-size:.95em;
margin:0;
padding:0;
}
#stage.theme{
padding-top:3px;
}
/* Definition List */
#Page1 > dl{
padding-top:10px;
clear:both;
margin:0;
list-style-type:none;
padding-left:10px;
overflow:auto;
}
#Page1 > dl > dt{
font-weight:bold;
float:left;
margin-left:5px;
}
#Page1 > dl > dd{
width:45px;
float:left;
color:#a87;
font-weight:bold;
}
/* Content Styling */
h1, h2, p{
margin:1em 0 .5em 13px;
}
h1{
color:#eee;
font-size:1.6em;
text-align:center;
margin:0;
margin-top:15px;
padding:0;
}
h2{
clear:both;
margin:0;
padding:3px;
font-size:1em;
text-align:center;
}
/* Stage Buttons */
#stage.theme a.btn
{
border: 1px solid #555;
-webkit-border-radius: 5px;
border-radius: 5px;
text-align:center;
display:block;
float:left;
background:#444;
width:150px;
color:#9ab;
font-size:1.1em;
text-decoration:none;
padding:1.2em 0;
margin:3px 0px 3px 5px;
}
a.btn.large
{
width:64px;
height:32px;
padding:1.2em 0;
}

111
tutorial/media.html Executable file
View File

@ -0,0 +1,111 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<style>
.mediaBtn
{
clear:none;
float:left;
background:rgba(64,64,64,0.5);
border: 1px solid rgba(128,128,128,0.5);
-webkit-border-radius: 5px;
border-radius: 5px;
margin:20px;
width:64px;
padding:4px;
}
</style>
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
var PS_STOPPED = 0;
var PS_PLAYING = 1;
var PS_PAUSED = 2;
var PS_RECORDING = 3;
var currentState;
var mediaFile = null;
function onPlayStopBtn()
{
if(currentState != PS_PLAYING)
{
mediaFile.play({numberOfLoops:0});
currentState = PS_PLAYING;
document.getElementById("playText").innerHTML = "Stop";
}
else
{
mediaFile.stop();
currentState = PS_STOPPED;
document.getElementById("playText").innerHTML = "Play";
}
}
function onMediaCreatedSuccess(obj)
{
alert("successfully created media");
}
function onMediaCreatedError(err)
{
alert("error creating media");
}
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
mediaFile = new Media('percBass.wav',onMediaCreatedSuccess,onMediaCreatedError);
updateButtonStates();
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">Media</span>
</div>
<h2>percBass.wav</h2>
<a href="#" onclick="onPlayStopBtn();">
<div class="mediaBtn">
<h2 id="playText">Play</h2>
</div>
</a>
<!--
<a href="#" onclick="onRecordBtn();">
<div class="mediaBtn">
<h2>Record</h2>
</div>
</a>
-->
</body>
</html>

105
tutorial/notification.html Executable file
View File

@ -0,0 +1,105 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
var isActivityShowing = false;
function onAlertBtn()
{
navigator.notification.alert("Custom Message","Custom Title", "Custom Label");
}
function onActivityBtn()
{
if(isActivityShowing)
{
navigator.notification.activityStop();
}
else
{
navigator.notification.activityStart();
}
isActivityShowing = !isActivityShowing;
document.getElementById("activityText").innerHTML = isActivityShowing ? "Hide Activity Indicator" : "Show Activity Indicator";
}
function onLoadingBtn()
{
navigator.notification.loadingStart({duration:2});
}
function onVibrateBtn()
{
navigator.notification.vibrate(100); // note, iPhone ignores the ms param
}
function onBeepBtn()
{
navigator.notification.beep();
}
function onWinLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}
function onDeviceReady()
{
}
</script>
</head>
<body id="stage" class="theme" onload="onWinLoad()">
<div class="topBar">
<a href="index.html">
<span class="back_button">Back</span>
</a>
<span class="pageTitle">Notification</span>
</div>
<a href="#" onclick="onAlertBtn();">
<div class="item">
<h2>Show Custom Alert</h2>
</div></a>
<a href="#" onclick="onActivityBtn();">
<div class="item">
<h2 id="activityText">Show Activity Indicator</h2>
</div>
</a>
<a href="#" onclick="onVibrateBtn();">
<div class="item">
<h2>Vibrate</h2>
</div>
</a>
<a href="#" onclick="onLoadingBtn();">
<div class="item">
<h2>Show Loading ( 2 Seconds )</h2>
</div>
</a>
<a href="#" onclick="onBeepBtn();">
<div class="item">
<h2>Beep</h2>
</div>
</a>
</body>
</html>

BIN
tutorial/percBass.wav Executable file

Binary file not shown.

1272
tutorial/phonegap.js Normal file

File diff suppressed because it is too large Load Diff