diff --git a/README.md b/README.md index 59431ec0..1f615532 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,16 @@ -PhoneGap Android +Cordova Android === -PhoneGap Android is an Android application library that allows for PhoneGap based projects to be built for the Android Platform. PhoneGap based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript. +Cordova Android is an Android application library that allows for Cordova based projects to be built for the Android Platform. Cordova based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript. + +Apache Cordova is an effort undergoing incubation at The Apache +Software Foundation (ASF), sponsored by the Apache Incubator project. +Incubation is required of all newly accepted projects until a further +review indicates that the infrastructure, communications, and decision +making process have stabilized in a manner consistent with other +successful ASF projects. While incubation status is not necessarily +a reflection of the completeness or stability of the code, it does +indicate that the project has yet to be fully endorsed by the ASF. Requires --- @@ -10,21 +19,21 @@ Requires - Apache ANT - Android SDK [http://developer.android.com](http://developer.android.com) -PhoneGap Android Developer Tools +Cordova Android Developer Tools --- -The PhoneGap developer tooling is split between general tooling and project level tooling. +The Cordova developer tooling is split between general tooling and project level tooling. General Commands - ./bin/create [path package activity] ... create the ./example app or a phonegap android project + ./bin/create [path package activity] ... create the ./example app or a cordova android project ./bin/bench ............................ generate a bench proj ./bin/autotest ......................... test the cli tools ./bin/test ............................. run mobile-spec Project Commands -These commands live in a generated PhoneGap Android project. +These commands live in a generated Cordova Android project. ./phonegap/debug [path] ..................... install to first device ./phonegap/emulate .......................... start avd (emulator) named default @@ -52,12 +61,12 @@ Running the [callback/callback-test](http://github.com/callback/callback-test) t ./bin/test -Creating a new PhoneGap Android Project +Creating a new Cordova Android Project --- ./bin/create ~/Desktop/myapp com.phonegap.special MyApp -Importing a PhoneGap Android Project into Eclipse +Importing a Cordova Android Project into Eclipse ---- 1. File > New > Project... diff --git a/framework/assets/js/camera.js b/framework/assets/js/camera.js index 17af89d7..e1467c63 100755 --- a/framework/assets/js/camera.js +++ b/framework/assets/js/camera.js @@ -127,7 +127,7 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options) options.maxResolution = 0; } if (options.destinationType === null || typeof options.destinationType === "undefined") { - options.destinationType = Camera.DestinationType.DATA_URL; + options.destinationType = Camera.DestinationType.FILE_URI; } if (options.sourceType === null || typeof options.sourceType === "undefined") { options.sourceType = Camera.PictureSourceType.CAMERA; diff --git a/framework/src/com/phonegap/AuthenticationToken.java b/framework/src/com/phonegap/AuthenticationToken.java new file mode 100644 index 00000000..9b759aad --- /dev/null +++ b/framework/src/com/phonegap/AuthenticationToken.java @@ -0,0 +1,51 @@ +package com.phonegap; + +/** + * The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource + */ +public class AuthenticationToken { + private String userName; + private String password; + + /** + * Gets the user name. + * + * @return the user name + */ + public String getUserName() { + return userName; + } + + /** + * Sets the user name. + * + * @param userName + * the new user name + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * Gets the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password + * the new password + */ + public void setPassword(String password) { + this.password = password; + } + + + + +} diff --git a/framework/src/com/phonegap/CameraLauncher.java b/framework/src/com/phonegap/CameraLauncher.java index dd619a24..f9257857 100755 --- a/framework/src/com/phonegap/CameraLauncher.java +++ b/framework/src/com/phonegap/CameraLauncher.java @@ -101,7 +101,7 @@ public class CameraLauncher extends Plugin { try { if (action.equals("takePicture")) { int srcType = CAMERA; - int destType = DATA_URL; + int destType = FILE_URI; this.targetHeight = 0; this.targetWidth = 0; this.encodingType = JPEG; diff --git a/framework/src/com/phonegap/ContactAccessorSdk5.java b/framework/src/com/phonegap/ContactAccessorSdk5.java index 9e9cee20..47a8111f 100644 --- a/framework/src/com/phonegap/ContactAccessorSdk5.java +++ b/framework/src/com/phonegap/ContactAccessorSdk5.java @@ -819,50 +819,49 @@ public class ContactAccessorSdk5 extends ContactAccessor { public String save(JSONObject contact) { AccountManager mgr = AccountManager.get(mApp); Account[] accounts = mgr.getAccounts(); - Account account = null; + String accountName = null; + String accountType = null; - if (accounts.length == 1) - account = accounts[0]; - else if (accounts.length > 1) { - for(Account a : accounts){ - if(a.type.contains("eas")&& a.name.matches(EMAIL_REGEXP)) /*Exchange ActiveSync*/ - { - account = a; - break; - } - } - if(account == null){ - for(Account a : accounts){ - if(a.type.contains("com.google") && a.name.matches(EMAIL_REGEXP)) /*Google sync provider*/ - { - account = a; - break; - } - } - } - if(account == null){ - for(Account a : accounts){ - if(a.name.matches(EMAIL_REGEXP)) /*Last resort, just look for an email address...*/ - { - account = a; - break; - } - } - } + if (accounts.length == 1) { + accountName = accounts[0].name; + accountType = accounts[0].type; } - - if(account == null) { - return null; + else if (accounts.length > 1) { + for(Account a : accounts) { + if(a.type.contains("eas")&& a.name.matches(EMAIL_REGEXP)) /*Exchange ActiveSync*/ { + accountName = a.name; + accountType = a.type; + break; + } + } + if(accountName == null){ + for(Account a : accounts){ + if(a.type.contains("com.google") && a.name.matches(EMAIL_REGEXP)) /*Google sync provider*/ { + accountName = a.name; + accountType = a.type; + break; + } + } + } + if(accountName == null){ + for(Account a : accounts){ + if(a.name.matches(EMAIL_REGEXP)) /*Last resort, just look for an email address...*/ { + accountName = a.name; + accountType = a.type; + break; + } + } + } } String id = getJsonString(contact, "id"); // Create new contact if (id == null) { - return createNewContact(contact, account); + return createNewContact(contact, accountType, accountName); } // Modify existing contact else { - return modifyContact(id, contact, account); + return modifyContact(id, contact, accountType, accountName); } } @@ -873,7 +872,7 @@ public class ContactAccessorSdk5 extends ContactAccessor { * @param contact the contact to be saved * @param account the account to be saved under */ - private String modifyContact(String id, JSONObject contact, Account account) { + private String modifyContact(String id, JSONObject contact, String accountType, String accountName) { // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact. // But not needed to update existing values. int rawId = (new Integer(getJsonString(contact,"rawId"))).intValue(); @@ -883,8 +882,8 @@ public class ContactAccessorSdk5 extends ContactAccessor { //Add contact type ops.add(ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI) - .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type) - .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, account.name) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName) .build()); // Modify name @@ -1427,14 +1426,14 @@ public class ContactAccessorSdk5 extends ContactAccessor { * @param contact the contact to be saved * @param account the account to be saved under */ - private String createNewContact(JSONObject contact, Account account) { + private String createNewContact(JSONObject contact, String accountType, String accountName) { // Create a list of attributes to add to the contact database ArrayList ops = new ArrayList(); //Add contact type ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) - .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type) - .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, account.name) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName) .build()); // Add name diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 26e3bc6a..2eee859b 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -18,16 +18,18 @@ */ package com.phonegap; -import java.util.HashMap; -import java.util.ArrayList; -import java.util.Stack; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.util.Iterator; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.json.JSONArray; import org.json.JSONException; +import org.xmlpull.v1.XmlPullParserException; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -55,6 +57,7 @@ import android.view.Window; import android.view.WindowManager; import android.webkit.ConsoleMessage; import android.webkit.GeolocationPermissions.Callback; +import android.webkit.HttpAuthHandler; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.SslErrorHandler; @@ -67,11 +70,10 @@ import android.webkit.WebViewClient; import android.widget.EditText; import android.widget.LinearLayout; +import com.phonegap.api.IPlugin; import com.phonegap.api.LOG; import com.phonegap.api.PhonegapActivity; -import com.phonegap.api.IPlugin; import com.phonegap.api.PluginManager; -import org.xmlpull.v1.XmlPullParserException; /** * This class is the main Android activity that represents the PhoneGap @@ -199,6 +201,9 @@ public class DroidGap extends PhonegapActivity { // (this is not the color for the webview, which is set in HTML) private int backgroundColor = Color.BLACK; + /** The authorization tokens. */ + private Hashtable authenticationTokens = new Hashtable(); + /* * The variables below are used to cache some of the activity properties. */ @@ -217,6 +222,88 @@ public class DroidGap extends PhonegapActivity { private boolean classicRender; + /** + * Sets the authentication token. + * + * @param authenticationToken + * the authentication token + * @param host + * the host + * @param realm + * the realm + */ + public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) { + + if(host == null) { + host = ""; + } + + if(realm == null) { + realm = ""; + } + + authenticationTokens.put(host.concat(realm), authenticationToken); + } + + /** + * Removes the authentication token. + * + * @param host + * the host + * @param realm + * the realm + * @return the authentication token or null if did not exist + */ + public AuthenticationToken removeAuthenticationToken(String host, String realm) { + return authenticationTokens.remove(host.concat(realm)); + } + + /** + * Gets the authentication token. + * + * In order it tries: + * 1- host + realm + * 2- host + * 3- realm + * 4- no host, no realm + * + * @param host + * the host + * @param realm + * the realm + * @return the authentication token + */ + public AuthenticationToken getAuthenticationToken(String host, String realm) { + AuthenticationToken token = null; + + token = authenticationTokens.get(host.concat(realm)); + + if(token == null) { + // try with just the host + token = authenticationTokens.get(host); + + // Try the realm + if(token == null) { + token = authenticationTokens.get(realm); + } + + // if no host found, just query for default + if(token == null) { + token = authenticationTokens.get(""); + } + } + + return token; + } + + /** + * Clear all authentication tokens. + */ + public void clearAuthenticationTokens() { + authenticationTokens.clear(); + } + + /** * Called when the activity is first created. * @@ -364,15 +451,15 @@ public class DroidGap extends PhonegapActivity { * @param url */ public void loadUrl(String url) { - - // If first page of app, then set URL to load to be the one passed in - if (this.initUrl == null || (this.urls.size() > 0)) { - this.loadUrlIntoView(url); - } - // Otherwise use the URL specified in the activity's extras bundle - else { - this.loadUrlIntoView(this.initUrl); - } + + // If first page of app, then set URL to load to be the one passed in + if (this.initUrl == null || (this.urls.size() > 0)) { + this.loadUrlIntoView(url); + } + // Otherwise use the URL specified in the activity's extras bundle + else { + this.loadUrlIntoView(this.initUrl); + } } /** @@ -434,10 +521,10 @@ public class DroidGap extends PhonegapActivity { // If loadingDialog property, then show the App loading dialog for first page of app String loading = null; if (me.urls.size() == 1) { - loading = me.getStringProperty("loadingDialog", null); + loading = me.getStringProperty("loadingDialog", null); } else { - loading = me.getStringProperty("loadingPageDialog", null); + loading = me.getStringProperty("loadingPageDialog", null); } if (loading != null) { @@ -493,15 +580,15 @@ public class DroidGap extends PhonegapActivity { * @param time The number of ms to wait before loading webview */ public void loadUrl(final String url, int time) { - - // If first page of app, then set URL to load to be the one passed in - if (this.initUrl == null || (this.urls.size() > 0)) { - this.loadUrlIntoView(url, time); - } - // Otherwise use the URL specified in the activity's extras bundle - else { - this.loadUrlIntoView(this.initUrl); - } + + // If first page of app, then set URL to load to be the one passed in + if (this.initUrl == null || (this.urls.size() > 0)) { + this.loadUrlIntoView(url, time); + } + // Otherwise use the URL specified in the activity's extras bundle + else { + this.loadUrlIntoView(this.initUrl); + } } /** @@ -515,14 +602,14 @@ public class DroidGap extends PhonegapActivity { // Clear cancel flag this.cancelLoadUrl = false; - - // If not first page of app, then load immediately - if (this.urls.size() > 0) { - this.loadUrlIntoView(url); - } - if (!url.startsWith("javascript:")) { - LOG.d(TAG, "DroidGap.loadUrl(%s, %d)", url, time); + // If not first page of app, then load immediately + if (this.urls.size() > 0) { + this.loadUrlIntoView(url); + } + + if (!url.startsWith("javascript:")) { + LOG.d(TAG, "DroidGap.loadUrl(%s, %d)", url, time); } final DroidGap me = this; @@ -1358,6 +1445,32 @@ public class DroidGap extends PhonegapActivity { return true; } + /** + * On received http auth request. + * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination + * + * @param view + * the view + * @param handler + * the handler + * @param host + * the host + * @param realm + * the realm + */ + @Override + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, + String realm) { + + // get the authentication token + AuthenticationToken token = getAuthenticationToken(host,realm); + + if(token != null) { + handler.proceed(token.getUserName(), token.getPassword()); + } + } + + @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { @@ -1732,7 +1845,7 @@ public class DroidGap extends PhonegapActivity { /** * Load PhoneGap configuration from res/xml/phonegap.xml. * Approved list of URLs that can be loaded into DroidGap - * + * * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR) * */ diff --git a/framework/src/com/phonegap/Storage.java b/framework/src/com/phonegap/Storage.java index fc74dc12..516f6b42 100755 --- a/framework/src/com/phonegap/Storage.java +++ b/framework/src/com/phonegap/Storage.java @@ -18,17 +18,22 @@ */ package com.phonegap; +import java.io.File; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult; + +import android.content.Context; import android.database.Cursor; import android.database.sqlite.*; /** - * This class implements the HTML5 database support for Android 1.X devices. It - * is not used for Android 2.X, since HTML5 database is built in to the browser. + * This class implements the HTML5 database support to work around a bug for + * Android 3.0 devices. It is not used for other versions of Android, since + * HTML5 database is built in to the browser. */ public class Storage extends Plugin { @@ -64,11 +69,7 @@ public class Storage extends Plugin { String result = ""; try { - // TODO: Do we want to allow a user to do this, since they could get - // to other app databases? - if (action.equals("setStorage")) { - this.setStorage(args.getString(0)); - } else if (action.equals("openDatabase")) { + if (action.equals("openDatabase")) { this.openDatabase(args.getString(0), args.getString(1), args.getString(2), args.getLong(3)); } else if (action.equals("executeSql")) { @@ -118,21 +119,6 @@ public class Storage extends Plugin { // LOCAL METHODS // -------------------------------------------------------------------------- - /** - * Set the application package for the database. Each application saves its - * database files in a directory with the application package as part of the - * file name. - * - * For example, application "com.phonegap.demo.Demo" would save its database - * files in "/data/data/com.phonegap.demo/databases/" directory. - * - * @param appPackage - * The application package. - */ - public void setStorage(String appPackage) { - this.path = "/data/data/" + appPackage + "/databases/"; - } - /** * Open database. * @@ -155,12 +141,10 @@ public class Storage extends Plugin { // If no database path, generate from application package if (this.path == null) { - Package pack = this.ctx.getClass().getPackage(); - String appPackage = pack.getName(); - this.setStorage(appPackage); + this.path = this.ctx.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); } - this.dbName = this.path + db + ".db"; + this.dbName = this.path + File.pathSeparator + db + ".db"; this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null); } @@ -249,9 +233,7 @@ public class Storage extends Plugin { } // Let JavaScript know that there are no more rows - this.sendJavascript("droiddb.completeQuery('" + tx_id + "', " + result - + ");"); - + this.sendJavascript("droiddb.completeQuery('" + tx_id + "', " + result + ");"); } }