From b323f329cc185fba87ace193d6fd7e93373b1af2 Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Thu, 10 May 2012 02:04:11 +0200 Subject: [PATCH 1/4] add volumeupbutton/volumedownbutton events --- framework/src/org/apache/cordova/DroidGap.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java index 107eb52a..a8b9df5d 100755 --- a/framework/src/org/apache/cordova/DroidGap.java +++ b/framework/src/org/apache/cordova/DroidGap.java @@ -1087,6 +1087,18 @@ public class DroidGap extends Activity implements CordovaInterface { return true; } + // If volumedown key + else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');"); + return super.onKeyUp(keyCode, event); + } + + // If volumeup key + else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { + this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');"); + return super.onKeyUp(keyCode, event); + } + return false; } From 8356ac67e859b4677fa0e18fdd7b58aa24ac6756 Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Tue, 22 May 2012 21:42:46 +0200 Subject: [PATCH 2/4] prevent volumeup/down default behaviour --- framework/src/org/apache/cordova/DroidGap.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java index a8b9df5d..61689db6 100755 --- a/framework/src/org/apache/cordova/DroidGap.java +++ b/framework/src/org/apache/cordova/DroidGap.java @@ -1090,13 +1090,13 @@ public class DroidGap extends Activity implements CordovaInterface { // If volumedown key else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');"); - return super.onKeyUp(keyCode, event); + return true; } // If volumeup key else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');"); - return super.onKeyUp(keyCode, event); + return true; } return false; From 0c9295f8bcfd801b0dee77b0c16838a856067603 Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Thu, 24 May 2012 02:01:27 +0200 Subject: [PATCH 3/4] listening to volume events now override default behaviour --- framework/assets/js/cordova.android.js | 39 ++++++++++++++++ framework/src/org/apache/cordova/App.java | 14 ++++++ .../src/org/apache/cordova/DroidGap.java | 44 ++++++++++++++++--- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js index cdf619df..f43e67b0 100644 --- a/framework/assets/js/cordova.android.js +++ b/framework/assets/js/cordova.android.js @@ -639,6 +639,9 @@ Channel.prototype.unsubscribe = function(g) { if (handler) { this.handlers[g] = null; delete this.handlers[g]; + } + // useful when same handler has been set multiple times and already deleted + if (this.numHandlers > 0) { this.numHandlers--; if (this.events.onUnsubscribe) this.events.onUnsubscribe.call(this); } @@ -1047,6 +1050,28 @@ module.exports = { cordova.addDocumentEventHandler('menubutton'); cordova.addDocumentEventHandler('searchbutton'); + function bindButtonChannel(buttonName) { + // generic button bind used for volumeup/volumedown buttons + return cordova.addDocumentEventHandler(buttonName + 'button', { + onSubscribe:function() { + // If we just attached the first handler, let native know we need to override the button. + if (this.numHandlers === 1) { + exec(null, null, "App", "overrideButton", [buttonName, true]); + } + }, + onUnsubscribe:function() { + // If we just detached the last handler, let native know we no longer override the volumeup button. + if (this.numHandlers === 0) { + exec(null, null, "App", "overrideButton", [buttonName, false]); + } + } + }); + + } + // Inject a listener for the volume buttons on the document. + var volumeUpButtonChannel = bindButtonChannel('volumeup'); + var volumeDownButtonChannel = bindButtonChannel('volumedown'); + // Figure out if we need to shim-in localStorage and WebSQL // support from the native side. var storage = require('cordova/plugin/android/storage'); @@ -3586,6 +3611,20 @@ module.exports = { exec(null, null, "App", "overrideBackbutton", [override]); }, + /** + * Override the default behavior of the Android volume button. + * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired. + * + * Note: The user should not have to call this method. Instead, when the user + * registers for the "volume[up|down]button" event, this is automatically done. + * + * @param button volumeup, volumedown + * @param override T=override, F=cancel override + */ + overrideButton:function(button, override) { + exec(null, null, "App", "overrideButton", [button, override]); + }, + /** * Exit and terminate the application. */ diff --git a/framework/src/org/apache/cordova/App.java b/framework/src/org/apache/cordova/App.java index 9b1c96a9..ea698f9c 100755 --- a/framework/src/org/apache/cordova/App.java +++ b/framework/src/org/apache/cordova/App.java @@ -62,6 +62,9 @@ public class App extends Plugin { } else if (action.equals("overrideBackbutton")) { this.overrideBackbutton(args.getBoolean(0)); + } + else if (action.equals("overrideButton")) { + this.overrideButton(args.getString(0), args.getBoolean(1)); } else if (action.equals("isBackbuttonOverridden")) { boolean b = this.isBackbuttonOverridden(); @@ -180,6 +183,17 @@ public class App extends Plugin { ((DroidGap)this.ctx).bound = override; } + /** + * Override the default behavior of the Android volume buttons. + * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired. + * + * @param button volumeup, volumedown + * @param override T=override, F=cancel override + */ + public void overrideButton(String button, boolean override) { + LOG.i("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden. The volume event will be fired!"); + ((DroidGap)this.ctx).bindButton(button, override); + } /** * Return whether the Android back button is overridden by the user. * diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java index e94a44e2..9b6ce131 100755 --- a/framework/src/org/apache/cordova/DroidGap.java +++ b/framework/src/org/apache/cordova/DroidGap.java @@ -158,6 +158,8 @@ public class DroidGap extends Activity implements CordovaInterface { protected LinearLayout root; public boolean bound = false; + public boolean volumeupBound = false; + public boolean volumedownBound = false; public CallbackServer callbackServer; protected PluginManager pluginManager; protected boolean cancelLoadUrl = false; @@ -1087,18 +1089,38 @@ public class DroidGap extends Activity implements CordovaInterface { return true; } + return false; + } + + /** + * Called when a key is pressed. (Key DOWN) + * + * @param keyCode + * @param event + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (this.appView == null) { + return super.onKeyDown(keyCode, event); + } + // If volumedown key - else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');"); - return true; + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + if (this.volumedownBound==true) { + // only override default behaviour is event bound + this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');"); + return true; + } } // If volumeup key else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');"); - return true; + if (this.volumeupBound==true) { + // only override default behaviour is event bound + this.appView.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');"); + return true; + } } - return false; } @@ -1416,6 +1438,16 @@ public class DroidGap extends Activity implements CordovaInterface { return this.bound; } + public void bindButton(String button, boolean override) { + // TODO Auto-generated method stub + if (button.compareTo("volumeup")==0) { + this.volumeupBound = override; + } + else if (button.compareTo("volumedown")==0) { + this.volumedownBound = override; + } + } + protected Dialog splashDialog; /** From be165c677fd265b133b6e4782d797c3fc0ac1535 Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Sat, 2 Jun 2012 22:57:35 +0200 Subject: [PATCH 4/4] upgrade to latest cordova.android.js --- framework/assets/js/cordova.android.js | 107 ++++++++----------------- 1 file changed, 34 insertions(+), 73 deletions(-) diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js index ddbb4b5e..2e91464d 100644 --- a/framework/assets/js/cordova.android.js +++ b/framework/assets/js/cordova.android.js @@ -1,6 +1,6 @@ -// commit 95f199e1c207dc89b84e79a9a7b27d6a3cc8fe14 +// commit 548f80ccff155e01a7dcbedfcc0d826253110f53 -// File generated at :: Thu May 24 2012 21:36:17 GMT-0400 (EDT) +// File generated at :: Sat Jun 02 2012 22:53:34 GMT+0200 (CEST) /* Licensed to the Apache Software Foundation (ASF) under one @@ -77,7 +77,7 @@ var channel = require('cordova/channel'); document.addEventListener('DOMContentLoaded', function() { channel.onDOMContentLoaded.fire(); }, false); -if (document.readyState == 'complete') { +if (document.readyState == 'complete' || document.readyState == 'interactive') { channel.onDOMContentLoaded.fire(); } @@ -99,7 +99,11 @@ var documentEventHandlers = {}, document.addEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); if (typeof documentEventHandlers[e] != 'undefined') { - documentEventHandlers[e].subscribe(handler); + if (evt === 'deviceready') { + documentEventHandlers[e].subscribeOnce(handler); + } else { + documentEventHandlers[e].subscribe(handler); + } } else { m_document_addEventListener.call(document, evt, handler, capture); } @@ -504,7 +508,7 @@ var Channel = function(type, opts) { this.type = type; this.handlers = {}; this.numHandlers = 0; - this.guid = 0; + this.guid = 1; this.fired = false; this.enabled = true; this.events = { @@ -595,12 +599,21 @@ Channel.prototype.subscribe = function(f, c, g) { var func = f; if (typeof c == "object") { func = utils.close(c, f); } - g = g || func.observer_guid || f.observer_guid || this.guid++; + g = g || func.observer_guid || f.observer_guid; + if (!g) { + // first time we've seen this subscriber + g = this.guid++; + } + else { + // subscriber already handled; dont set it twice + return g; + } func.observer_guid = g; f.observer_guid = g; this.handlers[g] = func; this.numHandlers++; if (this.events.onSubscribe) this.events.onSubscribe.call(this); + if (this.fired) func.call(this); return g; }; @@ -637,11 +650,9 @@ Channel.prototype.unsubscribe = function(g) { if (typeof g == 'function') { g = g.observer_guid; } var handler = this.handlers[g]; if (handler) { + if (handler.observer_guid) handler.observer_guid=null; this.handlers[g] = null; delete this.handlers[g]; - } - // useful when same handler has been set multiple times and already deleted - if (this.numHandlers > 0) { this.numHandlers--; if (this.events.onUnsubscribe) this.events.onUnsubscribe.call(this); } @@ -1113,7 +1124,7 @@ module.exports = { // Patch localStorage if necessary if (typeof window.localStorage == 'undefined' || window.localStorage === null) { - window.localStorage = new storage.CupCakeLocalStorage(); + window.localStorage = new storage.CupcakeLocalStorage(); } // Let native code know we are all done on the JS side. @@ -1284,8 +1295,12 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) { } else if (typeof options.saveToPhotoAlbum == "number") { saveToPhotoAlbum = options.saveToPhotoAlbum <=0 ? false : true; } + var popoverOptions = null; + if (typeof options.popoverOptions == "object") { + popoverOptions = options.popoverOptions; + } - exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, mediaType, allowEdit, correctOrientation, saveToPhotoAlbum]); + exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions]); }; module.exports = cameraExport; @@ -1311,6 +1326,13 @@ module.exports = { PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) CAMERA : 1, // Take picture from camera SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android) + }, + PopoverArrowDirection:{ + ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover + ARROW_DOWN : 2, + ARROW_LEFT : 4, + ARROW_RIGHT : 8, + ARROW_ANY : 15 } }; }); @@ -3628,6 +3650,7 @@ module.exports = { exec(null, null, "App", "overrideButton", [button, override]); }, + /** * Exit and terminate the application. */ @@ -5465,68 +5488,6 @@ var splashscreen = { module.exports = splashscreen; }); -// file: lib/common/plugin/widget.js -define("cordova/plugin/widget", function(require, exports, module) { -var exec = require('cordova/exec'), - cordova = require('cordova'), - channel = require('cordova/channel'); - -var Widget = function () { - this.author = null; - this.description = null; - this.name = null; - this.shortName = null; - this.version = null; - this.id = null; - this.authorEmail = null; - this.authorHref = null; - this._firstRun = true; - - var me = this; - - channel.onCordovaReady.subscribeOnce(function() { - me.getInfo(function (info) { - me.author = info.author; - me.description = info.description; - me.name = info.name; - me.shortName = info.shortName; - me.version = info.version; - me.id = info.id; - me.authorEmail = info.authorEmail; - me.authorHref = info.authorHref; - - // should only fire this once - if (me._firstRun) { - me._firstRun = false; - channel.onCordovaAppInfoReady.fire(); - } - }, - function (e) { - // If we can't get the network info we should still tell Cordova - // to fire the deviceready event. - if (me._firstRun) { - me._firstRun = false; - channel.onCordovaAppInfoReady.fire(); - } - console.log("Error initializing Widget: " + e); - }); - }); -}; - -/** - * Get connection info - * - * @param {Function} successCallback The function to call when the Connection data is available - * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL) - */ -Widget.prototype.getInfo = function (successCallback, errorCallback) { - // Get info - exec(successCallback, errorCallback, "Widget", "getApplicationInfo", []); -}; - -module.exports = new Widget(); -}); - // file: lib/common/utils.js define("cordova/utils", function(require, exports, module) { var utils = exports;