diff --git a/.gitignore b/.gitignore index 26ec74ca..d40db17f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ default.properties bin gen assets/www/phonegap.js -local.properties \ No newline at end of file +local.properties +framework/phonegap.jar \ No newline at end of file diff --git a/README.md b/README.md index 40f779ef..c49817e2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Pre-requisites * Java JDK 1.5 * Android SDK Package [http://developer.android.com](http://developer.android.com) * Apache ANT (For build script) - * Ruby, Rubygems, nokogiri (for build.rb) + * Ruby Recommended: ---------------------------------------------------------------- diff --git a/build.rb b/build.rb deleted file mode 100644 index 0b77b1f2..00000000 --- a/build.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'rubygems' -require 'nokogiri' -require 'fileutils' - -class Build - attr_reader :path - attr_reader :name - attr_reader :package_name - attr_reader :www_dir - - def start(name, pkg_name, www, path) - create_android(name, pkg_name, path) - @www_dir = www - generate_manifest - copy_libs - write_java - end - - def create_android(name, pkg_name, path) - @name = name - @pkg_name = pkg_name - @path = path - `android create project -t 5 -k #{pkg_name} -a #{name} -n #{name} -p #{path}` - end - - def generate_manifest - f = File.open('framework/AndroidManifest.xml', 'r') - doc = Nokogiri::XML(f.read) - manifest = doc.search('//manifest') - manifest[0]['package'] = @pkg_name - actions = doc.search('//activity') - actions[0]['android:name'] = ".#{@name}" - actions[1]['android:name'] = "com.phonegap.CameraPreview" - f = File.open("#{@path}/AndroidManifest.xml", 'w') - f.write(doc.to_xml) - end - - def copy_libs - FileUtils.cp('framework/phonegap.jar', "#{@path}/libs") - FileUtils.cp('framework/res/values/strings.xml', "#{@path}/res/values/strings.xml") - FileUtils.mkdir_p("#{@path}/res/drawable/") - FileUtils.mkdir_p("#{@path}/assets") - FileUtils.cp_r("#{@www_dir}/", "#{@path}/assets/www") - FileUtils.cp("#{@www_dir}/icon.png", "#{@path}/res/drawable/icon.png") - end - - def write_java - package_path = "#{@path}/src/" + @pkg_name.gsub('.', '/') - doc = File.open("#{package_path}/#{@name}.java", 'r') - data = doc.read.split(/\n/) - result = "" - data.each do |line| - if line.include? "android.os.Bundle" - line += "\n\nimport com.phonegap.*;" - end - if line.include? "extends Activity" - line = "public class #{@name} extends DroidGap" - end - if line.include? "setContentView" - line = " super.loadUrl(\"file:///android_asset/www/index.html\");" - end - result += line + "\n" - end - doc.close - package_path = "#{@path}/src/" + @pkg_name.gsub('.', '/') - target = File.open(package_path + "/#{@name}.java", 'w') - target.write(result); - end - -end - - -b = Build.new - -if(ARGV.length >= 3) - b.start(ARGV[0], ARGV[1], ARGV[2], ARGV[3]) -else - str = "Android PhoneGap Build Tool \n Usage: build \n name: The name of your application \n package_name: The name of your package: i.e. com.nitobi.demo \n wwwdir: The name of your Web App \n path: Location of where you want to work on your application" - puts str -end diff --git a/droidgap b/droidgap new file mode 100755 index 00000000..2b7780b0 --- /dev/null +++ b/droidgap @@ -0,0 +1,101 @@ +#!/usr/bin/env ruby + +class Build + def start(*args) + @android_sdk_path, @name, @pkg, @www, @path = args + + build_jar + create_android + generate_manifest + copy_libs + write_java + end + + # creates framework/phonegap.jar using android_sdk_path + # + # TODO + # - write out local.properties with android sdk every time + def build_jar + `touch #{ @android_sdk_path }` unless File.exists? @android_sdk_path + `ant jar` + end + + # runs android create project + def create_android + `android create project -t 5 -k #{ @pkg } -a #{ @name } -n #{ @name } -p #{ @path }` + end + + # creates an AndroidManifest.xml for the project + def generate_manifest + manifest = "" + open('framework/AndroidManifest.xml', 'r') do |old| + manifest = old.read + manifest.gsub! 'package="com.phonegap"', "package=\"#{ @pkg }\"" + manifest.gsub! 'android:name=".StandAlone"', ".#{ @name }" + end + open("#{ @path }/AndroidManifest.xml", 'w') {|x| x.puts manifest } + end + + # copies stuff from framework into the project + # + # TODO need to allow for www import + # - copy www into #{ @path }/assets/www + # - copy www/icon.png into #{ @path }/res/drawable/icon.png + # + def copy_libs + `cp framework/phonegap.jar #{ @path }/libs` + `cp framework/res/values/strings.xml #{ @path }/res/values/strings.xml` + `cp framework/res #{ @path }/res` + `cp framework/assets/www #{ @path }/assets/wwww` + end + + # this is so fucking unholy yet oddly beautiful + # not sure if I should thank Ruby or apologize for this abusive use of string interpolation + def write_java + j = " + package #{ @pkg }; + + import android.app.Activity; + import android.os.Bundle; + import com.phonegap.*; + + public class #{ @name } extends DroidGap + { + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + super.loadUrl(\"file:///android_asset/www/index.html\"); + } + } + " + open("#{ @path }/src/#{ @pkg.gsub '.', '/' }",'w') { |f| f.puts j } + end + # +end + + +if(ARGV.length == 5) + Build.new.start(ARGV) +else + puts <<-EOF + + DroidGap: An Android PhoneGap Project Generator + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Creates a fresh Android/PhoneGap app for hybrid mobile web hacking. + + Usage: + + ./droidgap + + Params: + + android_sdk_path ... The path to your Android SDK install. + name ............... The name of your application. + package_name ....... The name of your package (For example: com.nitobi.demo) + www ................ The name of your Web App. + path ............... Location of where you want to work on your application. + + EOF +end diff --git a/framework/AndroidManifest.xml b/framework/AndroidManifest.xml index b8ac3bee..a3b0fba1 100644 --- a/framework/AndroidManifest.xml +++ b/framework/AndroidManifest.xml @@ -32,7 +32,7 @@ - diff --git a/framework/README b/framework/README deleted file mode 100644 index 80e15dc4..00000000 --- a/framework/README +++ /dev/null @@ -1,6 +0,0 @@ -Note: phonegap.js goes in the assets/www directory. To get this file, please -build it from the top level by running make: - -make - -The file will be concatenated and minified, and will be stored in lib/android diff --git a/js/accelerometer.js b/framework/assets/js/accelerometer.js similarity index 100% rename from js/accelerometer.js rename to framework/assets/js/accelerometer.js diff --git a/js/camera.js b/framework/assets/js/camera.js similarity index 100% rename from js/camera.js rename to framework/assets/js/camera.js diff --git a/js/compass.js b/framework/assets/js/compass.js similarity index 100% rename from js/compass.js rename to framework/assets/js/compass.js diff --git a/js/contact.js b/framework/assets/js/contact.js similarity index 100% rename from js/contact.js rename to framework/assets/js/contact.js diff --git a/js/device.js b/framework/assets/js/device.js similarity index 100% rename from js/device.js rename to framework/assets/js/device.js diff --git a/js/file.js b/framework/assets/js/file.js similarity index 100% rename from js/file.js rename to framework/assets/js/file.js diff --git a/js/geolocation.js b/framework/assets/js/geolocation.js similarity index 100% rename from js/geolocation.js rename to framework/assets/js/geolocation.js diff --git a/js/keyevent.js b/framework/assets/js/keyevent.js similarity index 100% rename from js/keyevent.js rename to framework/assets/js/keyevent.js diff --git a/js/media.js b/framework/assets/js/media.js similarity index 100% rename from js/media.js rename to framework/assets/js/media.js diff --git a/js/network.js b/framework/assets/js/network.js similarity index 100% rename from js/network.js rename to framework/assets/js/network.js diff --git a/js/notification.js b/framework/assets/js/notification.js similarity index 100% rename from js/notification.js rename to framework/assets/js/notification.js diff --git a/js/phonegap.js.base b/framework/assets/js/phonegap.js.base similarity index 100% rename from js/phonegap.js.base rename to framework/assets/js/phonegap.js.base diff --git a/js/position.js b/framework/assets/js/position.js similarity index 100% rename from js/position.js rename to framework/assets/js/position.js diff --git a/js/storage.js b/framework/assets/js/storage.js similarity index 100% rename from js/storage.js rename to framework/assets/js/storage.js diff --git a/framework/assets/www/index.html b/framework/assets/www/index.html index eab23c22..f3b5bb2b 100644 --- a/framework/assets/www/index.html +++ b/framework/assets/www/index.html @@ -1,5 +1,4 @@ - + diff --git a/framework/assets/www/phonegap.js b/framework/assets/www/phonegap.js index a06c686e..bb385f51 100644 --- a/framework/assets/www/phonegap.js +++ b/framework/assets/www/phonegap.js @@ -17,7 +17,7 @@ PhoneGap = { /** * Boolean flag indicating if the PhoneGap API is available and initialized. - */ + */ // TODO: Remove this, it is unused here ... -jm PhoneGap.available = DeviceInfo.uuid != undefined; /** @@ -27,28 +27,51 @@ PhoneGap.available = DeviceInfo.uuid != undefined; */ PhoneGap.addConstructor = function(func) { var state = document.readyState; - if (state != 'loaded' && state != 'complete') - PhoneGap._constructors.push(func); + if ( state == 'loaded' || state == 'complete' ) + { + func(); + } else - func(); + { + PhoneGap._constructors.push(func); + } }; -(function() { - var timer = setInterval(function() { - var state = document.readyState; - if (state != 'loaded' && state != 'complete') - return; - clearInterval(timer); - while (PhoneGap._constructors.length > 0) { - var constructor = PhoneGap._constructors.shift(); - try { - constructor(); - } catch(e) { - if (typeof(debug['log']) == 'function') - debug.log("Failed to run constructor: " + debug.processMessage(e)); - else - alert("Failed to run constructor: " + e.message); + +(function() + { + var timer = setInterval(function() + { + + var state = document.readyState; + + if ( state == 'loaded' || state == 'complete' ) + { + clearInterval(timer); // stop looking + // run our constructors list + while (PhoneGap._constructors.length > 0) + { + var constructor = PhoneGap._constructors.shift(); + try + { + constructor(); + } + catch(e) + { + if (typeof(debug['log']) == 'function') + { + debug.log("Failed to run constructor: " + debug.processMessage(e)); + } + else + { + alert("Failed to run constructor: " + e.message); + } + } } - } + // all constructors run, now fire the deviceready event + var e = document.createEvent('Events'); + e.initEvent('deviceready'); + document.dispatchEvent(e); + } }, 1); })(); @@ -65,14 +88,51 @@ PhoneGap.exec = function() { if (PhoneGap.queue.timer == null) PhoneGap.queue.timer = setInterval(PhoneGap.run_command, 10); }; + /** - * Internal function used to dispatch the request to PhoneGap. This needs to be implemented per-platform to - * ensure that methods are called on the phone in a way appropriate for that device. + * Internal function used to dispatch the request to PhoneGap. It processes the + * command queue and executes the next command on the list. If one of the + * arguments is a JavaScript object, it will be passed on the QueryString of the + * url, which will be turned into a dictionary on the other end. * @private */ PhoneGap.run_command = function() { -}; + if (!PhoneGap.available || !PhoneGap.queue.ready) + return; + PhoneGap.queue.ready = false; + + var args = PhoneGap.queue.commands.shift(); + if (PhoneGap.queue.commands.length == 0) { + clearInterval(PhoneGap.queue.timer); + PhoneGap.queue.timer = null; + } + + var uri = []; + var dict = null; + for (var i = 1; i < args.length; i++) { + var arg = args[i]; + if (arg == undefined || arg == null) + arg = ''; + if (typeof(arg) == 'object') + dict = arg; + else + uri.push(encodeURIComponent(arg)); + } + var url = "gap://" + args[0] + "/" + uri.join("/"); + if (dict != null) { + var query_args = []; + for (var name in dict) { + if (typeof(name) != 'string') + continue; + query_args.push(encodeURIComponent(name) + "=" + encodeURIComponent(dict[name])); + } + if (query_args.length > 0) + url += "?" + query_args.join("&"); + } + document.location = url; + +}; function Acceleration(x, y, z) { this.x = x; @@ -294,58 +354,76 @@ Compass.prototype.setError = function(message) { PhoneGap.addConstructor(function() { if (typeof navigator.compass == "undefined") navigator.compass = new Compass(); }); -/** - * This class provides access to the device contacts. - * @constructor - */ - -function Contact(jsonObject) { - this.firstName = ""; - this.lastName = ""; - this.name = ""; - this.phones = {}; - this.emails = {}; - this.address = ""; +var Contact = function(){ + this.name = null; + this.emails = []; + this.phones = []; } -Contact.prototype.displayName = function() +var ContactName = function() { - // TODO: can be tuned according to prefs - return this.name; + this.formatted = ""; + this.familyName = ""; + this.givenName = ""; + this.additionalNames = []; + this.prefixes = []; + this.suffixes = []; } -function ContactManager() { - // Dummy object to hold array of contacts - this.contacts = []; - this.timestamp = new Date().getTime(); + +var ContactEmail = function() +{ + this.types = []; + this.address = ""; } -ContactManager.prototype.getAllContacts = function(successCallback, errorCallback, options) { - // Interface +var ContactPhoneNumber = function() +{ + this.types = []; + this.number = ""; +} + + +var Contacts = function() +{ + this.records = []; +} + +Contacts.prototype.find = function(obj, win, fail) +{ + if(obj.name != null) + { + ContactHook.search(name, "", ""); + } + this.win = win; + this.fail = fail; +} + +Contacts.prototype.droidFoundContact = function(name, npa, email) +{ + var contact = new Contact(); + contact.name = new ContactName(); + contact.name.formatted = name; + contact.name.givenName = name; + var mail = new ContactEmail(); + mail.types.push("home"); + mail.address = email; + contact.emails.push(mail); + phone = new ContactPhoneNumber(); + phone.types.push("home"); + phone.number = npa; + contact.phones.push(phone); + this.records.push(contact); +} + +Contacts.prototype.droidDone = function() +{ + this.win(this.records); } PhoneGap.addConstructor(function() { - if (typeof navigator.ContactManager == "undefined") navigator.ContactManager = new ContactManager(); + if(typeof navigator.contacts == "undefined") navigator.contacts = new Contacts(); }); -ContactManager.prototype.getAllContacts = function(successCallback, errorCallback, options) { - this.win = successCallback; - this.fail = errorCallback; - ContactHook.getContactsAndSendBack(); -} - -ContactManager.prototype.droidAddContact = function(name, phone, email) -{ - var contact = new Contact(); - contact.name = name; - contact.phones.primary = phone; - contact.emails.primary = email; - this.contacts.push(contact); -} - -ContactManager.prototype.droidDone = function() -{ - win(this.contacts); -} /** * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the * phone, etc. @@ -366,13 +444,7 @@ function Device() { this.gapVersion = window.DroidGap.getVersion(); this.platform = window.DroidGap.getPlatform(); this.name = window.DroidGap.getProductName(); - } else { - this.platform = DeviceInfo.platform; - this.version = DeviceInfo.version; - this.name = DeviceInfo.name; - this.gap = DeviceInfo.gap; - this.uuid = DeviceInfo.uuid; - } + } } catch(e) { this.available = false; } @@ -380,9 +452,6 @@ function Device() { PhoneGap.addConstructor(function() { navigator.device = window.device = new Device(); - var event = document.createEvent("Events"); - event.initEvent('deviceReady', false, false); - document.dispatchEvent(event); }); /** * This class provides generic read and write access to the mobile device file system. @@ -680,6 +749,28 @@ Geolocation.prototype.clearWatch = function(watchId) { Geo.stop(watchId); } +function KeyEvent() +{ +} + +KeyEvent.prototype.menuTrigger = function() +{ + var e = document.createEvent('Events'); + e.initEvent('menuKeyDown'); + document.dispatchEvent(e); +} + +KeyEvent.prototype.searchTrigger= function() +{ + var e = document.createEvent('Events'); + e.initEvent('searchKeyDown'); + document.dispatchEvent(e); +} + +if (document.keyEvent == null || typeof document.keyEvent == 'undefined') +{ + window.keyEvent = document.keyEvent = new KeyEvent(); +} /** * This class provides access to the device media, interfaces to both sound and video * @constructor @@ -951,3 +1042,92 @@ PositionError.UNKNOWN_ERROR = 0; PositionError.PERMISSION_DENIED = 1; PositionError.POSITION_UNAVAILABLE = 2; PositionError.TIMEOUT = 3; +/* + * This is purely for the Android 1.5/1.6 HTML 5 Storage + * I was hoping that Android 2.0 would deprecate this, but given the fact that + * most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required + */ + +var DroidDB = function() +{ + this.txQueue = []; +} + +DroidDB.prototype.addResult = function(rawdata, tx_id) +{ + eval("var data = " + rawdata); + var tx = this.txQueue[tx_id]; + tx.resultSet.push(data); +} + +DroidDB.prototype.completeQuery = function(tx_id) +{ + var tx = this.txQueue[tx_id]; + var r = new result(); + r.rows.resultSet = tx.resultSet; + r.rows.length = tx.resultSet.length; + tx.win(r); +} + +DroidDB.prototype.fail = function(reason, tx_id) +{ + var tx = this.txQueue[tx_id]; + tx.fail(reason); +} + +var DatabaseShell = function() +{ + +} + +DatabaseShell.prototype.transaction = function(process) +{ + tx = new Tx(); + process(tx); +} + +var Tx = function() +{ + droiddb.txQueue.push(this); + this.id = droiddb.txQueue.length - 1; + this.resultSet = []; +} + +Tx.prototype.executeSql = function(query, params, win, fail) +{ + droidStorage.executeSql(query, params, this.id); + tx.win = win; + tx.fail = fail; +} + +var result = function() +{ + this.rows = new Rows(); +} + +var Rows = function() +{ + this.resultSet = []; + this.length = 0; +} + +Rows.prototype.item = function(row_id) +{ + return this.resultSet[id]; +} + +var dbSetup = function(name, version, display_name, size) +{ + droidStorage.openDatabase(name, version, display_name, size) + db_object = new DatabaseShell(); + return db_object; +} + +PhoneGap.addConstructor(function() { + if (typeof navigator.openDatabase == "undefined") + { + navigator.openDatabase = window.openDatabase = dbSetup; + window.droiddb = new DroidDB(); + } +}); + diff --git a/plugins/.classpath b/plugins/.classpath deleted file mode 100644 index e4bcec4c..00000000 --- a/plugins/.classpath +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/plugins/.project b/plugins/.project deleted file mode 100644 index 5d814ceb..00000000 --- a/plugins/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - ponygap - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/plugins/AndroidManifest.xml b/plugins/AndroidManifest.xml deleted file mode 100644 index 26942144..00000000 --- a/plugins/AndroidManifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/plugins/build.properties b/plugins/build.properties deleted file mode 100644 index edc7f230..00000000 --- a/plugins/build.properties +++ /dev/null @@ -1,17 +0,0 @@ -# This file is used to override default values used by the Ant build system. -# -# This file must be checked in Version Control Systems, as it is -# integral to the build system of your project. - -# This file is only used by the Ant script. - -# You can use this to override default values such as -# 'source.dir' for the location of your java source folder and -# 'out.dir' for the location of your output folder. - -# You can also use it define how the release builds are signed by declaring -# the following properties: -# 'key.store' for the location of your keystore and -# 'key.alias' for the name of the key to use. -# The password will be asked during the build when you use the 'release' target. - diff --git a/plugins/build.xml b/plugins/build.xml deleted file mode 100644 index 56da6a1f..00000000 --- a/plugins/build.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/libs/phonegap.jar b/plugins/libs/phonegap.jar deleted file mode 100644 index 239a443f..00000000 Binary files a/plugins/libs/phonegap.jar and /dev/null differ diff --git a/plugins/local.properties b/plugins/local.properties deleted file mode 100644 index 546578e0..00000000 --- a/plugins/local.properties +++ /dev/null @@ -1,10 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked in Version Control Systems, -# as it contains information specific to your local configuration. - -# location of the SDK. This is only used by Ant -# For customization when using a Version Control System, please read the -# header note. -sdk.dir=/home/bowserj/android-sdk-linux_x86-1.6_r1 diff --git a/plugins/res/layout/main.xml b/plugins/res/layout/main.xml deleted file mode 100644 index 633b0d3c..00000000 --- a/plugins/res/layout/main.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/plugins/res/values/strings.xml b/plugins/res/values/strings.xml deleted file mode 100644 index 55f1fc2a..00000000 --- a/plugins/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - ponygap - diff --git a/plugins/src/com/phonegap/plugins/TtsManager.java b/plugins/src/com/phonegap/plugins/TtsManager.java deleted file mode 100644 index c34adeea..00000000 --- a/plugins/src/com/phonegap/plugins/TtsManager.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.phonegap.plugins; - -import android.content.Context; -import android.speech.tts.TextToSpeech; -import android.webkit.WebView; - -public class TtsManager { - - TextToSpeech voice; - Context mCtx; - WebView appView; - - TtsManager(WebView view, Context ctx) - { - mCtx = ctx; - appView = view; - voice = new TextToSpeech(mCtx, ttsInitListener); - } - - public void say(String text) - { - voice.speak(text, 1, null); - } - - //I have no idea why you would use this? Do you have predefined speech? - - private TextToSpeech.OnInitListener ttsInitListener = new TextToSpeech.OnInitListener() { - public void onInit(int status) { - - } - }; - - -} diff --git a/plugins/src/com/phonegap/plugins/ponygap.java b/plugins/src/com/phonegap/plugins/ponygap.java deleted file mode 100644 index 659ddd2a..00000000 --- a/plugins/src/com/phonegap/plugins/ponygap.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.phonegap.plugins; - -import android.os.Bundle; - -import com.phonegap.*; - -public class ponygap extends DroidGap -{ - /* Declare plugins here */ - TtsManager tts; - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - tts = new TtsManager(super.appView, this); - - super.appView.addJavascriptInterface(tts, "ttsHook"); - } -}