From d140c47fe4d0cee5e6d7f0df30c11dcd7bd65e63 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 07:05:22 -0400 Subject: [PATCH 01/25] 20130731.1 Cordova 3.0 support for Badge plugin --- iOS/Badge/{ => Cordova 2.x}/Badge.h | 0 iOS/Badge/{ => Cordova 2.x}/Badge.js | 0 iOS/Badge/{ => Cordova 2.x}/Badge.m | 0 iOS/Badge/plugin.xml | 26 ++++++++++++++++++ iOS/Badge/src/ios/Badge.h | 17 ++++++++++++ iOS/Badge/src/ios/Badge.m | 24 +++++++++++++++++ iOS/Badge/www/badge.js | 40 ++++++++++++++++++++++++++++ 7 files changed, 107 insertions(+) rename iOS/Badge/{ => Cordova 2.x}/Badge.h (100%) rename iOS/Badge/{ => Cordova 2.x}/Badge.js (100%) rename iOS/Badge/{ => Cordova 2.x}/Badge.m (100%) create mode 100644 iOS/Badge/plugin.xml create mode 100644 iOS/Badge/src/ios/Badge.h create mode 100644 iOS/Badge/src/ios/Badge.m create mode 100644 iOS/Badge/www/badge.js diff --git a/iOS/Badge/Badge.h b/iOS/Badge/Cordova 2.x/Badge.h similarity index 100% rename from iOS/Badge/Badge.h rename to iOS/Badge/Cordova 2.x/Badge.h diff --git a/iOS/Badge/Badge.js b/iOS/Badge/Cordova 2.x/Badge.js similarity index 100% rename from iOS/Badge/Badge.js rename to iOS/Badge/Cordova 2.x/Badge.js diff --git a/iOS/Badge/Badge.m b/iOS/Badge/Cordova 2.x/Badge.m similarity index 100% rename from iOS/Badge/Badge.m rename to iOS/Badge/Cordova 2.x/Badge.m diff --git a/iOS/Badge/plugin.xml b/iOS/Badge/plugin.xml new file mode 100644 index 00000000..be62a93a --- /dev/null +++ b/iOS/Badge/plugin.xml @@ -0,0 +1,26 @@ + + + + + Badge + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Badge/src/ios/Badge.h b/iOS/Badge/src/ios/Badge.h new file mode 100644 index 00000000..2ae4821a --- /dev/null +++ b/iOS/Badge/src/ios/Badge.h @@ -0,0 +1,17 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import +#import + +@interface Badge : CDVPlugin { +} +- (void)setBadge:(CDVInvokedUrlCommand*)command; + +@end \ No newline at end of file diff --git a/iOS/Badge/src/ios/Badge.m b/iOS/Badge/src/ios/Badge.m new file mode 100644 index 00000000..09c3fa0a --- /dev/null +++ b/iOS/Badge/src/ios/Badge.m @@ -0,0 +1,24 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import "Badge.h" + +@implementation Badge + +- (void)setBadge:(CDVInvokedUrlCommand*)command { + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(dispatch_get_main_queue(), ^(void) { + [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ command.arguments objectAtIndex:0] intValue]]; + }); + }); + +} + +@end \ No newline at end of file diff --git a/iOS/Badge/www/badge.js b/iOS/Badge/www/badge.js new file mode 100644 index 00000000..aeb61eea --- /dev/null +++ b/iOS/Badge/www/badge.js @@ -0,0 +1,40 @@ +/* +* This code is adapted from the work of Michael Nachbaur +* by Simon Madine of The Angry Robot Zombie Factory +* - Converted to Cordova 1.6.1 by Joseph Stuhr. +* 2012-04-19 +* MIT licensed +* +*/ + (function(cordova) { + + /* + * This class exposes the iPhone 'icon badge' functionality to JavaScript + * to add a number (with a red background) to each icon. + */ + function Badge() { } + + /** + * Positive integer sets the badge amount, 0 or negative removes it. + */ + Badge.prototype.set = function(options) { + cordova.exec(null,null,"Badge", "setBadge", [options]); + }; + + /** + * Shorthand to set the badge to 0 and remove it. + */ + Badge.prototype.clear = function() { + cordova.exec(null,null,"Badge","setBadge",[0]); + }; + + cordova.addConstructor(function() { + if(!window.plugins) window.plugins = {}; + window.plugins.badge = new Badge(); + }); + +})(window.cordova || window.Cordova); + + +/* DEBUG */ window.console.log('badge.js loaded...'); + From 991f7b80e33776111bb8950a36d8045be058a232 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 07:08:51 -0400 Subject: [PATCH 02/25] Cordova 3.0 support for PowerManagement --- .../{ => Cordova 2.x}/PowerManagement.h | 0 .../{ => Cordova 2.x}/PowerManagement.m | 0 .../{ => Cordova 2.x}/powermanagement.js | 0 iOS/PowerManagement/README.md | 56 ++--------- iOS/PowerManagement/README_old.md | 49 ++++++++++ iOS/PowerManagement/plugin.xml | 27 ++++++ iOS/PowerManagement/src/ios/PowerManagement.h | 48 ++++++++++ iOS/PowerManagement/src/ios/PowerManagement.m | 93 +++++++++++++++++++ iOS/PowerManagement/www/PowerManagement.js | 59 ++++++++++++ 9 files changed, 286 insertions(+), 46 deletions(-) rename iOS/PowerManagement/{ => Cordova 2.x}/PowerManagement.h (100%) rename iOS/PowerManagement/{ => Cordova 2.x}/PowerManagement.m (100%) rename iOS/PowerManagement/{ => Cordova 2.x}/powermanagement.js (100%) create mode 100644 iOS/PowerManagement/README_old.md create mode 100644 iOS/PowerManagement/plugin.xml create mode 100644 iOS/PowerManagement/src/ios/PowerManagement.h create mode 100644 iOS/PowerManagement/src/ios/PowerManagement.m create mode 100644 iOS/PowerManagement/www/PowerManagement.js diff --git a/iOS/PowerManagement/PowerManagement.h b/iOS/PowerManagement/Cordova 2.x/PowerManagement.h similarity index 100% rename from iOS/PowerManagement/PowerManagement.h rename to iOS/PowerManagement/Cordova 2.x/PowerManagement.h diff --git a/iOS/PowerManagement/PowerManagement.m b/iOS/PowerManagement/Cordova 2.x/PowerManagement.m similarity index 100% rename from iOS/PowerManagement/PowerManagement.m rename to iOS/PowerManagement/Cordova 2.x/PowerManagement.m diff --git a/iOS/PowerManagement/powermanagement.js b/iOS/PowerManagement/Cordova 2.x/powermanagement.js similarity index 100% rename from iOS/PowerManagement/powermanagement.js rename to iOS/PowerManagement/Cordova 2.x/powermanagement.js diff --git a/iOS/PowerManagement/README.md b/iOS/PowerManagement/README.md index 1c36035e..66bcb775 100644 --- a/iOS/PowerManagement/README.md +++ b/iOS/PowerManagement/README.md @@ -1,49 +1,13 @@ -PowerManagement -=============== -Plugin for Cordova (1.6+) +cordova-powermanagement +======================= -The PowerManagement plugin offers access to the devices power-management functionality. -It should be used for applications which keep running for a long time without any user interaction. +###Install to project: +cordova plugin add https://github.com/cemerson/cordova-powermanagement.git -For details on power functionality see: +###Remove from project: +cordova plugin rm org.apache.cordova.plugins.PowerManagement -* Android: [PowerManager](http://developer.android.com/reference/android/os/PowerManager.html) -* iOS: [idleTimerDisabled](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instp/UIApplication/idleTimerDisabled) - -Platforms ---------- -Currently available on: - -### Android -Copy the *PowerManagement.java* file to your *src/* directory. - -Edit your *AndroidManifest.xml* and add the following permission: -`` - -In addition you have to edit your *res/xml/plugins.xml* file to let Cordova know about the plugin: -`` - -### iOS -Copy the *PowerManagement.h* and *PowerManagement.m* files to your projects "Plugins" folder. - -Add the PowerManagement plugin to the *Cordova.plist* file (to the Plugins list). Both Key and Value are "PowerManagement". - - -License -======= -Copyright (C) 2011-2012 Wolfgang Koller - -This file is part of GOFG Sports Computer - http://www.gofg.at/. - -GOFG Sports Computer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -GOFG Sports Computer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GOFG Sports Computer. If not, see . +###Changes +- Removed All platforms except IOS for now :( +- Updated plugin files to work in CDV 3 CLI +- Updated PowerManagement.m to eliminate Background Thread warning in Xcode (reference: http://goo.gl/JokRZw) diff --git a/iOS/PowerManagement/README_old.md b/iOS/PowerManagement/README_old.md new file mode 100644 index 00000000..1c36035e --- /dev/null +++ b/iOS/PowerManagement/README_old.md @@ -0,0 +1,49 @@ +PowerManagement +=============== +Plugin for Cordova (1.6+) + +The PowerManagement plugin offers access to the devices power-management functionality. +It should be used for applications which keep running for a long time without any user interaction. + +For details on power functionality see: + +* Android: [PowerManager](http://developer.android.com/reference/android/os/PowerManager.html) +* iOS: [idleTimerDisabled](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instp/UIApplication/idleTimerDisabled) + +Platforms +--------- +Currently available on: + +### Android +Copy the *PowerManagement.java* file to your *src/* directory. + +Edit your *AndroidManifest.xml* and add the following permission: +`` + +In addition you have to edit your *res/xml/plugins.xml* file to let Cordova know about the plugin: +`` + +### iOS +Copy the *PowerManagement.h* and *PowerManagement.m* files to your projects "Plugins" folder. + +Add the PowerManagement plugin to the *Cordova.plist* file (to the Plugins list). Both Key and Value are "PowerManagement". + + +License +======= +Copyright (C) 2011-2012 Wolfgang Koller + +This file is part of GOFG Sports Computer - http://www.gofg.at/. + +GOFG Sports Computer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GOFG Sports Computer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GOFG Sports Computer. If not, see . diff --git a/iOS/PowerManagement/plugin.xml b/iOS/PowerManagement/plugin.xml new file mode 100644 index 00000000..ee3e1548 --- /dev/null +++ b/iOS/PowerManagement/plugin.xml @@ -0,0 +1,27 @@ + + + + + PowerManagement + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/PowerManagement/src/ios/PowerManagement.h b/iOS/PowerManagement/src/ios/PowerManagement.h new file mode 100644 index 00000000..1e918d41 --- /dev/null +++ b/iOS/PowerManagement/src/ios/PowerManagement.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011-2012 Wolfgang Koller + * + * This file is part of GOFG Sports Computer - http://www.gofg.at/. + * + * GOFG Sports Computer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GOFG Sports Computer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GOFG Sports Computer. If not, see . + */ + +/** + * Cordova (iOS) plugin for accessing the power-management functions of the device + */ + +#ifdef CORDOVA_FRAMEWORK +#import +#else +#import "CORDOVA/CDVPlugin.h" +#endif + +/** + * Interface which does the actual handling + */ +@interface PowerManagement :CDVPlugin { +} +/** + * Sets the idleTimerDisable property to true so that the idle timeout is disabled + */ +- (void) acquire:(CDVInvokedUrlCommand*)command; +// - (void) acquire:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; + +/** + * Sets the idleTimerDisable property to false so that the idle timeout is enabled + * + */ +- (void) release:(CDVInvokedUrlCommand*)command; +//- (void) release:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; + +@end diff --git a/iOS/PowerManagement/src/ios/PowerManagement.m b/iOS/PowerManagement/src/ios/PowerManagement.m new file mode 100644 index 00000000..5fb7b1d8 --- /dev/null +++ b/iOS/PowerManagement/src/ios/PowerManagement.m @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011-2012 Wolfgang Koller + * + * This file is part of GOFG Sports Computer - http://www.gofg.at/. + * + * GOFG Sports Computer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GOFG Sports Computer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GOFG Sports Computer. If not, see . + */ + +/** + * Cordova (iOS) plugin for accessing the power-management functions of the device + */ +#import "PowerManagement.h" + +/** + * Actual implementation of the interface + */ +@implementation PowerManagement +- (void) acquire:(CDVInvokedUrlCommand*)command{ + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + dispatch_async(dispatch_get_main_queue(), ^(void) { + + CDVPluginResult* result = nil; + NSString* jsString = nil; + NSString* callbackId = nil; + if(command.arguments.count) callbackId = [command.arguments objectAtIndex:0]; + + // Acquire a reference to the local UIApplication singleton + UIApplication* app = [UIApplication sharedApplication]; + + if( ![app isIdleTimerDisabled] ) { + [app setIdleTimerDisabled:true]; + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + jsString = [result toSuccessCallbackString:callbackId]; + } + else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer already disabled"]; + jsString = [result toErrorCallbackString:callbackId]; + } + + [self writeJavascript:jsString]; + + }); + }); +} + +- (void) release:(CDVInvokedUrlCommand*)command{ + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + dispatch_async(dispatch_get_main_queue(), ^(void) { + + CDVPluginResult* result = nil; + NSString* jsString = nil; + NSString* callbackId = nil; + if(command.arguments.count) callbackId = [command.arguments objectAtIndex:0]; + + // Acquire a reference to the local UIApplication singleton + UIApplication* app = [UIApplication sharedApplication]; + + + if( [app isIdleTimerDisabled] ) { + [app setIdleTimerDisabled:false]; + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + jsString = [result toSuccessCallbackString:callbackId]; + } + else { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer not disabled"]; + jsString = [result toErrorCallbackString:callbackId]; + } + + [self writeJavascript:jsString]; + + }); + }); + + +} +@end diff --git a/iOS/PowerManagement/www/PowerManagement.js b/iOS/PowerManagement/www/PowerManagement.js new file mode 100644 index 00000000..531d5da5 --- /dev/null +++ b/iOS/PowerManagement/www/PowerManagement.js @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011-2012 Wolfgang Koller + * + * This file is part of GOFG Sports Computer - http://www.gofg.at/. + * + * GOFG Sports Computer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GOFG Sports Computer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GOFG Sports Computer. If not, see . + */ + +cordova.define("cordova/plugin/powermanagement", function(require, exports, module) { + var exec = require('cordova/exec'); + + var PowerManagement = function() {}; + + /** + * Acquire a new wake-lock (keep device awake) + * + * @param powerMgmtSuccess function to be called when the wake-lock was acquired successfully + * @param errorCallback function to be called when there was a problem with acquiring the wake-lock + */ + PowerManagement.prototype.acquire = function(powerMgmtSuccess,powerMgmtError) { + exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'acquire', []); + } + + /** + * Release the wake-lock + * + * @param powerMgmtSuccess function to be called when the wake-lock was released successfully + * @param errorCallback function to be called when there was a problem while releasing the wake-lock + */ + PowerManagement.prototype.release = function(powerMgmtSuccess,powerMgmtError) { + exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'release', []); + } + + /** + * Acquire a partial wake-lock, allowing the device to dim the screen + * + * @param powerMgmtSuccess function to be called when the wake-lock was acquired successfully + * @param errorCallback function to be called when there was a problem with acquiring the wake-lock + */ + PowerManagement.prototype.dim = function(powerMgmtSuccess,powerMgmtError) { + exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'acquire', [true]); + } + + var powermanagement = new PowerManagement(); + module.exports = powermanagement; +}); + +/* DEBUG */ window.console.log('PowerManagement.js loaded...'); From 6ca7a4cda10aed032624e32445e366f2329b3abb Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 07:09:26 -0400 Subject: [PATCH 03/25] Cordova 3.0 support for SecureDeviceIdentifier --- iOS/SecureDeviceIdentifier/README.md | 56 +- iOS/SecureDeviceIdentifier/README_old.md | 47 ++ iOS/SecureDeviceIdentifier/plugin.xml | 30 + .../src/ios/SecureDeviceIdentifier.h | 33 + .../src/ios/SecureDeviceIdentifier.m | 39 + .../src/ios/SecureUDID/SecureUDID.h | 75 ++ .../src/ios/SecureUDID/SecureUDID.m | 679 ++++++++++++++++++ .../www/SecureDeviceIdentifier.js | 42 ++ 8 files changed, 958 insertions(+), 43 deletions(-) create mode 100644 iOS/SecureDeviceIdentifier/README_old.md create mode 100644 iOS/SecureDeviceIdentifier/plugin.xml create mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h create mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m create mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h create mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m create mode 100644 iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js diff --git a/iOS/SecureDeviceIdentifier/README.md b/iOS/SecureDeviceIdentifier/README.md index f0987005..3158d545 100644 --- a/iOS/SecureDeviceIdentifier/README.md +++ b/iOS/SecureDeviceIdentifier/README.md @@ -1,47 +1,17 @@ -# Cordova SecureDeviceIdentifier Plugin # -by [Olivier Louvignes](http://olouv.com) +com.apps-pi.securedeviceidentifier +----------------------------- ---- -### [This plugin is hosted by the author](https://github.com/mgcrea/cordova-secureudid/tree/master) ---- +###Install to project: +cordova plugin add https://github.com/cemerson/cordova-securedeviceidentifier.git -## DESCRIPTION ## +###Remove from project: +cordova plugin rm org.apache.cordova.plugins.SecureDeviceIdentifier -* This plugin provides a simple way to retreive a secureUDID to replace Apple deprecated UDID. - -* This plugin is built for Cordova >= v2.1.0 with ARC. - -* It relies on [SecureUDID](https://github.com/mgcrea/secureudid) to work (MIT license, included in ./libs). - -[![Screenshot](http://www.crashlytics.com/blog/wp-content/uploads/2012/03/SecureUDID.png)](https://github.com/mgcrea/cordova-secureudid/tree/master) - -## LICENSE ## - - The MIT License - - Copyright (c) 2012 Olivier Louvignes - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -## CREDITS ## - -Contributors : - -* [Olivier Louvignes](http://olouv.com), author. +###Changes +- Removed All platforms except IOS for now :( +- Updated plugin files to work in CDV 3 CLI +- Updated SecureDeviceIdentifier.m to eliminate Background Thread warning in Xcode (reference: http://goo.gl/JokRZw) +###TODO: +- If InAppBrowser is open in windowed mode and is called again to be fullscreen need to reset plugin to make sure fullscreen takes effect +- cleanup (never ends) \ No newline at end of file diff --git a/iOS/SecureDeviceIdentifier/README_old.md b/iOS/SecureDeviceIdentifier/README_old.md new file mode 100644 index 00000000..f0987005 --- /dev/null +++ b/iOS/SecureDeviceIdentifier/README_old.md @@ -0,0 +1,47 @@ +# Cordova SecureDeviceIdentifier Plugin # +by [Olivier Louvignes](http://olouv.com) + +--- +### [This plugin is hosted by the author](https://github.com/mgcrea/cordova-secureudid/tree/master) +--- + +## DESCRIPTION ## + +* This plugin provides a simple way to retreive a secureUDID to replace Apple deprecated UDID. + +* This plugin is built for Cordova >= v2.1.0 with ARC. + +* It relies on [SecureUDID](https://github.com/mgcrea/secureudid) to work (MIT license, included in ./libs). + +[![Screenshot](http://www.crashlytics.com/blog/wp-content/uploads/2012/03/SecureUDID.png)](https://github.com/mgcrea/cordova-secureudid/tree/master) + +## LICENSE ## + + The MIT License + + Copyright (c) 2012 Olivier Louvignes + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +## CREDITS ## + +Contributors : + +* [Olivier Louvignes](http://olouv.com), author. + diff --git a/iOS/SecureDeviceIdentifier/plugin.xml b/iOS/SecureDeviceIdentifier/plugin.xml new file mode 100644 index 00000000..ddff93a7 --- /dev/null +++ b/iOS/SecureDeviceIdentifier/plugin.xml @@ -0,0 +1,30 @@ + + + + + SecureDeviceIdentifier + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h new file mode 100755 index 00000000..565c577d --- /dev/null +++ b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h @@ -0,0 +1,33 @@ +// +// SecureDeviceIdentifier.h +// +// Created by Olivier Louvignes on 2012-05-31. +// +// Copyright 2012 Olivier Louvignes. All rights reserved. +// MIT Licensed + +#import +#import + +@interface SecureDeviceIdentifier : CDVPlugin { +} + +#pragma mark - Properties + +@property (nonatomic, copy) NSString* callbackId; +@property (nonatomic, copy) NSString* secureUDID; + +#pragma mark - Instance methods + +- (void)get:(CDVInvokedUrlCommand*)command; + +@end + +#pragma mark - Logging tools + +#ifdef DEBUG +# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); +#else +# define DLog(...) +#endif +#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m new file mode 100755 index 00000000..cb5ac721 --- /dev/null +++ b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m @@ -0,0 +1,39 @@ +// +// SecureDeviceIdentifier.m +// +// Created by Olivier Louvignes on 2012-05-31. +// +// Copyright 2012 Olivier Louvignes. All rights reserved. +// MIT Licensed + +#import "SecureDeviceIdentifier.h" +#import "SecureUDID.h" + +@implementation SecureDeviceIdentifier + +@synthesize callbackId = _callbackId, secureUDID = _secureUDID; + +- (void)get:(CDVInvokedUrlCommand*)command { + + self.callbackId = command.callbackId; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + //[self.commandDelegate runInBackground:^{ + NSDictionary *options = [command.arguments objectAtIndex:0]; + NSString *domain = [options objectForKey:@"domain"] ?: @""; + NSString *key = [options objectForKey:@"key"] ?: @""; + self.secureUDID = [SecureUDID UDIDForDomain:domain usingKey:key]; //NSLog(@"self.secureUDID %@", self.secureUDID); + + dispatch_async(dispatch_get_main_queue(), ^(void) { + // Create Plugin Result + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.secureUDID]; + // Call the Success Javascript function + [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackId]]; + }); + }); + + + +} + +@end diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h new file mode 100755 index 00000000..d1b0c245 --- /dev/null +++ b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h @@ -0,0 +1,75 @@ +// +// SecureUDID.h +// SecureUDID +// +// Created by Crashlytics Team on 3/22/12. +// Copyright (c) 2012 Crashlytics, Inc. All rights reserved. +// http://www.crashlytics.com +// info@crashlytics.com +// + +/* + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#import + +@interface SecureUDID : NSObject + +/* + Returns a unique id for the device, sandboxed to the domain and salt provided. This is a potentially + expensive call. You should not do this on the main thread, especially during launch. + + retrieveUDIDForDomain:usingKey:completion: is provided as an alternative for your 4.0+ coding convenience. + + Example usage: + #import "SecureUDID.h" + + NSString *udid = [SecureUDID UDIDForDomain:@"com.example.myapp" key:@"difficult-to-guess-key"]; + + */ ++ (NSString *)UDIDForDomain:(NSString *)domain usingKey:(NSString *)key; + +/* + Getting a SecureUDID can be very expensive. Use this call to derive an identifier in the background, + and invoke a block when ready. Use of this method implies a device running >= iOS 4.0. + + Example usage: + #import "SecureUDID.h" + + [SecureUDID retrieveUDIDForDomain:@"com.example.myapp" usingKey:@"difficult-to-guess-key" completion:^(NSString *identifier) { + // make use of identifier here + }]; + + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 ++ (void)retrieveUDIDForDomain:(NSString *)domain usingKey:(NSString *)key completion:(void (^)(NSString* identifier))completion; +#endif + +/* + Indicates that the system has been disabled via the Opt-Out mechansim. + */ ++ (BOOL)isOptedOut; + +@end + +/* + This identifier is returned when Opt-Out is enabled. + */ +extern NSString *const SUUIDDefaultIdentifier; diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m new file mode 100755 index 00000000..63710303 --- /dev/null +++ b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m @@ -0,0 +1,679 @@ +// +// SecureUDID.m +// SecureUDID +// +// Created by Crashlytics Team on 3/22/12. +// Copyright (c) 2012 Crashlytics, Inc. All rights reserved. +// http://www.crashlytics.com +// info@crashlytics.com +// + +/* + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +#import "SecureUDID.h" +#import +#import +#import +#import + +#define SUUID_SCHEMA_VERSION (1) +#define SUUID_MAX_STORAGE_LOCATIONS (64) + +NSString *const SUUIDDefaultIdentifier = @"00000000-0000-0000-0000-000000000000"; + +NSString *const SUUIDTypeDataDictionary = @"public.secureudid"; +NSString *const SUUIDTimeStampKey = @"SUUIDTimeStampKey"; +NSString *const SUUIDOwnerKey = @"SUUIDOwnerKey"; +NSString *const SUUIDLastAccessedKey = @"SUUIDLastAccessedKey"; +NSString *const SUUIDIdentifierKey = @"SUUIDIdentifierKey"; +NSString *const SUUIDOptOutKey = @"SUUIDOptOutKey"; +NSString *const SUUIDModelHashKey = @"SUUIDModelHashKey"; +NSString *const SUUIDSchemaVersionKey = @"SUUIDSchemaVersionKey"; +NSString *const SUUIDPastboardFileFormat = @"org.secureudid-%d"; + +NSData *SUUIDCryptorToData(CCOperation operation, NSData *value, NSData *key); +NSString *SUUIDCryptorToString(CCOperation operation, NSData *value, NSData *key); +NSData *SUUIDHash(NSData* data); +NSData *SUUIDModelHash(void); + +void SUUIDMarkOptedOut(void); +void SUUIDMarkOptedIn(void); +void SUUIDRemoveAllSecureUDIDData(void); +NSString *SUUIDPasteboardNameForNumber(NSInteger number); +NSInteger SUUIDStorageLocationForOwnerKey(NSData *key, NSMutableDictionary** dictionary); +NSDictionary *SUUIDDictionaryForStorageLocation(NSInteger number); +NSDictionary *SUUIDMostRecentDictionary(void); +void SUUIDWriteDictionaryToStorageLocation(NSInteger number, NSDictionary* dictionary); +void SUUIDDeleteStorageLocation(NSInteger number); + +BOOL SUUIDValidTopLevelObject(id object); +BOOL SUUIDValidOwnerObject(id object); + +@implementation SecureUDID + +/* + Returns a unique id for the device, sandboxed to the domain and salt provided. + + Example usage: + #import "SecureUDID.h" + + NSString *udid = [SecureUDID UDIDForDomain:@"com.example.myapp" salt:@"superSecretCodeHere!@##%#$#%$^"]; + + */ ++ (NSString *)UDIDForDomain:(NSString *)domain usingKey:(NSString *)key { + NSString *identifier = SUUIDDefaultIdentifier; + + // Salt the domain to make the crypt keys affectively unguessable. + NSData *domainAndKey = [[NSString stringWithFormat:@"%@%@", domain, key] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *ownerKey = SUUIDHash(domainAndKey); + + // Encrypt the salted domain key and load the pasteboard on which to store data + NSData *encryptedOwnerKey = SUUIDCryptorToData(kCCEncrypt, [domain dataUsingEncoding:NSUTF8StringEncoding], ownerKey); + + // @synchronized introduces an implicit @try-@finally, so care needs to be taken with the return value + @synchronized (self) { + NSMutableDictionary *topLevelDictionary = nil; + + // Retrieve an appropriate storage index for this owner + NSInteger ownerIndex = SUUIDStorageLocationForOwnerKey(encryptedOwnerKey, &topLevelDictionary); + + // If the model hash key is present, verify it, otherwise add it + NSData *storedModelHash = [topLevelDictionary objectForKey:SUUIDModelHashKey]; + NSData *modelHash = SUUIDModelHash(); + + if (storedModelHash) { + if (![modelHash isEqual:storedModelHash]) { + // The model hashes do not match - this structure is invalid + [topLevelDictionary removeAllObjects]; + } + } + + // store the current model hash + [topLevelDictionary setObject:modelHash forKey:SUUIDModelHashKey]; + + // check for the opt-out flag and return the default identifier if we find it + if ([[topLevelDictionary objectForKey:SUUIDOptOutKey] boolValue] == YES) { + return identifier; + } + + // If we encounter a schema version greater than we support, there is no simple alternative + // other than to simulate Opt Out. Any writes to the store risk corruption. + if ([[topLevelDictionary objectForKey:SUUIDSchemaVersionKey] intValue] > SUUID_SCHEMA_VERSION) { + return identifier; + } + + // Attempt to get the owner's dictionary. Should we get back nil from the encryptedDomain key, we'll still + // get a valid, empty mutable dictionary + NSMutableDictionary *ownerDictionary = [NSMutableDictionary dictionaryWithDictionary:[topLevelDictionary objectForKey:encryptedOwnerKey]]; + + // Set our last access time and claim ownership for this storage location. + NSDate* lastAccessDate = [NSDate date]; + + [ownerDictionary setObject:lastAccessDate forKey:SUUIDLastAccessedKey]; + [topLevelDictionary setObject:lastAccessDate forKey:SUUIDTimeStampKey]; + [topLevelDictionary setObject:encryptedOwnerKey forKey:SUUIDOwnerKey]; + + [topLevelDictionary setObject:[NSNumber numberWithInt:SUUID_SCHEMA_VERSION] forKey:SUUIDSchemaVersionKey]; + + // Make sure our owner dictionary is in the top level structure + [topLevelDictionary setObject:ownerDictionary forKey:encryptedOwnerKey]; + + + NSData *identifierData = [ownerDictionary objectForKey:SUUIDIdentifierKey]; + if (identifierData) { + identifier = SUUIDCryptorToString(kCCDecrypt, identifierData, ownerKey); + if (!identifier) { + // We've failed to decrypt our identifier. This is a sign of storage corruption. + SUUIDDeleteStorageLocation(ownerIndex); + + // return here - do not write values back to the store + return SUUIDDefaultIdentifier; + } + } else { + // Otherwise, create a new RFC-4122 Version 4 UUID + // http://en.wikipedia.org/wiki/Universally_unique_identifier + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); + identifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)); + CFRelease(uuid); + + // Encrypt it for storage. + NSData *data = SUUIDCryptorToData(kCCEncrypt, [identifier dataUsingEncoding:NSUTF8StringEncoding], ownerKey); + + [ownerDictionary setObject:data forKey:SUUIDIdentifierKey]; + } + + SUUIDWriteDictionaryToStorageLocation(ownerIndex, topLevelDictionary); + } + + return identifier; +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 ++ (void)retrieveUDIDForDomain:(NSString *)domain usingKey:(NSString *)key completion:(void (^)(NSString* identifier))completion { + // retreive the identifier on a low-priority thread + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + NSString* identifier; + + identifier = [SecureUDID UDIDForDomain:domain usingKey:key]; + + completion(identifier); + }); +} +#endif + +/* + API to determine if a device has opted out of SecureUDID. + */ ++ (BOOL)isOptedOut { + for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + NSDictionary* topLevelDictionary; + + topLevelDictionary = SUUIDDictionaryForStorageLocation(i); + if (!topLevelDictionary) { + continue; + } + + if ([[topLevelDictionary objectForKey:SUUIDOptOutKey] boolValue] == YES) { + return YES; + } + } + + return NO; +} + +/* + Applies the operation (encrypt or decrypt) to the NSData value with the provided NSData key + and returns the value as NSData. + */ +NSData *SUUIDCryptorToData(CCOperation operation, NSData *value, NSData *key) { + NSMutableData *output = [NSMutableData dataWithLength:value.length + kCCBlockSizeAES128]; + + size_t numBytes = 0; + CCCryptorStatus cryptStatus = CCCrypt(operation, + kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + [key bytes], + kCCKeySizeAES128, + NULL, + value.bytes, + value.length, + output.mutableBytes, + output.length, + &numBytes); + + if (cryptStatus == kCCSuccess) { + return [NSData dataWithBytes:output.bytes length:numBytes]; + } + + return nil; +} + +/* + Applies the operation (encrypt or decrypt) to the NSData value with the provided NSData key + and returns the value as an NSString. + */ +NSString *SUUIDCryptorToString(CCOperation operation, NSData *value, NSData *key) { + NSData* data; + + data = SUUIDCryptorToData(operation, value, key); + if (!data) { + return nil; + } + + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + +/* + Compute a SHA1 of the input. + */ +NSData *SUUIDHash(NSData *data) { + uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; + + CC_SHA1(data.bytes, data.length, digest); + + return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; +} + +NSData* SUUIDModelHash(void) { + NSString* result; + + result = nil; + + do { + size_t size; + + // first get the size + if (sysctlbyname("hw.machine", NULL, &size, NULL, 0) != 0) { + break; + } + + char value[size]; + + // now get the value + if (sysctlbyname("hw.machine", value, &size, NULL, 0) != 0) { + break; + } + + // convert the value to an NSString + result = [NSString stringWithCString:value encoding:NSUTF8StringEncoding]; + } while (0); + + if (!result) { + result = @"Unknown"; + } + + return SUUIDHash([result dataUsingEncoding:NSUTF8StringEncoding]); +} + +/* + Finds the most recent structure, and adds the Opt-Out flag to it. Then writes that structure back + out to all used storage locations, making sure to preserve ownership. + */ +void SUUIDMarkOptedOut(void) { + NSMutableDictionary* mostRecentDictionary; + + mostRecentDictionary = [NSMutableDictionary dictionaryWithDictionary:SUUIDMostRecentDictionary()]; + + [mostRecentDictionary setObject:[NSDate date] forKey:SUUIDTimeStampKey]; + [mostRecentDictionary setObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; + + for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + NSData* owner; + + // Inherit the owner, if it is present. This makes some schema assumptions. + owner = [SUUIDDictionaryForStorageLocation(i) objectForKey:SUUIDOwnerKey]; + if (owner) { + [mostRecentDictionary setObject:owner forKey:SUUIDOwnerKey]; + } + + // write the opt-out data even if the location was previously empty + SUUIDWriteDictionaryToStorageLocation(i, mostRecentDictionary); + } +} + +void SUUIDMarkOptedIn(void) { + NSDate* accessedDate; + + accessedDate = [NSDate date]; + + // Opting back in is trickier. We need to remove top-level Opt-Out markers. Also makes some + // schema assumptions. + for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + NSMutableDictionary* dictionary; + + dictionary = [NSMutableDictionary dictionaryWithDictionary:SUUIDDictionaryForStorageLocation(i)]; + if (!dictionary) { + // This is a possible indiction of storage corruption. However, SUUIDDictionaryForStorageLocation + // will have already cleaned it up for us, so there's not much to do here. + continue; + } + + [dictionary removeObjectForKey:SUUIDOptOutKey]; + + // quick check for the minimum set of keys. If the dictionary previously held just + // an Opt-Out marker + timestamp, dictionary is not invalid. Writing will fail in this + // case, leaving the data that was there. We need to delete. + if (!SUUIDValidTopLevelObject(dictionary)) { + SUUIDDeleteStorageLocation(i); + continue; + } + + [dictionary setObject:accessedDate forKey:SUUIDTimeStampKey]; + + SUUIDWriteDictionaryToStorageLocation(i, dictionary); + } +} + +/* + Removes all SecureUDID data from storage with the exception of Opt-Out flags, which + are never removed. Removing the Opt-Out flags would effectively opt a user back in. + */ +void SUUIDRemoveAllSecureUDIDData(void) { + NSDictionary* optOutPlaceholder = nil; + + if ([SecureUDID isOptedOut]) { + optOutPlaceholder = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; + } + + for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + if (optOutPlaceholder) { + SUUIDWriteDictionaryToStorageLocation(i, optOutPlaceholder); + continue; + } + + SUUIDDeleteStorageLocation(i); + } +} + +/* + Returns an NSString formatted with the supplied number. + */ +NSString *SUUIDPasteboardNameForNumber(NSInteger number) { + return [NSString stringWithFormat:SUUIDPastboardFileFormat, number]; +} + +/* + Reads a dictionary from a storage location. Validation occurs once data + is read, but before it is returned. If something fails, or if the read structure + is invalid, the location is cleared. + + Returns the data dictionary, or nil on failure. + */ +NSDictionary *SUUIDDictionaryForStorageLocation(NSInteger number) { + id decodedObject; + UIPasteboard* pasteboard; + NSData* data; + + // Don't even bother if the index is outside our limits + if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { + return nil; + } + + pasteboard = [UIPasteboard pasteboardWithName:SUUIDPasteboardNameForNumber(number) create:NO]; + if (!pasteboard) { + return nil; + } + + data = [pasteboard valueForPasteboardType:SUUIDTypeDataDictionary]; + if (!data) { + return nil; + } + + @try { + decodedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + } @catch (NSException* exception) { + // Catching an exception like this is risky. However, crashing here is + // not acceptable, and unarchiveObjectWithData can throw. + [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; + + return nil; + } + + if (!SUUIDValidTopLevelObject(decodedObject)) { + [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; + + return nil; + } + + return decodedObject; +} + +NSDictionary *SUUIDMostRecentDictionary(void) { + NSDictionary* mostRecentDictionary; + BOOL found; + + mostRecentDictionary = [NSDictionary dictionaryWithObject:[NSDate distantPast] forKey:SUUIDTimeStampKey]; + + // scan all locations looking for the most recent + for (NSUInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + NSDictionary* dictionary; + NSDate* date; + + dictionary = SUUIDDictionaryForStorageLocation(i); + if (!dictionary) { + continue; + } + + // Schema assumption + date = [dictionary objectForKey:SUUIDTimeStampKey]; + if ([date compare:[mostRecentDictionary objectForKey:SUUIDTimeStampKey]] == NSOrderedDescending) { + mostRecentDictionary = dictionary; + found = YES; + } + } + + if (!found) { + return nil; + } + + return mostRecentDictionary; +} + +/* + Writes out a dictionary to a storage location. That dictionary must be a 'valid' + SecureUDID structure, and the location must be within range. A new location is + created if is didn't already exist. + */ +void SUUIDWriteDictionaryToStorageLocation(NSInteger number, NSDictionary* dictionary) { + UIPasteboard* pasteboard; + + // be sure to respect our limits + if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { + return; + } + + // only write out valid structures + if (!SUUIDValidTopLevelObject(dictionary)) { + return; + } + + pasteboard = [UIPasteboard pasteboardWithName:SUUIDPasteboardNameForNumber(number) create:YES]; + if (!pasteboard) { + return; + } + + pasteboard.persistent = YES; + + [pasteboard setData:[NSKeyedArchiver archivedDataWithRootObject:dictionary] + forPasteboardType:SUUIDTypeDataDictionary]; +} + +/* + Clear a storage location, removing anything stored there. Useful for dealing with + potential corruption. Be careful with this function, as it can remove Opt-Out markers. + */ +void SUUIDDeleteStorageLocation(NSInteger number) { + UIPasteboard* pasteboard; + NSString* name; + + if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { + return; + } + + name = SUUIDPasteboardNameForNumber(number); + pasteboard = [UIPasteboard pasteboardWithName:name create:NO]; + if (!pasteboard) + return; + + // While setting pasteboard data to nil seems to always remove contents, the + // removePasteboardWithName: call doesn't appear to always work. Using both seems + // like the safest thing to do + [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; + [UIPasteboard removePasteboardWithName:name]; +} + +/* + SecureUDID leverages UIPasteboards to persistently store its data. + UIPasteboards marked as 'persistent' have the following attributes: + - They persist across application relaunches, device reboots, and OS upgrades. + - They are destroyed when the application that created them is deleted from the device. + + To protect against the latter case, SecureUDID leverages multiple pasteboards (up to + SUUID_MAX_STORAGE_LOCATIONS), creating one for each distinct domain/app that + leverages the system. The permanence of SecureUDIDs increases exponentially with the + number of apps that use it. + + This function searches for a suitable storage location for a SecureUDID structure. It + attempts to find the structure written by ownerKey. If no owner is found and there are + still open locations, the lowest numbered location is selected. If there are no + available locations, the last-written is selected. + + Once a spot is found, the most-recent data is re-written over this location. The location + is then, finally, returned. + */ +NSInteger SUUIDStorageLocationForOwnerKey(NSData *ownerKey, NSMutableDictionary** ownerDictionary) { + NSInteger ownerIndex; + NSInteger lowestUnusedIndex; + NSInteger oldestUsedIndex; + NSDate* mostRecentDate; + NSDate* oldestUsedDate; + NSDictionary* mostRecentDictionary; + BOOL optedOut; + + ownerIndex = -1; + lowestUnusedIndex = -1; + oldestUsedIndex = 0; // make sure this value is always in range + mostRecentDate = [NSDate distantPast]; + oldestUsedDate = [NSDate distantFuture]; + mostRecentDictionary = nil; + optedOut = NO; + + // The array of SecureUDID pasteboards can be sparse, since any number of + // apps may have been deleted. To find a pasteboard owned by the the current + // domain, iterate all of them. + for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { + NSDate* modifiedDate; + NSDictionary* dictionary; + + dictionary = SUUIDDictionaryForStorageLocation(i); + if (!dictionary) { + if (lowestUnusedIndex == -1) { + lowestUnusedIndex = i; + } + + continue; + } + + // Check the 'modified' timestamp of this pasteboard + modifiedDate = [dictionary valueForKey:SUUIDTimeStampKey]; + optedOut = optedOut || [[dictionary valueForKey:SUUIDOptOutKey] boolValue]; + + // Hold a copy of the data if this is the newest we've found so far. + if ([modifiedDate compare:mostRecentDate] == NSOrderedDescending) { + mostRecentDate = modifiedDate; + mostRecentDictionary = dictionary; + } + + // Check for the oldest entry in the structure, used for eviction + if ([modifiedDate compare:oldestUsedDate] == NSOrderedAscending) { + oldestUsedDate = modifiedDate; + oldestUsedIndex = i; + } + + // Finally, check if this is the pasteboard owned by the requesting domain. + if ([[dictionary objectForKey:SUUIDOwnerKey] isEqual:ownerKey]) { + ownerIndex = i; + } + } + + // If no pasteboard is owned by this domain, establish a new one to increase the + // likelihood of permanence. + if (ownerIndex == -1) { + // Unless there are no available slots, then evict the oldest entry + if ((lowestUnusedIndex < 0) || (lowestUnusedIndex >= SUUID_MAX_STORAGE_LOCATIONS)) { + ownerIndex = oldestUsedIndex; + } else { + ownerIndex = lowestUnusedIndex; + } + } + + // pass back the dictionary, by reference + *ownerDictionary = [NSMutableDictionary dictionaryWithDictionary:mostRecentDictionary]; + + // make sure our Opt-Out flag is consistent + if (optedOut) { + [*ownerDictionary setObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; + } + + // Make sure to write the most recent structure to the new location + SUUIDWriteDictionaryToStorageLocation(ownerIndex, mostRecentDictionary); + + return ownerIndex; +} + +/* + Attempts to validate the full SecureUDID structure. + */ +BOOL SUUIDValidTopLevelObject(id object) { + if (![object isKindOfClass:[NSDictionary class]]) { + return NO; + } + + // Now, we need to verify the current schema. There are a few possible valid states: + // - SUUIDTimeStampKey + SUUIDOwnerKey + at least one additional key that is not SUUIDOptOutKey + // - SUUIDTimeStampKey + SUUIDOwnerKey + SUUIDOptOutKey + + if ([(NSDictionary *)object objectForKey:SUUIDTimeStampKey] && [(NSDictionary *)object objectForKey:SUUIDOwnerKey]) { + NSMutableDictionary* ownersOnlyDictionary; + NSData* ownerField; + + if ([(NSDictionary *)object objectForKey:SUUIDOptOutKey]) { + return YES; + } + + // We have to trust future schema versions. Note that the lack of a schema version key will + // always fail this check, since the first schema version was 1. + if ([[(NSDictionary *)object objectForKey:SUUIDSchemaVersionKey] intValue] > SUUID_SCHEMA_VERSION) { + return YES; + } + + ownerField = [(NSDictionary *)object objectForKey:SUUIDOwnerKey]; + if (![ownerField isKindOfClass:[NSData class]]) { + return NO; + } + + ownersOnlyDictionary = [NSMutableDictionary dictionaryWithDictionary:object]; + + [ownersOnlyDictionary removeObjectForKey:SUUIDTimeStampKey]; + [ownersOnlyDictionary removeObjectForKey:SUUIDOwnerKey]; + [ownersOnlyDictionary removeObjectForKey:SUUIDOptOutKey]; + [ownersOnlyDictionary removeObjectForKey:SUUIDModelHashKey]; + [ownersOnlyDictionary removeObjectForKey:SUUIDSchemaVersionKey]; + + // now, iterate through to verify each internal structure + for (id key in [ownersOnlyDictionary allKeys]) { + if ([key isEqual:SUUIDTimeStampKey] || [key isEqual:SUUIDOwnerKey] || [key isEqual:SUUIDOptOutKey]) + continue; + + if (![key isKindOfClass:[NSData class]]) { + return NO; + } + + if (!SUUIDValidOwnerObject([ownersOnlyDictionary objectForKey:key])) { + return NO; + } + } + + // if all these tests pass, this structure is valid + return YES; + } + + // Maybe just the SUUIDOptOutKey, on its own + if ([[(NSDictionary *)object objectForKey:SUUIDOptOutKey] boolValue] == YES) { + return YES; + } + + return NO; +} + +/* + Attempts to validate the structure for an "owner dictionary". + */ +BOOL SUUIDValidOwnerObject(id object) { + if (![object isKindOfClass:[NSDictionary class]]) { + return NO; + } + + return [object valueForKey:SUUIDLastAccessedKey] && [object valueForKey:SUUIDIdentifierKey]; +} + +@end diff --git a/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js b/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js new file mode 100644 index 00000000..be5fd39c --- /dev/null +++ b/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js @@ -0,0 +1,42 @@ +// +// SecureDeviceIdentifier.js +// +// Created by Olivier Louvignes on 05/31/2012. +// +// Copyright 2012 Olivier Louvignes. All rights reserved. +// MIT Licensed + +(function(cordova) { + + function SecureDeviceIdentifier() {} + + SecureDeviceIdentifier.prototype.get = function(options, callback) { + if(!options) options = {}; + var scope = options.scope || null; + delete options.scope; + + var service = 'SecureDeviceIdentifier', + action = 'get', + callbackId = service + (cordova.callbackId + 1); + + var config = { + domain: options.domain || 'com.example.myapp', + key: options.key || 'difficult-to-guess-key' + }; + + var _callback = function(result) { + if(typeof callback == 'function') callback.apply(scope, arguments); + }; + + return cordova.exec(_callback, _callback, service, action, [config]); + + }; + + cordova.addConstructor(function() { + if(!window.plugins) window.plugins = {}; + window.plugins.secureDeviceIdentifier = new SecureDeviceIdentifier(); + }); + +})(window.cordova || window.Cordova); + +/* DEBUG */ window.console.log('SecureDeviceIdentifier.js loaded...'); \ No newline at end of file From 2aeaf7346582932acbc6f604b635e76b2fdf9184 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 07:11:24 -0400 Subject: [PATCH 04/25] Modified InAppBrowser to allow width, height, x/y positioning. Uses the current Cordova 3.0 version of the official InAppBrowser plugin. --- iOS/InAppBrowser/README.md | 28 + iOS/InAppBrowser/plugin.xml | 60 ++ .../src/android/InAppBrowser.java | 832 +++++++++++++++ iOS/InAppBrowser/src/blackberry10/README.md | 25 + iOS/InAppBrowser/src/ios/CDVInAppBrowser.h | 98 ++ iOS/InAppBrowser/src/ios/CDVInAppBrowser.m | 958 ++++++++++++++++++ iOS/InAppBrowser/src/wp/InAppBrowser.cs | 277 +++++ iOS/InAppBrowser/www/InAppBrowser.js | 98 ++ 8 files changed, 2376 insertions(+) create mode 100644 iOS/InAppBrowser/README.md create mode 100644 iOS/InAppBrowser/plugin.xml create mode 100644 iOS/InAppBrowser/src/android/InAppBrowser.java create mode 100644 iOS/InAppBrowser/src/blackberry10/README.md create mode 100644 iOS/InAppBrowser/src/ios/CDVInAppBrowser.h create mode 100644 iOS/InAppBrowser/src/ios/CDVInAppBrowser.m create mode 100644 iOS/InAppBrowser/src/wp/InAppBrowser.cs create mode 100644 iOS/InAppBrowser/www/InAppBrowser.js diff --git a/iOS/InAppBrowser/README.md b/iOS/InAppBrowser/README.md new file mode 100644 index 00000000..0eaffafa --- /dev/null +++ b/iOS/InAppBrowser/README.md @@ -0,0 +1,28 @@ +cordova-plugin-inappbrowser +----------------------------- +To install this plugin, follow the [Command-line Interface Guide](http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface). + +If you are not using the Cordova Command-line Interface, follow [Using Plugman to Manage Plugins](http://cordova.apache.org/docs/en/edge/guide_plugin_ref_plugman.md.html). + +###Notes: +- Main reason I updated this plugin is to maintain the ability to specify Width/Height and Xposition/YPosition of my web views. I had it working in the Cordova 2.x world - but this updated version blew that all up so I had to go in and hack things up to get it working again. I am not an ace ObjC programmer by any stretch - so please share whatever adjustments, clean-up or polish suggestions if anyone has any! +- New parameters available with this version of InAppBrowser are as follows (example usage below: + - **vw,vh,vx,vy** (width, height, xpos, ypos). . + - **buttoncolorbg** (I got sick of that default blue button so now you can specifyc a html hex color for the button background. Maybe one day I'll add similar stuff for the other UI elements [toolbar, label colors etc]). +- For some reason CoreGraphics framework isn't being auto added to project (even thought its specified in the plugin.xml so it has to be manually added when using this plugin otherwise you'll get a build error. + +###Install Plugin +cordova plugins add https://github.com/cemerson/cordova-inappbrowser-ce.git + +###Remove Plugin +cordova plugins rm org.apache.cordova.core.inappbrowser-ce + +###Usage Examples: +####window.open() no options: + window.open('http://www.ign.com','_blank'); + +####window.open() with fancy options!: + window.open('http://www.ign.com','_blank','vw=568,vh=1004,vx=200,vy=0,buttoncolorbg=#BA8C3C'); + +####window.open() with PDFs + (nothing special to note here - same options from above apply) diff --git a/iOS/InAppBrowser/plugin.xml b/iOS/InAppBrowser/plugin.xml new file mode 100644 index 00000000..f46f40c3 --- /dev/null +++ b/iOS/InAppBrowser/plugin.xml @@ -0,0 +1,60 @@ + + + + InAppBrowserCE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/InAppBrowser/src/android/InAppBrowser.java b/iOS/InAppBrowser/src/android/InAppBrowser.java new file mode 100644 index 00000000..581a4a08 --- /dev/null +++ b/iOS/InAppBrowser/src/android/InAppBrowser.java @@ -0,0 +1,832 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova.core; + +import java.util.HashMap; +import java.util.StringTokenizer; + + +import org.apache.cordova.Config; +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.LOG; +import org.apache.cordova.PluginResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.text.InputType; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.webkit.WebChromeClient; +import android.webkit.GeolocationPermissions.Callback; +import android.webkit.JsPromptResult; +import android.webkit.WebSettings; +import android.webkit.WebStorage; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; + +@SuppressLint("SetJavaScriptEnabled") +public class InAppBrowser extends CordovaPlugin { + + private static final String NULL = "null"; + protected static final String LOG_TAG = "InAppBrowser"; + private static final String SELF = "_self"; + private static final String SYSTEM = "_system"; + // private static final String BLANK = "_blank"; + private static final String EXIT_EVENT = "exit"; + private static final String LOCATION = "location"; + private static final String HIDDEN = "hidden"; + private static final String LOAD_START_EVENT = "loadstart"; + private static final String LOAD_STOP_EVENT = "loadstop"; + private static final String LOAD_ERROR_EVENT = "loaderror"; + private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption"; + private long MAX_QUOTA = 100 * 1024 * 1024; + + private Dialog dialog; + private WebView inAppWebView; + private EditText edittext; + private CallbackContext callbackContext; + private boolean showLocationBar = true; + private boolean openWindowHidden = false; + private String buttonLabel = "Done"; + + /** + * Executes the request and returns PluginResult. + * + * @param action The action to execute. + * @param args JSONArry of arguments for the plugin. + * @param callbackId The callback id used when calling back into JavaScript. + * @return A PluginResult object with a status and message. + */ + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + try { + if (action.equals("open")) { + this.callbackContext = callbackContext; + String url = args.getString(0); + String target = args.optString(1); + if (target == null || target.equals("") || target.equals(NULL)) { + target = SELF; + } + HashMap features = parseFeature(args.optString(2)); + + Log.d(LOG_TAG, "target = " + target); + + url = updateUrl(url); + String result = ""; + + // SELF + if (SELF.equals(target)) { + Log.d(LOG_TAG, "in self"); + // load in webview + if (url.startsWith("file://") || url.startsWith("javascript:") + || Config.isUrlWhiteListed(url)) { + this.webView.loadUrl(url); + } + //Load the dialer + else if (url.startsWith(WebView.SCHEME_TEL)) + { + try { + Intent intent = new Intent(Intent.ACTION_DIAL); + intent.setData(Uri.parse(url)); + this.cordova.getActivity().startActivity(intent); + } catch (android.content.ActivityNotFoundException e) { + LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); + } + } + // load in InAppBrowser + else { + result = this.showWebPage(url, features); + } + } + // SYSTEM + else if (SYSTEM.equals(target)) { + Log.d(LOG_TAG, "in system"); + result = this.openExternal(url); + } + // BLANK - or anything else + else { + Log.d(LOG_TAG, "in blank"); + result = this.showWebPage(url, features); + } + + PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result); + pluginResult.setKeepCallback(true); + this.callbackContext.sendPluginResult(pluginResult); + } + else if (action.equals("close")) { + closeDialog(); + this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + else if (action.equals("injectScriptCode")) { + String jsWrapper = null; + if (args.getBoolean(1)) { + jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId()); + } + injectDeferredObject(args.getString(0), jsWrapper); + } + else if (action.equals("injectScriptFile")) { + String jsWrapper; + if (args.getBoolean(1)) { + jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId()); + } else { + jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)"; + } + injectDeferredObject(args.getString(0), jsWrapper); + } + else if (action.equals("injectStyleCode")) { + String jsWrapper; + if (args.getBoolean(1)) { + jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId()); + } else { + jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)"; + } + injectDeferredObject(args.getString(0), jsWrapper); + } + else if (action.equals("injectStyleFile")) { + String jsWrapper; + if (args.getBoolean(1)) { + jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId()); + } else { + jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)"; + } + injectDeferredObject(args.getString(0), jsWrapper); + } + else if (action.equals("show")) { + Runnable runnable = new Runnable() { + @Override + public void run() { + dialog.show(); + } + }; + this.cordova.getActivity().runOnUiThread(runnable); + this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + else { + return false; + } + } catch (JSONException e) { + this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + } + return true; + } + + /** + * Inject an object (script or style) into the InAppBrowser WebView. + * + * This is a helper method for the inject{Script|Style}{Code|File} API calls, which + * provides a consistent method for injecting JavaScript code into the document. + * + * If a wrapper string is supplied, then the source string will be JSON-encoded (adding + * quotes) and wrapped using string formatting. (The wrapper string should have a single + * '%s' marker) + * + * @param source The source object (filename or script/style text) to inject into + * the document. + * @param jsWrapper A JavaScript string to wrap the source string in, so that the object + * is properly injected, or null if the source string is JavaScript text + * which should be executed directly. + */ + private void injectDeferredObject(String source, String jsWrapper) { + String scriptToInject; + if (jsWrapper != null) { + org.json.JSONArray jsonEsc = new org.json.JSONArray(); + jsonEsc.put(source); + String jsonRepr = jsonEsc.toString(); + String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1); + scriptToInject = String.format(jsWrapper, jsonSourceString); + } else { + scriptToInject = source; + } + // This action will have the side-effect of blurring the currently focused element + this.inAppWebView.loadUrl("javascript:" + scriptToInject); + } + + /** + * Put the list of features into a hash map + * + * @param optString + * @return + */ + private HashMap parseFeature(String optString) { + if (optString.equals(NULL)) { + return null; + } else { + HashMap map = new HashMap(); + StringTokenizer features = new StringTokenizer(optString, ","); + StringTokenizer option; + while(features.hasMoreElements()) { + option = new StringTokenizer(features.nextToken(), "="); + if (option.hasMoreElements()) { + String key = option.nextToken(); + if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) { + this.buttonLabel = option.nextToken(); + } else { + Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE; + map.put(key, value); + } + } + } + return map; + } + } + + /** + * Convert relative URL to full path + * + * @param url + * @return + */ + private String updateUrl(String url) { + Uri newUrl = Uri.parse(url); + if (newUrl.isRelative()) { + url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url; + } + return url; + } + + /** + * Display a new browser with the specified URL. + * + * @param url The url to load. + * @param usePhoneGap Load url in PhoneGap webview + * @return "" if ok, or error message. + */ + public String openExternal(String url) { + try { + Intent intent = null; + intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + this.cordova.getActivity().startActivity(intent); + return ""; + } catch (android.content.ActivityNotFoundException e) { + Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString()); + return e.toString(); + } + } + + /** + * Closes the dialog + */ + private void closeDialog() { + try { + this.inAppWebView.loadUrl("about:blank"); + JSONObject obj = new JSONObject(); + obj.put("type", EXIT_EVENT); + + sendUpdate(obj, false); + } catch (JSONException ex) { + Log.d(LOG_TAG, "Should never happen"); + } + + if (dialog != null) { + dialog.dismiss(); + } + } + + /** + * Checks to see if it is possible to go back one page in history, then does so. + */ + private void goBack() { + if (this.inAppWebView.canGoBack()) { + this.inAppWebView.goBack(); + } + } + + /** + * Checks to see if it is possible to go forward one page in history, then does so. + */ + private void goForward() { + if (this.inAppWebView.canGoForward()) { + this.inAppWebView.goForward(); + } + } + + /** + * Navigate to the new page + * + * @param url to load + */ + private void navigate(String url) { + InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); + + if (!url.startsWith("http") && !url.startsWith("file:")) { + this.inAppWebView.loadUrl("http://" + url); + } else { + this.inAppWebView.loadUrl(url); + } + this.inAppWebView.requestFocus(); + } + + + /** + * Should we show the location bar? + * + * @return boolean + */ + private boolean getShowLocationBar() { + return this.showLocationBar; + } + + /** + * Display a new browser with the specified URL. + * + * @param url The url to load. + * @param jsonObject + */ + public String showWebPage(final String url, HashMap features) { + // Determine if we should hide the location bar. + showLocationBar = true; + openWindowHidden = false; + if (features != null) { + Boolean show = features.get(LOCATION); + if (show != null) { + showLocationBar = show.booleanValue(); + } + Boolean hidden = features.get(HIDDEN); + if(hidden != null) { + openWindowHidden = hidden.booleanValue(); + } + } + + final CordovaWebView thatWebView = this.webView; + + // Create dialog in new thread + Runnable runnable = new Runnable() { + /** + * Convert our DIP units to Pixels + * + * @return int + */ + private int dpToPixels(int dipValue) { + int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, + (float) dipValue, + cordova.getActivity().getResources().getDisplayMetrics() + ); + + return value; + } + + public void run() { + // Let's create the main dialog + dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar); + dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog; + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + public void onDismiss(DialogInterface dialog) { + try { + JSONObject obj = new JSONObject(); + obj.put("type", EXIT_EVENT); + + sendUpdate(obj, false); + } catch (JSONException e) { + Log.d(LOG_TAG, "Should never happen"); + } + } + }); + + // Main container layout + LinearLayout main = new LinearLayout(cordova.getActivity()); + main.setOrientation(LinearLayout.VERTICAL); + + // Toolbar layout + RelativeLayout toolbar = new RelativeLayout(cordova.getActivity()); + toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44))); + toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2)); + toolbar.setHorizontalGravity(Gravity.LEFT); + toolbar.setVerticalGravity(Gravity.TOP); + + // Action Button Container layout + RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity()); + actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + actionButtonContainer.setHorizontalGravity(Gravity.LEFT); + actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL); + actionButtonContainer.setId(1); + + // Back button + Button back = new Button(cordova.getActivity()); + RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT); + back.setLayoutParams(backLayoutParams); + back.setContentDescription("Back Button"); + back.setId(2); + back.setText("<"); + back.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + goBack(); + } + }); + + // Forward button + Button forward = new Button(cordova.getActivity()); + RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2); + forward.setLayoutParams(forwardLayoutParams); + forward.setContentDescription("Forward Button"); + forward.setId(3); + forward.setText(">"); + forward.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + goForward(); + } + }); + + // Edit Text Box + edittext = new EditText(cordova.getActivity()); + RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1); + textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5); + edittext.setLayoutParams(textLayoutParams); + edittext.setId(4); + edittext.setSingleLine(true); + edittext.setText(url); + edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI); + edittext.setImeOptions(EditorInfo.IME_ACTION_GO); + edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE + edittext.setOnKeyListener(new View.OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + // If the event is a key-down event on the "enter" button + if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { + navigate(edittext.getText().toString()); + return true; + } + return false; + } + }); + + // Close button + Button close = new Button(cordova.getActivity()); + RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + close.setLayoutParams(closeLayoutParams); + forward.setContentDescription("Close Button"); + close.setId(5); + close.setText(buttonLabel); + close.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + closeDialog(); + } + }); + + // WebView + inAppWebView = new WebView(cordova.getActivity()); + inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView)); + WebViewClient client = new InAppBrowserClient(thatWebView, edittext); + inAppWebView.setWebViewClient(client); + WebSettings settings = inAppWebView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setJavaScriptCanOpenWindowsAutomatically(true); + settings.setBuiltInZoomControls(true); + settings.setPluginState(android.webkit.WebSettings.PluginState.ON); + + //Toggle whether this is enabled or not! + Bundle appSettings = cordova.getActivity().getIntent().getExtras(); + boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true); + if(enableDatabase) + { + String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath(); + settings.setDatabasePath(databasePath); + settings.setDatabaseEnabled(true); + } + settings.setDomStorageEnabled(true); + + inAppWebView.loadUrl(url); + inAppWebView.setId(6); + inAppWebView.getSettings().setLoadWithOverviewMode(true); + inAppWebView.getSettings().setUseWideViewPort(true); + inAppWebView.requestFocus(); + inAppWebView.requestFocusFromTouch(); + + // Add the back and forward buttons to our action button container layout + actionButtonContainer.addView(back); + actionButtonContainer.addView(forward); + + // Add the views to our toolbar + toolbar.addView(actionButtonContainer); + toolbar.addView(edittext); + toolbar.addView(close); + + // Don't add the toolbar if its been disabled + if (getShowLocationBar()) { + // Add our toolbar to our main view/layout + main.addView(toolbar); + } + + // Add our webview to our main view/layout + main.addView(inAppWebView); + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); + lp.copyFrom(dialog.getWindow().getAttributes()); + lp.width = WindowManager.LayoutParams.MATCH_PARENT; + lp.height = WindowManager.LayoutParams.MATCH_PARENT; + + dialog.setContentView(main); + dialog.show(); + dialog.getWindow().setAttributes(lp); + // the goal of openhidden is to load the url and not display it + // Show() needs to be called to cause the URL to be loaded + if(openWindowHidden) { + dialog.hide(); + } + } + }; + this.cordova.getActivity().runOnUiThread(runnable); + return ""; + } + + /** + * Create a new plugin success result and send it back to JavaScript + * + * @param obj a JSONObject contain event payload information + */ + private void sendUpdate(JSONObject obj, boolean keepCallback) { + sendUpdate(obj, keepCallback, PluginResult.Status.OK); + } + + /** + * Create a new plugin result and send it back to JavaScript + * + * @param obj a JSONObject contain event payload information + * @param status the status code to return to the JavaScript environment + */ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) { + PluginResult result = new PluginResult(status, obj); + result.setKeepCallback(keepCallback); + this.callbackContext.sendPluginResult(result); + } + + public class InAppChromeClient extends WebChromeClient { + + private CordovaWebView webView; + + public InAppChromeClient(CordovaWebView webView) { + super(); + this.webView = webView; + } + /** + * Handle database quota exceeded notification. + * + * @param url + * @param databaseIdentifier + * @param currentQuota + * @param estimatedSize + * @param totalUsedQuota + * @param quotaUpdater + */ + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, + long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) + { + LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); + + if (estimatedSize < MAX_QUOTA) + { + //increase for 1Mb + long newQuota = estimatedSize; + LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota); + quotaUpdater.updateQuota(newQuota); + } + else + { + // Set the quota to whatever it is and force an error + // TODO: get docs on how to handle this properly + quotaUpdater.updateQuota(currentQuota); + } + } + + /** + * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. + * + * @param origin + * @param callback + */ + @Override + public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { + super.onGeolocationPermissionsShowPrompt(origin, callback); + callback.invoke(origin, true, false); + } + + /** + * Tell the client to display a prompt dialog to the user. + * If the client returns true, WebView will assume that the client will + * handle the prompt dialog and call the appropriate JsPromptResult method. + * + * The prompt bridge provided for the InAppBrowser is capable of executing any + * oustanding callback belonging to the InAppBrowser plugin. Care has been + * taken that other callbacks cannot be triggered, and that no other code + * execution is possible. + * + * To trigger the bridge, the prompt default value should be of the form: + * + * gap-iab:// + * + * where is the string id of the callback to trigger (something + * like "InAppBrowser0123456789") + * + * If present, the prompt message is expected to be a JSON-encoded value to + * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid. + * + * @param view + * @param url + * @param message + * @param defaultValue + * @param result + */ + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { + // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute. + if (defaultValue != null && defaultValue.startsWith("gap-iab://")) { + PluginResult scriptResult; + String scriptCallbackId = defaultValue.substring(10); + if (scriptCallbackId.startsWith("InAppBrowser")) { + if(message == null || message.length() == 0) { + scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray()); + } else { + try { + scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message)); + } catch(JSONException e) { + scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()); + } + } + this.webView.sendPluginResult(scriptResult, scriptCallbackId); + result.confirm(""); + return true; + } + } + return false; + } + + } + + /** + * The webview client receives notifications about appView + */ + public class InAppBrowserClient extends WebViewClient { + EditText edittext; + CordovaWebView webView; + + /** + * Constructor. + * + * @param mContext + * @param edittext + */ + public InAppBrowserClient(CordovaWebView webView, EditText mEditText) { + this.webView = webView; + this.edittext = mEditText; + } + + /** + * Notify the host application that a page has started loading. + * + * @param view The webview initiating the callback. + * @param url The url of the page. + */ + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + String newloc = ""; + if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) { + newloc = url; + } + // If dialing phone (tel:5551212) + else if (url.startsWith(WebView.SCHEME_TEL)) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL); + intent.setData(Uri.parse(url)); + cordova.getActivity().startActivity(intent); + } catch (android.content.ActivityNotFoundException e) { + LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); + } + } + + else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + cordova.getActivity().startActivity(intent); + } catch (android.content.ActivityNotFoundException e) { + LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString()); + } + } + // If sms:5551212?body=This is the message + else if (url.startsWith("sms:")) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + + // Get address + String address = null; + int parmIndex = url.indexOf('?'); + if (parmIndex == -1) { + address = url.substring(4); + } + else { + address = url.substring(4, parmIndex); + + // If body, then set sms body + Uri uri = Uri.parse(url); + String query = uri.getQuery(); + if (query != null) { + if (query.startsWith("body=")) { + intent.putExtra("sms_body", query.substring(5)); + } + } + } + intent.setData(Uri.parse("sms:" + address)); + intent.putExtra("address", address); + intent.setType("vnd.android-dir/mms-sms"); + cordova.getActivity().startActivity(intent); + } catch (android.content.ActivityNotFoundException e) { + LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString()); + } + } + else { + newloc = "http://" + url; + } + + if (!newloc.equals(edittext.getText().toString())) { + edittext.setText(newloc); + } + + try { + JSONObject obj = new JSONObject(); + obj.put("type", LOAD_START_EVENT); + obj.put("url", newloc); + + sendUpdate(obj, true); + } catch (JSONException ex) { + Log.d(LOG_TAG, "Should never happen"); + } + } + + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + try { + JSONObject obj = new JSONObject(); + obj.put("type", LOAD_STOP_EVENT); + obj.put("url", url); + + sendUpdate(obj, true); + } catch (JSONException ex) { + Log.d(LOG_TAG, "Should never happen"); + } + } + + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + + try { + JSONObject obj = new JSONObject(); + obj.put("type", LOAD_ERROR_EVENT); + obj.put("url", failingUrl); + obj.put("code", errorCode); + obj.put("message", description); + + sendUpdate(obj, true, PluginResult.Status.ERROR); + } catch (JSONException ex) { + Log.d(LOG_TAG, "Should never happen"); + } + + } + } +} diff --git a/iOS/InAppBrowser/src/blackberry10/README.md b/iOS/InAppBrowser/src/blackberry10/README.md new file mode 100644 index 00000000..0b167897 --- /dev/null +++ b/iOS/InAppBrowser/src/blackberry10/README.md @@ -0,0 +1,25 @@ +# BlackBerry 10 In-App-Browser Plugin + +The in app browser functionality is entirely contained within common js. There is no native implementation required. +To install this plugin, follow the [Command-line Interface Guide](http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface). + +If you are not using the Cordova Command-line Interface, follow [Using Plugman to Manage Plugins](http://cordova.apache.org/docs/en/edge/guide_plugin_ref_plugman.md.html). +./cordova-plugin-battery-status/README.md +./cordova-plugin-camera/README.md +./cordova-plugin-console/README.md +./cordova-plugin-contacts/README.md +./cordova-plugin-device/README.md +./cordova-plugin-device-motion/README.md +./cordova-plugin-device-orientation/README.md +./cordova-plugin-device-orientation/src/blackberry10/README.md +./cordova-plugin-file/README.md +./cordova-plugin-file-transfer/README.md +./cordova-plugin-geolocation/README.md +./cordova-plugin-globalization/README.md +./cordova-plugin-inappbrowser/README.md +./cordova-plugin-inappbrowser/src/blackberry10/README.md +./cordova-plugin-media/README.md +./cordova-plugin-media-capture/README.md +./cordova-plugin-network-information/README.md +./cordova-plugin-splashscreen/README.md +./cordova-plugin-vibration/README.md diff --git a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h new file mode 100644 index 00000000..b79e2e60 --- /dev/null +++ b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h @@ -0,0 +1,98 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import +#import +#import + +@class CDVInAppBrowserViewController; + +@interface CDVInAppBrowser : CDVPlugin { + BOOL _injectedIframeBridge; +} + +@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController; +@property (nonatomic, copy) NSString* callbackId; + +- (void)open:(CDVInvokedUrlCommand*)command; +- (void)close:(CDVInvokedUrlCommand*)command; +- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; +- (void)show:(CDVInvokedUrlCommand*)command; + +@end + +@interface CDVInAppBrowserViewController : UIViewController { +@private + NSString* _userAgent; + NSString* _prevUserAgent; + NSInteger _userAgentLockToken; + CDVWebViewDelegate* _webViewDelegate; +} + +@property (nonatomic, strong) IBOutlet UIWebView* webView; +@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton; +@property (nonatomic, strong) IBOutlet UILabel* addressLabel; +@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton; +@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton; +@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner; +@property (nonatomic, strong) IBOutlet UIToolbar* toolbar; + +@property (nonatomic, weak) id orientationDelegate; +@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate; +@property (nonatomic) NSURL* currentURL; + +- (void)close; +- (void)navigateTo:(NSURL*)url; +- (void)showLocationBar:(BOOL)show; +- (void)showToolBar:(BOOL)show; + +/* cemerson */ // added buttonBGColor parameter +- (void)setCloseButtonTitle:(NSString*)title buttonBGColor:(UIColor*)buttonBGColor; + +- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent; + +@end + +@interface CDVInAppBrowserOptions : NSObject {} + +@property (nonatomic, assign) BOOL location; +@property (nonatomic, assign) BOOL toolbar; +@property (nonatomic, copy) NSString* closebuttoncaption; + +@property (nonatomic, copy) NSString* presentationstyle; +@property (nonatomic, copy) NSString* transitionstyle; + +@property (nonatomic, assign) BOOL enableviewportscale; +@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction; +@property (nonatomic, assign) BOOL allowinlinemediaplayback; +@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction; +@property (nonatomic, assign) BOOL suppressesincrementalrendering; +@property (nonatomic, assign) BOOL hidden; + +/* cemerson */ @property (nonatomic, assign) CGFloat vw; +/* cemerson */ @property (nonatomic, assign) CGFloat vh; +/* cemerson */ @property (nonatomic, assign) CGFloat vx; +/* cemerson */ @property (nonatomic, assign) CGFloat vy; +/* cemerson */ @property (nonatomic, assign) NSString* buttoncolorbg; + + ++ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; + +@end \ No newline at end of file diff --git a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m new file mode 100644 index 00000000..d1a5aa4d --- /dev/null +++ b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m @@ -0,0 +1,958 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVInAppBrowser.h" +#import +#import +#import + +#define kInAppBrowserTargetSelf @"_self" +#define kInAppBrowserTargetSystem @"_system" +#define kInAppBrowserTargetBlank @"_blank" + +#define TOOLBAR_HEIGHT 44.0 +#define LOCATIONBAR_HEIGHT 21.0 +#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT)) +#define BUTTON_BACKGROUND_COLOR @"#448EE3" +#define CLOSE_BUTTON_LABEL @"Done" + +#pragma mark CDVInAppBrowser + +CDVInAppBrowserViewController *vc; +CDVInAppBrowserViewController *iabvc; + +BOOL WINDOWED_MODE_SPECIFIED = NO; + +@implementation CDVInAppBrowser + +- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView +{ + self = [super initWithWebView:theWebView]; + if (self != nil) { + // your initialization here + } + + return self; +} + +- (void)onReset +{ + [self close:nil]; +} + +- (void)close:(CDVInvokedUrlCommand*)command +{ + if (self.inAppBrowserViewController != nil) { + [self.inAppBrowserViewController close]; + self.inAppBrowserViewController = nil; + } + + self.callbackId = nil; +} + +- (BOOL) isSystemUrl:(NSURL*)url +{ + if ([[url host] isEqualToString:@"itunes.apple.com"]) { + return YES; + } + + return NO; +} + +- (void)open:(CDVInvokedUrlCommand*)command +{ + CDVPluginResult* pluginResult; + + NSString* url = [command argumentAtIndex:0]; + NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; + NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; + + if ( + ([options rangeOfString:@"vx"].location == NSNotFound) && + ([options rangeOfString:@"vy"].location == NSNotFound) && + ([options rangeOfString:@"vw"].location == NSNotFound) && + ([options rangeOfString:@"vh"].location == NSNotFound) + ){ + WINDOWED_MODE_SPECIFIED = NO; + }else{ + WINDOWED_MODE_SPECIFIED = YES; + } + + NSLog(@"PLUGIN: InAppBrowser.open()...{WINDOWED_MODE_SPECIFIED:%i} [CDVInAppBrowser.m]", WINDOWED_MODE_SPECIFIED); + + self.callbackId = command.callbackId; + + if (url != nil) { + NSURL* baseUrl = [self.webView.request URL]; + NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; + + if ([self isSystemUrl:absoluteUrl]) { + target = kInAppBrowserTargetSystem; + } + + if ([target isEqualToString:kInAppBrowserTargetSelf]) { + [self openInCordovaWebView:absoluteUrl withOptions:options]; + } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { + [self openInSystem:absoluteUrl]; + } else { // _blank or anything else + [self openInInAppBrowser:absoluteUrl withOptions:options]; + } + + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"]; + } + + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +} + +- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options +{ + + if (self.inAppBrowserViewController == nil) { + NSString* originalUA = [CDVUserAgentUtil originalUserAgent]; + self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]]; + self.inAppBrowserViewController.navigationDelegate = self; + + if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { + self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; + } + } + + /* cemerson */ // set pointer to this viewcontroller for later use + /* cemerson */iabvc = self.inAppBrowserViewController; + + CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; + [self.inAppBrowserViewController showLocationBar:browserOptions.location]; + [self.inAppBrowserViewController showToolBar:browserOptions.toolbar]; + + /* cemerson */ // abstract this out into a standalone method? + NSString *stringColor = browserOptions.buttoncolorbg; + NSUInteger red, green, blue; + sscanf([stringColor UTF8String], "#%02X%02X%02X", &red, &green, &blue); + UIColor *buttonbg = [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1]; + + /* cemerson */ // for now calling setCloseButtonTitle() either way to make sure button gets colored + if (browserOptions.closebuttoncaption != nil) { + [self.inAppBrowserViewController setCloseButtonTitle:browserOptions.closebuttoncaption buttonBGColor:buttonbg]; + }else{ + [self.inAppBrowserViewController setCloseButtonTitle:@"Done" buttonBGColor:buttonbg]; + } + + // Set Presentation Style + UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default + if (browserOptions.presentationstyle != nil) { + if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"pagesheet"]) { + presentationStyle = UIModalPresentationPageSheet; + } else if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"formsheet"]) { + presentationStyle = UIModalPresentationFormSheet; + } + } + // NSLog(@"PLUGIN: InAppBrowser.presentationStyle = %@",browserOptions.presentationstyle); + self.inAppBrowserViewController.modalPresentationStyle = presentationStyle; + + // Set Transition Style + UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default + if (browserOptions.transitionstyle != nil) { + if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"fliphorizontal"]) { + transitionStyle = UIModalTransitionStyleFlipHorizontal; + } else if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"crossdissolve"]) { + transitionStyle = UIModalTransitionStyleCrossDissolve; + } + } + self.inAppBrowserViewController.modalTransitionStyle = transitionStyle; + + // UIWebView options + self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale; + self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction; + self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback; + if (IsAtLeastiOSVersion(@"6.0")) { + self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction; + self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering; + } + + if (! browserOptions.hidden) { + if (self.viewController.modalViewController != self.inAppBrowserViewController) { + + if(WINDOWED_MODE_SPECIFIED){ + //NSLog(@"PLUGIN: InAppBrowser: addSubView Mode"); + + /*cemerson*/ // NEW addSubView APPROACH + /*cemerson*/ vc = (CDVInAppBrowserViewController*)[ super viewController ]; + CGRect vcBoundsInit = CGRectMake(browserOptions.vx, + browserOptions.vh, + browserOptions.vw, + browserOptions.vh); + /*cemerson*/ CGRect vcBounds = CGRectMake(browserOptions.vx, + browserOptions.vy, + browserOptions.vw, + browserOptions.vh); + + /*cemerson*/ // if formsheet mode we dont mess with the frame + /*cemerson*/ iabvc.view.frame = vcBoundsInit; + + /*cemerson*/ iabvc.webView.scalesPageToFit = YES; + /*cemerson*/ [iabvc viewWillAppear:NO]; + /*cemerson*/ [vc.self.view addSubview:iabvc.view]; + + /*cemerson*/ // view animation + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.25]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; + + /*cemerson*/ iabvc.view.frame = vcBounds; + /*cemerson*/ [UIView commitAnimations]; + }else{ + /*cemerson*/ // OLD presentModalViewController APPROACH + //NSLog(@"PLUGIN: InAppBrowser: presentModalViewController Mode"); + [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; + } + + + } + } + [self.inAppBrowserViewController navigateTo:url]; +} + +//- (BOOL)webView:(UIWebView*)theWebView should +- (UIColor*)getUIColorFromHTMLHexColorString: (NSString*)htmlColorString{ + NSString *stringColor = htmlColorString; + NSUInteger red, green, blue; + sscanf([stringColor UTF8String], "#%02X%02X%02X", &red, &green, &blue); + + UIColor *buttonbg = [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1]; + + return buttonbg; + +} + +- (void)show:(CDVInvokedUrlCommand*)command +{ + if ([self.inAppBrowserViewController isViewLoaded] && self.inAppBrowserViewController.view.window) + return; + [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; +} + +- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options +{ + if ([self.commandDelegate URLIsWhitelisted:url]) { + NSURLRequest* request = [NSURLRequest requestWithURL:url]; + [self.webView loadRequest:request]; + } else { // this assumes the InAppBrowser can be excepted from the white-list + [self openInInAppBrowser:url withOptions:options]; + } +} + +- (void)openInSystem:(NSURL*)url +{ + if ([[UIApplication sharedApplication] canOpenURL:url]) { + [[UIApplication sharedApplication] openURL:url]; + } else { // handle any custom schemes to plugins + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + } +} + +// This is a helper method for the inject{Script|Style}{Code|File} API calls, which +// provides a consistent method for injecting JavaScript code into the document. +// +// If a wrapper string is supplied, then the source string will be JSON-encoded (adding +// quotes) and wrapped using string formatting. (The wrapper string should have a single +// '%@' marker). +// +// If no wrapper is supplied, then the source string is executed directly. + +- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper +{ + if (!_injectedIframeBridge) { + _injectedIframeBridge = YES; + // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController + [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"]; + } + + if (jsWrapper != nil) { + NSString* sourceArrayString = [@[source] JSONString]; + if (sourceArrayString) { + NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)]; + NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString]; + [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject]; + } + } else { + [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source]; + } +} + +- (void)injectScriptCode:(CDVInvokedUrlCommand*)command +{ + NSString* jsWrapper = nil; + + if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { + jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId]; + } + [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; +} + +- (void)injectScriptFile:(CDVInvokedUrlCommand*)command +{ + NSString* jsWrapper; + + if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { + jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; + } else { + jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"; + } + [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; +} + +- (void)injectStyleCode:(CDVInvokedUrlCommand*)command +{ + NSString* jsWrapper; + + if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { + jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; + } else { + jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"; + } + [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; +} + +- (void)injectStyleFile:(CDVInvokedUrlCommand*)command +{ + NSString* jsWrapper; + + if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { + jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; + } else { + jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"; + } + [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; +} + +/** + * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging + * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no + * other code execution is possible. + * + * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form: + * + * gap-iab:/// + * + * where is the string id of the callback to trigger (something like "InAppBrowser0123456789") + * + * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded + * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION + * is returned if the JSON is invalid. + */ +- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + NSURL* url = request.URL; + BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; + + // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute, + // and the path, if present, should be a JSON-encoded value to pass to the callback. + if ([[url scheme] isEqualToString:@"gap-iab"]) { + NSString* scriptCallbackId = [url host]; + CDVPluginResult* pluginResult = nil; + + if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) { + NSString* scriptResult = [url path]; + NSError* __autoreleasing error = nil; + + // The message should be a JSON-encoded array of the result of the script which executed. + if ((scriptResult != nil) && ([scriptResult length] > 1)) { + scriptResult = [scriptResult substringFromIndex:1]; + NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION]; + } + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]]; + } + [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId]; + return NO; + } + } else if ((self.callbackId != nil) && isTopLevelNavigation) { + // Send a loadstart event for each top-level navigation (includes redirects). + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK + messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}]; + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; + } + + return YES; +} + +- (void)webViewDidStartLoad:(UIWebView*)theWebView +{ + _injectedIframeBridge = NO; +} + +- (void)webViewDidFinishLoad:(UIWebView*)theWebView +{ + if (self.callbackId != nil) { + + /* cemerson */ // if you CLOSE the web view before it finishes loading sometimes it throws and error + if(self.inAppBrowserViewController.currentURL.absoluteString == nil){ + NSLog(@" webViewDidFinishLoad() WARNING: *absoluteString is nil! Did you close the web view before it finished loading?"); + return; + } + + // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected). + NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; + + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK + messageAsDictionary:@{@"type":@"loadstop", @"url":url}]; + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; + } +} + +- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error +{ + if (self.callbackId != nil) { + NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR + messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}]; + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; + } +} + +- (void)browserExit +{ + if (self.callbackId != nil) { + + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK + messageAsDictionary:@{@"type":@"exit"}]; + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; + + // NSLog(@"PLUGIN: InAppBrowser.browserExit(pluginResult: %@)... [CDVInAppBrowser.m]", pluginResult); + + } + // Don't recycle the ViewController since it may be consuming a lot of memory. + // Also - this is required for the PDF/User-Agent bug work-around. + self.inAppBrowserViewController = nil; +} + +@end + +#pragma mark CDVInAppBrowserViewController + +@implementation CDVInAppBrowserViewController + +@synthesize currentURL; + +- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent +{ + self = [super init]; + + if (self != nil) { + _userAgent = userAgent; + _prevUserAgent = prevUserAgent; + _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; + [self createViews]; + } + + return self; +} + +- (void)createViews +{ + // We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included + + /*cemerson*/ // inherit frame of parent view + CGRect webViewBounds = CGRectMake(0, + 0, + self.view.frame.size.width, + self.view.frame.size.height); + + webViewBounds.size.height -= FOOTER_HEIGHT; + + self.webView.scalesPageToFit = YES; + + self.webView = [[UIWebView alloc] initWithFrame:webViewBounds]; + + [self.view addSubview:self.webView]; + [self.view sendSubviewToBack:self.webView]; + + self.webView.delegate = _webViewDelegate; + self.webView.backgroundColor = [UIColor clearColor]; + + self.webView.clearsContextBeforeDrawing = YES; + self.webView.clipsToBounds = YES; + self.webView.contentMode = UIViewContentModeScaleToFill; + self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); + self.webView.multipleTouchEnabled = YES; + /* cemerson */ // set webView to transparent so the transition animation is actually covering up the app + /* cemerson */ self.webView.opaque = NO; + self.webView.scalesPageToFit = NO; + self.webView.userInteractionEnabled = YES; + + self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + self.spinner.alpha = 1.000; + self.spinner.autoresizesSubviews = YES; + self.spinner.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; + self.spinner.clearsContextBeforeDrawing = NO; + self.spinner.clipsToBounds = NO; + self.spinner.contentMode = UIViewContentModeScaleToFill; + self.spinner.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); + self.spinner.frame = CGRectMake(454.0, 231.0, 20.0, 20.0); + self.spinner.hidden = YES; + self.spinner.hidesWhenStopped = YES; + self.spinner.multipleTouchEnabled = NO; + self.spinner.opaque = NO; + self.spinner.userInteractionEnabled = NO; + [self.spinner stopAnimating]; + + self.closeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)]; + self.closeButton.enabled = YES; + + UIBarButtonItem* flexibleSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + + UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + fixedSpaceButton.width = 20; + + self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, (self.view.bounds.size.height - TOOLBAR_HEIGHT), self.view.bounds.size.width, TOOLBAR_HEIGHT)]; + self.toolbar.alpha = 1.000; + self.toolbar.autoresizesSubviews = YES; + self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; + self.toolbar.barStyle = UIBarStyleBlackOpaque; + self.toolbar.clearsContextBeforeDrawing = NO; + self.toolbar.clipsToBounds = NO; + self.toolbar.contentMode = UIViewContentModeScaleToFill; + self.toolbar.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); + self.toolbar.hidden = NO; + self.toolbar.multipleTouchEnabled = NO; + self.toolbar.opaque = NO; + self.toolbar.userInteractionEnabled = YES; + + CGFloat labelInset = 5.0; + self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, (self.view.bounds.size.height - FOOTER_HEIGHT), self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)]; + self.addressLabel.adjustsFontSizeToFitWidth = NO; + self.addressLabel.alpha = 1.000; + self.addressLabel.autoresizesSubviews = YES; + self.addressLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; + self.addressLabel.backgroundColor = [UIColor clearColor]; + self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; + self.addressLabel.clearsContextBeforeDrawing = YES; + self.addressLabel.clipsToBounds = YES; + self.addressLabel.contentMode = UIViewContentModeScaleToFill; + self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); + self.addressLabel.enabled = YES; + self.addressLabel.hidden = NO; + self.addressLabel.lineBreakMode = UILineBreakModeTailTruncation; + self.addressLabel.minimumFontSize = 10.000; + self.addressLabel.multipleTouchEnabled = NO; + self.addressLabel.numberOfLines = 1; + self.addressLabel.opaque = NO; + self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0); + self.addressLabel.text = @"Loading..."; + self.addressLabel.textAlignment = UITextAlignmentLeft; + self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000]; + self.addressLabel.userInteractionEnabled = NO; + + NSString* frontArrowString = @"►"; // create arrow from Unicode char + self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)]; + self.forwardButton.enabled = YES; + self.forwardButton.imageInsets = UIEdgeInsetsZero; + + NSString* backArrowString = @"◄"; // create arrow from Unicode char + self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)]; + self.backButton.enabled = YES; + self.backButton.imageInsets = UIEdgeInsetsZero; + + [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton, self.backButton, fixedSpaceButton, self.forwardButton]]; + + /* cemerson */ self.view.backgroundColor = [UIColor grayColor]; + /* cemerson */ self.view.opaque = YES; + + [self.view addSubview:self.toolbar]; + [self.view addSubview:self.addressLabel]; + [self.view addSubview:self.spinner]; +} + +/* cemerson */ // added buttonBGColor parameter +- (void)setCloseButtonTitle:(NSString*)title buttonBGColor:(UIColor*)buttonBGColor +{ + //NSLog(@"setCloseButtonTitle() color:%@", buttonBGColor); + // the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically + // but, if you want to set this yourself, knock yourself out (we can't set the title for a system Done button, so we have to create a new one) + self.closeButton = nil; + self.closeButton = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStyleBordered target:self action:@selector(close)]; + self.closeButton.enabled = YES; + + self.closeButton.tintColor = buttonBGColor; + + NSMutableArray* items = [self.toolbar.items mutableCopy]; + [items replaceObjectAtIndex:0 withObject:self.closeButton]; + [self.toolbar setItems:items]; +} + +- (void)showLocationBar:(BOOL)show +{ + CGRect locationbarFrame = self.addressLabel.frame; + + BOOL toolbarVisible = !self.toolbar.hidden; + + // prevent double show/hide + if (show == !(self.addressLabel.hidden)) { + return; + } + + if (show) { + self.addressLabel.hidden = NO; + + if (toolbarVisible) { + // toolBar at the bottom, leave as is + // put locationBar on top of the toolBar + + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= FOOTER_HEIGHT; + self.webView.frame = webViewBounds; + + locationbarFrame.origin.y = webViewBounds.size.height; + self.addressLabel.frame = locationbarFrame; + } else { + // no toolBar, so put locationBar at the bottom + + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= LOCATIONBAR_HEIGHT; + self.webView.frame = webViewBounds; + + locationbarFrame.origin.y = webViewBounds.size.height; + self.addressLabel.frame = locationbarFrame; + } + } else { + self.addressLabel.hidden = YES; + + if (toolbarVisible) { + // locationBar is on top of toolBar, hide locationBar + + // webView take up whole height less toolBar height + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= TOOLBAR_HEIGHT; + self.webView.frame = webViewBounds; + } else { + // no toolBar, expand webView to screen dimensions + + CGRect webViewBounds = self.view.bounds; + self.webView.frame = webViewBounds; + } + } +} + +- (void)showToolBar:(BOOL)show +{ + CGRect toolbarFrame = self.toolbar.frame; + CGRect locationbarFrame = self.addressLabel.frame; + + BOOL locationbarVisible = !self.addressLabel.hidden; + + // prevent double show/hide + if (show == !(self.toolbar.hidden)) { + return; + } + + if (show) { + self.toolbar.hidden = NO; + + if (locationbarVisible) { + // locationBar at the bottom, move locationBar up + // put toolBar at the bottom + + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= FOOTER_HEIGHT; + self.webView.frame = webViewBounds; + + locationbarFrame.origin.y = webViewBounds.size.height; + self.addressLabel.frame = locationbarFrame; + + toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT); + self.toolbar.frame = toolbarFrame; + } else { + // no locationBar, so put toolBar at the bottom + + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= TOOLBAR_HEIGHT; + self.webView.frame = webViewBounds; + + toolbarFrame.origin.y = webViewBounds.size.height; + self.toolbar.frame = toolbarFrame; + } + } else { + self.toolbar.hidden = YES; + + if (locationbarVisible) { + // locationBar is on top of toolBar, hide toolBar + // put locationBar at the bottom + + // webView take up whole height less locationBar height + CGRect webViewBounds = self.view.bounds; + webViewBounds.size.height -= LOCATIONBAR_HEIGHT; + self.webView.frame = webViewBounds; + + // move locationBar down + locationbarFrame.origin.y = webViewBounds.size.height; + self.addressLabel.frame = locationbarFrame; + } else { + // no locationBar, expand webView to screen dimensions + + CGRect webViewBounds = self.view.bounds; + self.webView.frame = webViewBounds; + } + } +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; +} + +- (void)viewDidUnload +{ + [self.webView loadHTMLString:nil baseURL:nil]; + [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; + [super viewDidUnload]; +} + +- (void)close +{ + [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; + + /* cemerson */ // TODO: prevent throwing error when closing before web page finished loading (??) + + /* cemerson */ // OLD close actions + if ([self respondsToSelector:@selector(presentingViewController)]) { + [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; + } else { + [[self parentViewController] dismissModalViewControllerAnimated:YES]; + } + + self.currentURL = nil; + + if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) { + [self.navigationDelegate browserExit]; + } + + /* cemerson */ // if windowsModeSpecified we assume addSubView was used + if(WINDOWED_MODE_SPECIFIED){ + [iabvc.view removeFromSuperview]; + } + + NSLog(@"PLUGIN: InAppBrowser.close()... [CDVInAppBrowser.m]"); + + +} + +- (void)navigateTo:(NSURL*)url +{ + NSURLRequest* request = [NSURLRequest requestWithURL:url]; + + if (_userAgentLockToken != 0) { + [self.webView loadRequest:request]; + } else { + [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { + _userAgentLockToken = lockToken; + [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; + [self.webView loadRequest:request]; + }]; + } +} + +- (void)goBack:(id)sender +{ + [self.webView goBack]; +} + +- (void)goForward:(id)sender +{ + [self.webView goForward]; +} + +#pragma mark UIWebViewDelegate + +- (void)webViewDidStartLoad:(UIWebView*)theWebView +{ + // loading url, start spinner, update back/forward + + self.addressLabel.text = @"Loading..."; + self.backButton.enabled = theWebView.canGoBack; + self.forwardButton.enabled = theWebView.canGoForward; + + [self.spinner startAnimating]; + + return [self.navigationDelegate webViewDidStartLoad:theWebView]; +} + +- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; + + if (isTopLevelNavigation) { + self.currentURL = request.URL; + } + return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType]; +} + +- (void)webViewDidFinishLoad:(UIWebView*)theWebView +{ + // update url, stop spinner, update back/forward + + self.addressLabel.text = [self.currentURL absoluteString]; + self.backButton.enabled = theWebView.canGoBack; + self.forwardButton.enabled = theWebView.canGoForward; + + [self.spinner stopAnimating]; + + // Work around a bug where the first time a PDF is opened, all UIWebViews + // reload their User-Agent from NSUserDefaults. + // This work-around makes the following assumptions: + // 1. The app has only a single Cordova Webview. If not, then the app should + // take it upon themselves to load a PDF in the background as a part of + // their start-up flow. + // 2. That the PDF does not require any additional network requests. We change + // the user-agent here back to that of the CDVViewController, so requests + // from it must pass through its white-list. This *does* break PDFs that + // contain links to other remote PDF/websites. + // More info at https://issues.apache.org/jira/browse/CB-2225 + BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]]; + if (isPDF) { + [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; + } + + [self.navigationDelegate webViewDidFinishLoad:theWebView]; +} + +- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error +{ + // log fail message, stop spinner, update back/forward + NSLog(@"webView:didFailLoadWithError - %@", [error localizedDescription]); + + self.backButton.enabled = theWebView.canGoBack; + self.forwardButton.enabled = theWebView.canGoForward; + [self.spinner stopAnimating]; + + self.addressLabel.text = @"Load Error"; + + [self.navigationDelegate webView:theWebView didFailLoadWithError:error]; +} + +#pragma mark CDVScreenOrientationDelegate + +- (BOOL)shouldAutorotate +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { + return [self.orientationDelegate shouldAutorotate]; + } + return YES; +} + +- (NSUInteger)supportedInterfaceOrientations +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { + return [self.orientationDelegate supportedInterfaceOrientations]; + } + + return 1 << UIInterfaceOrientationPortrait; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { + return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; + } + + return YES; +} + +@end + +@implementation CDVInAppBrowserOptions + +- (id)init +{ + if (self = [super init]) { + // default values + + self.location = YES; + self.toolbar = YES; + self.enableviewportscale = NO; + self.mediaplaybackrequiresuseraction = NO; + self.allowinlinemediaplayback = NO; + self.keyboarddisplayrequiresuseraction = YES; + self.suppressesincrementalrendering = NO; + self.hidden = NO; + + /* cemerson */ self.closebuttoncaption = CLOSE_BUTTON_LABEL; + /* cemerson */ self.vw = iabvc.view.frame.size.width; + /* cemerson */ self.vh = iabvc.view.frame.size.height; // - (FOOTER_HEIGHT); + /* cemerson */ self.vx = iabvc.view.frame.origin.x; + /* cemerson */ self.vy = 0; + /* cemerson */ self.buttoncolorbg = BUTTON_BACKGROUND_COLOR; + } + + return self; +} + ++ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options +{ + CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init]; + + // NOTE: this parsing does not handle quotes within values + NSArray* pairs = [options componentsSeparatedByString:@","]; + + // parse keys and values, set the properties + for (NSString* pair in pairs) { + NSArray* keyvalue = [pair componentsSeparatedByString:@"="]; + + if ([keyvalue count] == 2) { + NSString* key = [[keyvalue objectAtIndex:0] lowercaseString]; + NSString* value = [keyvalue objectAtIndex:1]; + NSString* value_lc = [value lowercaseString]; + + BOOL isBoolean = [value_lc isEqualToString:@"yes"] || [value_lc isEqualToString:@"no"]; + NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; + [numberFormatter setAllowsFloats:YES]; + BOOL isNumber = [numberFormatter numberFromString:value_lc] != nil; + + // set the property according to the key name + if ([obj respondsToSelector:NSSelectorFromString(key)]) { + //NSLog(@"....parsing browserOption[%@] ...", key); + if (isNumber) { + [obj setValue:[numberFormatter numberFromString:value_lc] forKey:key]; + } else if (isBoolean) { + [obj setValue:[NSNumber numberWithBool:[value_lc isEqualToString:@"yes"]] forKey:key]; + } else { // string + [obj setValue:value forKey:key]; + } + } + } + } + + return obj; +} + +@end diff --git a/iOS/InAppBrowser/src/wp/InAppBrowser.cs b/iOS/InAppBrowser/src/wp/InAppBrowser.cs new file mode 100644 index 00000000..46e13849 --- /dev/null +++ b/iOS/InAppBrowser/src/wp/InAppBrowser.cs @@ -0,0 +1,277 @@ +using System; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using Microsoft.Phone.Controls; +using System.Diagnostics; +using System.Runtime.Serialization; +using WPCordovaClassLib.Cordova; +using WPCordovaClassLib.Cordova.Commands; +using WPCordovaClassLib.Cordova.JSON; +using Microsoft.Phone.Shell; +using Microsoft.Phone.Tasks; + +namespace WPCordovaClassLib.Cordova.Commands +{ + [DataContract] + public class BrowserOptions + { + [DataMember] + public string url; + + [DataMember] + public bool isGeolocationEnabled; + } + + public class InAppBrowser : BaseCommand + { + + private static WebBrowser browser; + private static ApplicationBarIconButton backButton; + private static ApplicationBarIconButton fwdButton; + + public void open(string options) + { + string[] args = JSON.JsonHelper.Deserialize(options); + //BrowserOptions opts = JSON.JsonHelper.Deserialize(options); + string urlLoc = args[0]; + string target = args[1]; + /* + _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser + _blank - always open in the InAppBrowser + _system - always open in the system web browser + */ + switch (target) + { + case "_blank": + ShowInAppBrowser(urlLoc); + break; + case "_self": + ShowCordovaBrowser(urlLoc); + break; + case "_system": + ShowSystemBrowser(urlLoc); + break; + } + + + } + + private void ShowCordovaBrowser(string url) + { + Uri loc = new Uri(url, UriKind.RelativeOrAbsolute); + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + if (page != null) + { + CordovaView cView = page.FindName("CordovaView") as CordovaView; + if (cView != null) + { + WebBrowser br = cView.Browser; + br.Navigate(loc); + } + } + + } + }); + } + + private void ShowSystemBrowser(string url) + { + WebBrowserTask webBrowserTask = new WebBrowserTask(); + webBrowserTask.Uri = new Uri(url, UriKind.Absolute); + webBrowserTask.Show(); + } + + + private void ShowInAppBrowser(string url) + { + Uri loc = new Uri(url); + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + if (browser != null) + { + //browser.IsGeolocationEnabled = opts.isGeolocationEnabled; + browser.Navigate(loc); + } + else + { + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + + string baseImageUrl = "Images/"; + + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + browser = new WebBrowser(); + browser.IsScriptEnabled = true; + browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted); + + browser.Navigating += new EventHandler(browser_Navigating); + browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed); + browser.Navigated += new EventHandler(browser_Navigated); + browser.Navigate(loc); + //browser.IsGeolocationEnabled = opts.isGeolocationEnabled; + grid.Children.Add(browser); + } + + ApplicationBar bar = new ApplicationBar(); + bar.BackgroundColor = Colors.Gray; + bar.IsMenuEnabled = false; + + backButton = new ApplicationBarIconButton(); + backButton.Text = "Back"; + + backButton.IconUri = new Uri(baseImageUrl + "appbar.back.rest.png", UriKind.Relative); + backButton.Click += new EventHandler(backButton_Click); + bar.Buttons.Add(backButton); + + + fwdButton = new ApplicationBarIconButton(); + fwdButton.Text = "Forward"; + fwdButton.IconUri = new Uri(baseImageUrl + "appbar.next.rest.png", UriKind.Relative); + fwdButton.Click += new EventHandler(fwdButton_Click); + bar.Buttons.Add(fwdButton); + + ApplicationBarIconButton closeBtn = new ApplicationBarIconButton(); + closeBtn.Text = "Close"; + closeBtn.IconUri = new Uri(baseImageUrl + "appbar.close.rest.png", UriKind.Relative); + closeBtn.Click += new EventHandler(closeBtn_Click); + bar.Buttons.Add(closeBtn); + + page.ApplicationBar = bar; + } + + } + } + }); + } + + void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) + { + + } + + void fwdButton_Click(object sender, EventArgs e) + { + if (browser != null) + { + try + { +#if WP8 + browser.GoForward(); +#else + browser.InvokeScript("execScript", "history.forward();"); +#endif + } + catch (Exception) + { + + } + } + } + + void backButton_Click(object sender, EventArgs e) + { + if (browser != null) + { + try + { +#if WP8 + browser.GoBack(); +#else + browser.InvokeScript("execScript", "history.back();"); +#endif + } + catch (Exception) + { + + } + } + } + + void closeBtn_Click(object sender, EventArgs e) + { + this.close(); + } + + + public void close(string options = "") + { + if (browser != null) + { + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + grid.Children.Remove(browser); + } + page.ApplicationBar = null; + } + } + browser = null; + string message = "{\"type\":\"exit\"}"; + PluginResult result = new PluginResult(PluginResult.Status.OK, message); + result.KeepCallback = false; + this.DispatchCommandResult(result); + }); + } + } + + void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) + { +#if WP8 + if (browser != null) + { + backButton.IsEnabled = browser.CanGoBack; + fwdButton.IsEnabled = browser.CanGoForward; + + } +#endif + string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}"; + PluginResult result = new PluginResult(PluginResult.Status.OK, message); + result.KeepCallback = true; + this.DispatchCommandResult(result); + } + + void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e) + { + string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}"; + PluginResult result = new PluginResult(PluginResult.Status.ERROR, message); + result.KeepCallback = true; + this.DispatchCommandResult(result); + } + + void browser_Navigating(object sender, NavigatingEventArgs e) + { + string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}"; + PluginResult result = new PluginResult(PluginResult.Status.OK, message); + result.KeepCallback = true; + this.DispatchCommandResult(result); + } + + } +} diff --git a/iOS/InAppBrowser/www/InAppBrowser.js b/iOS/InAppBrowser/www/InAppBrowser.js new file mode 100644 index 00000000..75a35453 --- /dev/null +++ b/iOS/InAppBrowser/www/InAppBrowser.js @@ -0,0 +1,98 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +var exec = require('cordova/exec'); +var channel = require('cordova/channel'); +var modulemapper = require('cordova/modulemapper'); + +function InAppBrowser() { + this.channels = { + 'loadstart': channel.create('loadstart'), + 'loadstop' : channel.create('loadstop'), + 'loaderror' : channel.create('loaderror'), + 'exit' : channel.create('exit') + }; +} + +InAppBrowser.prototype = { +_eventHandler: function (event) { + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } +}, +close: function (eventname) { + exec(null, null, "InAppBrowser", "close", []); +}, +show: function (eventname) { + exec(null, null, "InAppBrowser", "show", []); +}, +addEventListener: function (eventname,f) { + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } +}, +removeEventListener: function(eventname, f) { + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } +}, + +executeScript: function(injectDetails, cb) { + if (injectDetails.code) { + exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]); + } else if (injectDetails.file) { + exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]); + } else { + throw new Error('executeScript requires exactly one of code or file to be specified'); + } +}, + +insertCSS: function(injectDetails, cb) { + if (injectDetails.code) { + exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]); + } else if (injectDetails.file) { + exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]); + } else { + throw new Error('insertCSS requires exactly one of code or file to be specified'); + } +} +}; + + +module.exports = function(strUrl, strWindowName, strWindowFeatures) { + var iab = new InAppBrowser(); + var cb = function(eventname) { + iab._eventHandler(eventname); + }; + + // Don't catch calls that write to existing frames (e.g. named iframes). + if (window.frames && window.frames[strWindowName]) { + var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open'); + return origOpenFunc.apply(window, arguments); + } + + exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); + + return iab; +}; + + +window.console.log('inappbrowser.js loaded...'); \ No newline at end of file From 7d7ee2cabc0fdaa0ec879b2b5c51d3f5d34b91e1 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 07:22:49 -0400 Subject: [PATCH 05/25] 20130731.2 --- iOS/Badge/README.md | 11 +++++++++++ iOS/Badge/{README => README_old.md} | 0 2 files changed, 11 insertions(+) create mode 100644 iOS/Badge/README.md rename iOS/Badge/{README => README_old.md} (100%) diff --git a/iOS/Badge/README.md b/iOS/Badge/README.md new file mode 100644 index 00000000..20b310f4 --- /dev/null +++ b/iOS/Badge/README.md @@ -0,0 +1,11 @@ +cordova-badge +============= + +Original version/notes here: +https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Badge + +##Install Plugin: +cordova plugin add https://github.com/cemerson/cordova-badge.git + +##Remove Plugin: +cordova plugin rm org.apache.cordova.plugins.Badge \ No newline at end of file diff --git a/iOS/Badge/README b/iOS/Badge/README_old.md similarity index 100% rename from iOS/Badge/README rename to iOS/Badge/README_old.md From ce82db6bd4d095279cbeb4bb96b8e79e466aa7df Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:02:36 -0400 Subject: [PATCH 06/25] 20130731.3 updating Badge to be a submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..11eb03df --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge + url = https://github.com/cemerson/cordova-badge.git From d6173901301298613c340952c5d3de9e05d34df7 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:24:24 -0400 Subject: [PATCH 07/25] 20130731.5 --- iOS/Badge/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iOS/Badge/README.md b/iOS/Badge/README.md index 20b310f4..1d0f6b59 100644 --- a/iOS/Badge/README.md +++ b/iOS/Badge/README.md @@ -8,4 +8,6 @@ https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Badge cordova plugin add https://github.com/cemerson/cordova-badge.git ##Remove Plugin: -cordova plugin rm org.apache.cordova.plugins.Badge \ No newline at end of file +cordova plugin rm org.apache.cordova.plugins.Badge + +20130731.5 From 980474fd0b7ca586a1f836fbe4563331260c4b29 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:32:41 -0400 Subject: [PATCH 08/25] Moving InAppBrowser to submodule --- .gitmodules | 6 + .../Cordova 2.x/PowerManagement.h | 45 -- .../Cordova 2.x/PowerManagement.m | 75 -- .../Cordova 2.x/powermanagement.js | 57 -- iOS/PowerManagement/LICENSE | 674 ----------------- iOS/PowerManagement/README.md | 13 - iOS/PowerManagement/README_old.md | 49 -- iOS/PowerManagement/plugin.xml | 27 - iOS/PowerManagement/src/ios/PowerManagement.h | 48 -- iOS/PowerManagement/src/ios/PowerManagement.m | 93 --- iOS/PowerManagement/www/PowerManagement.js | 59 -- iOS/SecureDeviceIdentifier/README.md | 17 - iOS/SecureDeviceIdentifier/README_old.md | 47 -- iOS/SecureDeviceIdentifier/plugin.xml | 30 - .../src/ios/SecureDeviceIdentifier.h | 33 - .../src/ios/SecureDeviceIdentifier.m | 39 - .../src/ios/SecureUDID/SecureUDID.h | 75 -- .../src/ios/SecureUDID/SecureUDID.m | 679 ------------------ .../www/SecureDeviceIdentifier.js | 42 -- 19 files changed, 6 insertions(+), 2102 deletions(-) delete mode 100644 iOS/PowerManagement/Cordova 2.x/PowerManagement.h delete mode 100644 iOS/PowerManagement/Cordova 2.x/PowerManagement.m delete mode 100644 iOS/PowerManagement/Cordova 2.x/powermanagement.js delete mode 100644 iOS/PowerManagement/LICENSE delete mode 100644 iOS/PowerManagement/README.md delete mode 100644 iOS/PowerManagement/README_old.md delete mode 100644 iOS/PowerManagement/plugin.xml delete mode 100644 iOS/PowerManagement/src/ios/PowerManagement.h delete mode 100644 iOS/PowerManagement/src/ios/PowerManagement.m delete mode 100644 iOS/PowerManagement/www/PowerManagement.js delete mode 100644 iOS/SecureDeviceIdentifier/README.md delete mode 100644 iOS/SecureDeviceIdentifier/README_old.md delete mode 100644 iOS/SecureDeviceIdentifier/plugin.xml delete mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h delete mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m delete mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h delete mode 100755 iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m delete mode 100644 iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js diff --git a/.gitmodules b/.gitmodules index 11eb03df..8b47fbc2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge url = https://github.com/cemerson/cordova-badge.git +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser + url = https://github.com/cemerson/cordova-inappbrowser-ce.git +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier + url = https://github.com/cemerson/cordova-securedeviceidentifier.git diff --git a/iOS/PowerManagement/Cordova 2.x/PowerManagement.h b/iOS/PowerManagement/Cordova 2.x/PowerManagement.h deleted file mode 100644 index 6fd219d6..00000000 --- a/iOS/PowerManagement/Cordova 2.x/PowerManagement.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -/** - * Cordova (iOS) plugin for accessing the power-management functions of the device - */ - -#ifdef CORDOVA_FRAMEWORK -#import -#else -#import "CORDOVA/CDVPlugin.h" -#endif - -/** - * Interface which does the actual handling - */ -@interface PowerManagement :CDVPlugin { -} -/** - * Sets the idleTimerDisable property to true so that the idle timeout is disabled - */ -- (void) acquire:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Sets the idleTimerDisable property to false so that the idle timeout is enabled - */ -- (void) release:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -@end diff --git a/iOS/PowerManagement/Cordova 2.x/PowerManagement.m b/iOS/PowerManagement/Cordova 2.x/PowerManagement.m deleted file mode 100644 index 708c8d71..00000000 --- a/iOS/PowerManagement/Cordova 2.x/PowerManagement.m +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -/** - * Cordova (iOS) plugin for accessing the power-management functions of the device - */ -#import "PowerManagement.h" - -/** - * Actual implementation of the interface - */ -@implementation PowerManagement -- (void) acquire:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* jsString = nil; - NSString* callbackId = [arguments objectAtIndex:0]; - - // Acquire a reference to the local UIApplication singleton - UIApplication* app = [UIApplication sharedApplication]; - - if( ![app isIdleTimerDisabled] ) { - [app setIdleTimerDisabled:true]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - jsString = [result toSuccessCallbackString:callbackId]; - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer already disabled"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; -} - - -- (void) release:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options -{ - CDVPluginResult* result = nil; - NSString* jsString = nil; - NSString* callbackId = [arguments objectAtIndex:0]; - - // Acquire a reference to the local UIApplication singleton - UIApplication* app = [UIApplication sharedApplication]; - - if( [app isIdleTimerDisabled] ) { - [app setIdleTimerDisabled:false]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - jsString = [result toSuccessCallbackString:callbackId]; - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer not disabled"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; -} -@end diff --git a/iOS/PowerManagement/Cordova 2.x/powermanagement.js b/iOS/PowerManagement/Cordova 2.x/powermanagement.js deleted file mode 100644 index e3705e5c..00000000 --- a/iOS/PowerManagement/Cordova 2.x/powermanagement.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -cordova.define("cordova/plugin/powermanagement", function(require, exports, module) { - var exec = require('cordova/exec'); - - var PowerManagement = function() {}; - - /** - * Acquire a new wake-lock (keep device awake) - * - * @param successCallback function to be called when the wake-lock was acquired successfully - * @param errorCallback function to be called when there was a problem with acquiring the wake-lock - */ - PowerManagement.prototype.acquire = function(successCallback,failureCallback) { - exec(successCallback, failureCallback, 'PowerManagement', 'acquire', []); - } - - /** - * Release the wake-lock - * - * @param successCallback function to be called when the wake-lock was released successfully - * @param errorCallback function to be called when there was a problem while releasing the wake-lock - */ - PowerManagement.prototype.release = function(successCallback,failureCallback) { - exec(successCallback, failureCallback, 'PowerManagement', 'release', []); - } - - /** - * Acquire a partial wake-lock, allowing the device to dim the screen - * - * @param successCallback function to be called when the wake-lock was acquired successfully - * @param errorCallback function to be called when there was a problem with acquiring the wake-lock - */ - PowerManagement.prototype.dim = function(successCallback,failureCallback) { - exec(successCallback, failureCallback, 'PowerManagement', 'acquire', [true]); - } - - var powermanagement = new PowerManagement(); - module.exports = powermanagement; -}); diff --git a/iOS/PowerManagement/LICENSE b/iOS/PowerManagement/LICENSE deleted file mode 100644 index 20d40b6b..00000000 --- a/iOS/PowerManagement/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/iOS/PowerManagement/README.md b/iOS/PowerManagement/README.md deleted file mode 100644 index 66bcb775..00000000 --- a/iOS/PowerManagement/README.md +++ /dev/null @@ -1,13 +0,0 @@ -cordova-powermanagement -======================= - -###Install to project: -cordova plugin add https://github.com/cemerson/cordova-powermanagement.git - -###Remove from project: -cordova plugin rm org.apache.cordova.plugins.PowerManagement - -###Changes -- Removed All platforms except IOS for now :( -- Updated plugin files to work in CDV 3 CLI -- Updated PowerManagement.m to eliminate Background Thread warning in Xcode (reference: http://goo.gl/JokRZw) diff --git a/iOS/PowerManagement/README_old.md b/iOS/PowerManagement/README_old.md deleted file mode 100644 index 1c36035e..00000000 --- a/iOS/PowerManagement/README_old.md +++ /dev/null @@ -1,49 +0,0 @@ -PowerManagement -=============== -Plugin for Cordova (1.6+) - -The PowerManagement plugin offers access to the devices power-management functionality. -It should be used for applications which keep running for a long time without any user interaction. - -For details on power functionality see: - -* Android: [PowerManager](http://developer.android.com/reference/android/os/PowerManager.html) -* iOS: [idleTimerDisabled](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instp/UIApplication/idleTimerDisabled) - -Platforms ---------- -Currently available on: - -### Android -Copy the *PowerManagement.java* file to your *src/* directory. - -Edit your *AndroidManifest.xml* and add the following permission: -`` - -In addition you have to edit your *res/xml/plugins.xml* file to let Cordova know about the plugin: -`` - -### iOS -Copy the *PowerManagement.h* and *PowerManagement.m* files to your projects "Plugins" folder. - -Add the PowerManagement plugin to the *Cordova.plist* file (to the Plugins list). Both Key and Value are "PowerManagement". - - -License -======= -Copyright (C) 2011-2012 Wolfgang Koller - -This file is part of GOFG Sports Computer - http://www.gofg.at/. - -GOFG Sports Computer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -GOFG Sports Computer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GOFG Sports Computer. If not, see . diff --git a/iOS/PowerManagement/plugin.xml b/iOS/PowerManagement/plugin.xml deleted file mode 100644 index ee3e1548..00000000 --- a/iOS/PowerManagement/plugin.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - PowerManagement - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/PowerManagement/src/ios/PowerManagement.h b/iOS/PowerManagement/src/ios/PowerManagement.h deleted file mode 100644 index 1e918d41..00000000 --- a/iOS/PowerManagement/src/ios/PowerManagement.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -/** - * Cordova (iOS) plugin for accessing the power-management functions of the device - */ - -#ifdef CORDOVA_FRAMEWORK -#import -#else -#import "CORDOVA/CDVPlugin.h" -#endif - -/** - * Interface which does the actual handling - */ -@interface PowerManagement :CDVPlugin { -} -/** - * Sets the idleTimerDisable property to true so that the idle timeout is disabled - */ -- (void) acquire:(CDVInvokedUrlCommand*)command; -// - (void) acquire:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -/** - * Sets the idleTimerDisable property to false so that the idle timeout is enabled - * - */ -- (void) release:(CDVInvokedUrlCommand*)command; -//- (void) release:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; - -@end diff --git a/iOS/PowerManagement/src/ios/PowerManagement.m b/iOS/PowerManagement/src/ios/PowerManagement.m deleted file mode 100644 index 5fb7b1d8..00000000 --- a/iOS/PowerManagement/src/ios/PowerManagement.m +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -/** - * Cordova (iOS) plugin for accessing the power-management functions of the device - */ -#import "PowerManagement.h" - -/** - * Actual implementation of the interface - */ -@implementation PowerManagement -- (void) acquire:(CDVInvokedUrlCommand*)command{ - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - dispatch_async(dispatch_get_main_queue(), ^(void) { - - CDVPluginResult* result = nil; - NSString* jsString = nil; - NSString* callbackId = nil; - if(command.arguments.count) callbackId = [command.arguments objectAtIndex:0]; - - // Acquire a reference to the local UIApplication singleton - UIApplication* app = [UIApplication sharedApplication]; - - if( ![app isIdleTimerDisabled] ) { - [app setIdleTimerDisabled:true]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - jsString = [result toSuccessCallbackString:callbackId]; - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer already disabled"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; - - }); - }); -} - -- (void) release:(CDVInvokedUrlCommand*)command{ - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - dispatch_async(dispatch_get_main_queue(), ^(void) { - - CDVPluginResult* result = nil; - NSString* jsString = nil; - NSString* callbackId = nil; - if(command.arguments.count) callbackId = [command.arguments objectAtIndex:0]; - - // Acquire a reference to the local UIApplication singleton - UIApplication* app = [UIApplication sharedApplication]; - - - if( [app isIdleTimerDisabled] ) { - [app setIdleTimerDisabled:false]; - - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - jsString = [result toSuccessCallbackString:callbackId]; - } - else { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsString:@"IdleTimer not disabled"]; - jsString = [result toErrorCallbackString:callbackId]; - } - - [self writeJavascript:jsString]; - - }); - }); - - -} -@end diff --git a/iOS/PowerManagement/www/PowerManagement.js b/iOS/PowerManagement/www/PowerManagement.js deleted file mode 100644 index 531d5da5..00000000 --- a/iOS/PowerManagement/www/PowerManagement.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2011-2012 Wolfgang Koller - * - * This file is part of GOFG Sports Computer - http://www.gofg.at/. - * - * GOFG Sports Computer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GOFG Sports Computer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GOFG Sports Computer. If not, see . - */ - -cordova.define("cordova/plugin/powermanagement", function(require, exports, module) { - var exec = require('cordova/exec'); - - var PowerManagement = function() {}; - - /** - * Acquire a new wake-lock (keep device awake) - * - * @param powerMgmtSuccess function to be called when the wake-lock was acquired successfully - * @param errorCallback function to be called when there was a problem with acquiring the wake-lock - */ - PowerManagement.prototype.acquire = function(powerMgmtSuccess,powerMgmtError) { - exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'acquire', []); - } - - /** - * Release the wake-lock - * - * @param powerMgmtSuccess function to be called when the wake-lock was released successfully - * @param errorCallback function to be called when there was a problem while releasing the wake-lock - */ - PowerManagement.prototype.release = function(powerMgmtSuccess,powerMgmtError) { - exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'release', []); - } - - /** - * Acquire a partial wake-lock, allowing the device to dim the screen - * - * @param powerMgmtSuccess function to be called when the wake-lock was acquired successfully - * @param errorCallback function to be called when there was a problem with acquiring the wake-lock - */ - PowerManagement.prototype.dim = function(powerMgmtSuccess,powerMgmtError) { - exec(powerMgmtSuccess, powerMgmtError, 'PowerManagement', 'acquire', [true]); - } - - var powermanagement = new PowerManagement(); - module.exports = powermanagement; -}); - -/* DEBUG */ window.console.log('PowerManagement.js loaded...'); diff --git a/iOS/SecureDeviceIdentifier/README.md b/iOS/SecureDeviceIdentifier/README.md deleted file mode 100644 index 3158d545..00000000 --- a/iOS/SecureDeviceIdentifier/README.md +++ /dev/null @@ -1,17 +0,0 @@ -com.apps-pi.securedeviceidentifier ------------------------------ - -###Install to project: -cordova plugin add https://github.com/cemerson/cordova-securedeviceidentifier.git - -###Remove from project: -cordova plugin rm org.apache.cordova.plugins.SecureDeviceIdentifier - -###Changes -- Removed All platforms except IOS for now :( -- Updated plugin files to work in CDV 3 CLI -- Updated SecureDeviceIdentifier.m to eliminate Background Thread warning in Xcode (reference: http://goo.gl/JokRZw) - -###TODO: -- If InAppBrowser is open in windowed mode and is called again to be fullscreen need to reset plugin to make sure fullscreen takes effect -- cleanup (never ends) \ No newline at end of file diff --git a/iOS/SecureDeviceIdentifier/README_old.md b/iOS/SecureDeviceIdentifier/README_old.md deleted file mode 100644 index f0987005..00000000 --- a/iOS/SecureDeviceIdentifier/README_old.md +++ /dev/null @@ -1,47 +0,0 @@ -# Cordova SecureDeviceIdentifier Plugin # -by [Olivier Louvignes](http://olouv.com) - ---- -### [This plugin is hosted by the author](https://github.com/mgcrea/cordova-secureudid/tree/master) ---- - -## DESCRIPTION ## - -* This plugin provides a simple way to retreive a secureUDID to replace Apple deprecated UDID. - -* This plugin is built for Cordova >= v2.1.0 with ARC. - -* It relies on [SecureUDID](https://github.com/mgcrea/secureudid) to work (MIT license, included in ./libs). - -[![Screenshot](http://www.crashlytics.com/blog/wp-content/uploads/2012/03/SecureUDID.png)](https://github.com/mgcrea/cordova-secureudid/tree/master) - -## LICENSE ## - - The MIT License - - Copyright (c) 2012 Olivier Louvignes - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -## CREDITS ## - -Contributors : - -* [Olivier Louvignes](http://olouv.com), author. - diff --git a/iOS/SecureDeviceIdentifier/plugin.xml b/iOS/SecureDeviceIdentifier/plugin.xml deleted file mode 100644 index ddff93a7..00000000 --- a/iOS/SecureDeviceIdentifier/plugin.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - SecureDeviceIdentifier - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h deleted file mode 100755 index 565c577d..00000000 --- a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// SecureDeviceIdentifier.h -// -// Created by Olivier Louvignes on 2012-05-31. -// -// Copyright 2012 Olivier Louvignes. All rights reserved. -// MIT Licensed - -#import -#import - -@interface SecureDeviceIdentifier : CDVPlugin { -} - -#pragma mark - Properties - -@property (nonatomic, copy) NSString* callbackId; -@property (nonatomic, copy) NSString* secureUDID; - -#pragma mark - Instance methods - -- (void)get:(CDVInvokedUrlCommand*)command; - -@end - -#pragma mark - Logging tools - -#ifdef DEBUG -# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); -#else -# define DLog(...) -#endif -#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m b/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m deleted file mode 100755 index cb5ac721..00000000 --- a/iOS/SecureDeviceIdentifier/src/ios/SecureDeviceIdentifier.m +++ /dev/null @@ -1,39 +0,0 @@ -// -// SecureDeviceIdentifier.m -// -// Created by Olivier Louvignes on 2012-05-31. -// -// Copyright 2012 Olivier Louvignes. All rights reserved. -// MIT Licensed - -#import "SecureDeviceIdentifier.h" -#import "SecureUDID.h" - -@implementation SecureDeviceIdentifier - -@synthesize callbackId = _callbackId, secureUDID = _secureUDID; - -- (void)get:(CDVInvokedUrlCommand*)command { - - self.callbackId = command.callbackId; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - //[self.commandDelegate runInBackground:^{ - NSDictionary *options = [command.arguments objectAtIndex:0]; - NSString *domain = [options objectForKey:@"domain"] ?: @""; - NSString *key = [options objectForKey:@"key"] ?: @""; - self.secureUDID = [SecureUDID UDIDForDomain:domain usingKey:key]; //NSLog(@"self.secureUDID %@", self.secureUDID); - - dispatch_async(dispatch_get_main_queue(), ^(void) { - // Create Plugin Result - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.secureUDID]; - // Call the Success Javascript function - [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackId]]; - }); - }); - - - -} - -@end diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h deleted file mode 100755 index d1b0c245..00000000 --- a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.h +++ /dev/null @@ -1,75 +0,0 @@ -// -// SecureUDID.h -// SecureUDID -// -// Created by Crashlytics Team on 3/22/12. -// Copyright (c) 2012 Crashlytics, Inc. All rights reserved. -// http://www.crashlytics.com -// info@crashlytics.com -// - -/* - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -#import - -@interface SecureUDID : NSObject - -/* - Returns a unique id for the device, sandboxed to the domain and salt provided. This is a potentially - expensive call. You should not do this on the main thread, especially during launch. - - retrieveUDIDForDomain:usingKey:completion: is provided as an alternative for your 4.0+ coding convenience. - - Example usage: - #import "SecureUDID.h" - - NSString *udid = [SecureUDID UDIDForDomain:@"com.example.myapp" key:@"difficult-to-guess-key"]; - - */ -+ (NSString *)UDIDForDomain:(NSString *)domain usingKey:(NSString *)key; - -/* - Getting a SecureUDID can be very expensive. Use this call to derive an identifier in the background, - and invoke a block when ready. Use of this method implies a device running >= iOS 4.0. - - Example usage: - #import "SecureUDID.h" - - [SecureUDID retrieveUDIDForDomain:@"com.example.myapp" usingKey:@"difficult-to-guess-key" completion:^(NSString *identifier) { - // make use of identifier here - }]; - - */ -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 -+ (void)retrieveUDIDForDomain:(NSString *)domain usingKey:(NSString *)key completion:(void (^)(NSString* identifier))completion; -#endif - -/* - Indicates that the system has been disabled via the Opt-Out mechansim. - */ -+ (BOOL)isOptedOut; - -@end - -/* - This identifier is returned when Opt-Out is enabled. - */ -extern NSString *const SUUIDDefaultIdentifier; diff --git a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m b/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m deleted file mode 100755 index 63710303..00000000 --- a/iOS/SecureDeviceIdentifier/src/ios/SecureUDID/SecureUDID.m +++ /dev/null @@ -1,679 +0,0 @@ -// -// SecureUDID.m -// SecureUDID -// -// Created by Crashlytics Team on 3/22/12. -// Copyright (c) 2012 Crashlytics, Inc. All rights reserved. -// http://www.crashlytics.com -// info@crashlytics.com -// - -/* - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -#import "SecureUDID.h" -#import -#import -#import -#import - -#define SUUID_SCHEMA_VERSION (1) -#define SUUID_MAX_STORAGE_LOCATIONS (64) - -NSString *const SUUIDDefaultIdentifier = @"00000000-0000-0000-0000-000000000000"; - -NSString *const SUUIDTypeDataDictionary = @"public.secureudid"; -NSString *const SUUIDTimeStampKey = @"SUUIDTimeStampKey"; -NSString *const SUUIDOwnerKey = @"SUUIDOwnerKey"; -NSString *const SUUIDLastAccessedKey = @"SUUIDLastAccessedKey"; -NSString *const SUUIDIdentifierKey = @"SUUIDIdentifierKey"; -NSString *const SUUIDOptOutKey = @"SUUIDOptOutKey"; -NSString *const SUUIDModelHashKey = @"SUUIDModelHashKey"; -NSString *const SUUIDSchemaVersionKey = @"SUUIDSchemaVersionKey"; -NSString *const SUUIDPastboardFileFormat = @"org.secureudid-%d"; - -NSData *SUUIDCryptorToData(CCOperation operation, NSData *value, NSData *key); -NSString *SUUIDCryptorToString(CCOperation operation, NSData *value, NSData *key); -NSData *SUUIDHash(NSData* data); -NSData *SUUIDModelHash(void); - -void SUUIDMarkOptedOut(void); -void SUUIDMarkOptedIn(void); -void SUUIDRemoveAllSecureUDIDData(void); -NSString *SUUIDPasteboardNameForNumber(NSInteger number); -NSInteger SUUIDStorageLocationForOwnerKey(NSData *key, NSMutableDictionary** dictionary); -NSDictionary *SUUIDDictionaryForStorageLocation(NSInteger number); -NSDictionary *SUUIDMostRecentDictionary(void); -void SUUIDWriteDictionaryToStorageLocation(NSInteger number, NSDictionary* dictionary); -void SUUIDDeleteStorageLocation(NSInteger number); - -BOOL SUUIDValidTopLevelObject(id object); -BOOL SUUIDValidOwnerObject(id object); - -@implementation SecureUDID - -/* - Returns a unique id for the device, sandboxed to the domain and salt provided. - - Example usage: - #import "SecureUDID.h" - - NSString *udid = [SecureUDID UDIDForDomain:@"com.example.myapp" salt:@"superSecretCodeHere!@##%#$#%$^"]; - - */ -+ (NSString *)UDIDForDomain:(NSString *)domain usingKey:(NSString *)key { - NSString *identifier = SUUIDDefaultIdentifier; - - // Salt the domain to make the crypt keys affectively unguessable. - NSData *domainAndKey = [[NSString stringWithFormat:@"%@%@", domain, key] dataUsingEncoding:NSUTF8StringEncoding]; - NSData *ownerKey = SUUIDHash(domainAndKey); - - // Encrypt the salted domain key and load the pasteboard on which to store data - NSData *encryptedOwnerKey = SUUIDCryptorToData(kCCEncrypt, [domain dataUsingEncoding:NSUTF8StringEncoding], ownerKey); - - // @synchronized introduces an implicit @try-@finally, so care needs to be taken with the return value - @synchronized (self) { - NSMutableDictionary *topLevelDictionary = nil; - - // Retrieve an appropriate storage index for this owner - NSInteger ownerIndex = SUUIDStorageLocationForOwnerKey(encryptedOwnerKey, &topLevelDictionary); - - // If the model hash key is present, verify it, otherwise add it - NSData *storedModelHash = [topLevelDictionary objectForKey:SUUIDModelHashKey]; - NSData *modelHash = SUUIDModelHash(); - - if (storedModelHash) { - if (![modelHash isEqual:storedModelHash]) { - // The model hashes do not match - this structure is invalid - [topLevelDictionary removeAllObjects]; - } - } - - // store the current model hash - [topLevelDictionary setObject:modelHash forKey:SUUIDModelHashKey]; - - // check for the opt-out flag and return the default identifier if we find it - if ([[topLevelDictionary objectForKey:SUUIDOptOutKey] boolValue] == YES) { - return identifier; - } - - // If we encounter a schema version greater than we support, there is no simple alternative - // other than to simulate Opt Out. Any writes to the store risk corruption. - if ([[topLevelDictionary objectForKey:SUUIDSchemaVersionKey] intValue] > SUUID_SCHEMA_VERSION) { - return identifier; - } - - // Attempt to get the owner's dictionary. Should we get back nil from the encryptedDomain key, we'll still - // get a valid, empty mutable dictionary - NSMutableDictionary *ownerDictionary = [NSMutableDictionary dictionaryWithDictionary:[topLevelDictionary objectForKey:encryptedOwnerKey]]; - - // Set our last access time and claim ownership for this storage location. - NSDate* lastAccessDate = [NSDate date]; - - [ownerDictionary setObject:lastAccessDate forKey:SUUIDLastAccessedKey]; - [topLevelDictionary setObject:lastAccessDate forKey:SUUIDTimeStampKey]; - [topLevelDictionary setObject:encryptedOwnerKey forKey:SUUIDOwnerKey]; - - [topLevelDictionary setObject:[NSNumber numberWithInt:SUUID_SCHEMA_VERSION] forKey:SUUIDSchemaVersionKey]; - - // Make sure our owner dictionary is in the top level structure - [topLevelDictionary setObject:ownerDictionary forKey:encryptedOwnerKey]; - - - NSData *identifierData = [ownerDictionary objectForKey:SUUIDIdentifierKey]; - if (identifierData) { - identifier = SUUIDCryptorToString(kCCDecrypt, identifierData, ownerKey); - if (!identifier) { - // We've failed to decrypt our identifier. This is a sign of storage corruption. - SUUIDDeleteStorageLocation(ownerIndex); - - // return here - do not write values back to the store - return SUUIDDefaultIdentifier; - } - } else { - // Otherwise, create a new RFC-4122 Version 4 UUID - // http://en.wikipedia.org/wiki/Universally_unique_identifier - CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); - identifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)); - CFRelease(uuid); - - // Encrypt it for storage. - NSData *data = SUUIDCryptorToData(kCCEncrypt, [identifier dataUsingEncoding:NSUTF8StringEncoding], ownerKey); - - [ownerDictionary setObject:data forKey:SUUIDIdentifierKey]; - } - - SUUIDWriteDictionaryToStorageLocation(ownerIndex, topLevelDictionary); - } - - return identifier; -} - -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 -+ (void)retrieveUDIDForDomain:(NSString *)domain usingKey:(NSString *)key completion:(void (^)(NSString* identifier))completion { - // retreive the identifier on a low-priority thread - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - NSString* identifier; - - identifier = [SecureUDID UDIDForDomain:domain usingKey:key]; - - completion(identifier); - }); -} -#endif - -/* - API to determine if a device has opted out of SecureUDID. - */ -+ (BOOL)isOptedOut { - for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - NSDictionary* topLevelDictionary; - - topLevelDictionary = SUUIDDictionaryForStorageLocation(i); - if (!topLevelDictionary) { - continue; - } - - if ([[topLevelDictionary objectForKey:SUUIDOptOutKey] boolValue] == YES) { - return YES; - } - } - - return NO; -} - -/* - Applies the operation (encrypt or decrypt) to the NSData value with the provided NSData key - and returns the value as NSData. - */ -NSData *SUUIDCryptorToData(CCOperation operation, NSData *value, NSData *key) { - NSMutableData *output = [NSMutableData dataWithLength:value.length + kCCBlockSizeAES128]; - - size_t numBytes = 0; - CCCryptorStatus cryptStatus = CCCrypt(operation, - kCCAlgorithmAES128, - kCCOptionPKCS7Padding, - [key bytes], - kCCKeySizeAES128, - NULL, - value.bytes, - value.length, - output.mutableBytes, - output.length, - &numBytes); - - if (cryptStatus == kCCSuccess) { - return [NSData dataWithBytes:output.bytes length:numBytes]; - } - - return nil; -} - -/* - Applies the operation (encrypt or decrypt) to the NSData value with the provided NSData key - and returns the value as an NSString. - */ -NSString *SUUIDCryptorToString(CCOperation operation, NSData *value, NSData *key) { - NSData* data; - - data = SUUIDCryptorToData(operation, value, key); - if (!data) { - return nil; - } - - return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; -} - -/* - Compute a SHA1 of the input. - */ -NSData *SUUIDHash(NSData *data) { - uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; - - CC_SHA1(data.bytes, data.length, digest); - - return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; -} - -NSData* SUUIDModelHash(void) { - NSString* result; - - result = nil; - - do { - size_t size; - - // first get the size - if (sysctlbyname("hw.machine", NULL, &size, NULL, 0) != 0) { - break; - } - - char value[size]; - - // now get the value - if (sysctlbyname("hw.machine", value, &size, NULL, 0) != 0) { - break; - } - - // convert the value to an NSString - result = [NSString stringWithCString:value encoding:NSUTF8StringEncoding]; - } while (0); - - if (!result) { - result = @"Unknown"; - } - - return SUUIDHash([result dataUsingEncoding:NSUTF8StringEncoding]); -} - -/* - Finds the most recent structure, and adds the Opt-Out flag to it. Then writes that structure back - out to all used storage locations, making sure to preserve ownership. - */ -void SUUIDMarkOptedOut(void) { - NSMutableDictionary* mostRecentDictionary; - - mostRecentDictionary = [NSMutableDictionary dictionaryWithDictionary:SUUIDMostRecentDictionary()]; - - [mostRecentDictionary setObject:[NSDate date] forKey:SUUIDTimeStampKey]; - [mostRecentDictionary setObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; - - for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - NSData* owner; - - // Inherit the owner, if it is present. This makes some schema assumptions. - owner = [SUUIDDictionaryForStorageLocation(i) objectForKey:SUUIDOwnerKey]; - if (owner) { - [mostRecentDictionary setObject:owner forKey:SUUIDOwnerKey]; - } - - // write the opt-out data even if the location was previously empty - SUUIDWriteDictionaryToStorageLocation(i, mostRecentDictionary); - } -} - -void SUUIDMarkOptedIn(void) { - NSDate* accessedDate; - - accessedDate = [NSDate date]; - - // Opting back in is trickier. We need to remove top-level Opt-Out markers. Also makes some - // schema assumptions. - for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - NSMutableDictionary* dictionary; - - dictionary = [NSMutableDictionary dictionaryWithDictionary:SUUIDDictionaryForStorageLocation(i)]; - if (!dictionary) { - // This is a possible indiction of storage corruption. However, SUUIDDictionaryForStorageLocation - // will have already cleaned it up for us, so there's not much to do here. - continue; - } - - [dictionary removeObjectForKey:SUUIDOptOutKey]; - - // quick check for the minimum set of keys. If the dictionary previously held just - // an Opt-Out marker + timestamp, dictionary is not invalid. Writing will fail in this - // case, leaving the data that was there. We need to delete. - if (!SUUIDValidTopLevelObject(dictionary)) { - SUUIDDeleteStorageLocation(i); - continue; - } - - [dictionary setObject:accessedDate forKey:SUUIDTimeStampKey]; - - SUUIDWriteDictionaryToStorageLocation(i, dictionary); - } -} - -/* - Removes all SecureUDID data from storage with the exception of Opt-Out flags, which - are never removed. Removing the Opt-Out flags would effectively opt a user back in. - */ -void SUUIDRemoveAllSecureUDIDData(void) { - NSDictionary* optOutPlaceholder = nil; - - if ([SecureUDID isOptedOut]) { - optOutPlaceholder = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; - } - - for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - if (optOutPlaceholder) { - SUUIDWriteDictionaryToStorageLocation(i, optOutPlaceholder); - continue; - } - - SUUIDDeleteStorageLocation(i); - } -} - -/* - Returns an NSString formatted with the supplied number. - */ -NSString *SUUIDPasteboardNameForNumber(NSInteger number) { - return [NSString stringWithFormat:SUUIDPastboardFileFormat, number]; -} - -/* - Reads a dictionary from a storage location. Validation occurs once data - is read, but before it is returned. If something fails, or if the read structure - is invalid, the location is cleared. - - Returns the data dictionary, or nil on failure. - */ -NSDictionary *SUUIDDictionaryForStorageLocation(NSInteger number) { - id decodedObject; - UIPasteboard* pasteboard; - NSData* data; - - // Don't even bother if the index is outside our limits - if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { - return nil; - } - - pasteboard = [UIPasteboard pasteboardWithName:SUUIDPasteboardNameForNumber(number) create:NO]; - if (!pasteboard) { - return nil; - } - - data = [pasteboard valueForPasteboardType:SUUIDTypeDataDictionary]; - if (!data) { - return nil; - } - - @try { - decodedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - } @catch (NSException* exception) { - // Catching an exception like this is risky. However, crashing here is - // not acceptable, and unarchiveObjectWithData can throw. - [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; - - return nil; - } - - if (!SUUIDValidTopLevelObject(decodedObject)) { - [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; - - return nil; - } - - return decodedObject; -} - -NSDictionary *SUUIDMostRecentDictionary(void) { - NSDictionary* mostRecentDictionary; - BOOL found; - - mostRecentDictionary = [NSDictionary dictionaryWithObject:[NSDate distantPast] forKey:SUUIDTimeStampKey]; - - // scan all locations looking for the most recent - for (NSUInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - NSDictionary* dictionary; - NSDate* date; - - dictionary = SUUIDDictionaryForStorageLocation(i); - if (!dictionary) { - continue; - } - - // Schema assumption - date = [dictionary objectForKey:SUUIDTimeStampKey]; - if ([date compare:[mostRecentDictionary objectForKey:SUUIDTimeStampKey]] == NSOrderedDescending) { - mostRecentDictionary = dictionary; - found = YES; - } - } - - if (!found) { - return nil; - } - - return mostRecentDictionary; -} - -/* - Writes out a dictionary to a storage location. That dictionary must be a 'valid' - SecureUDID structure, and the location must be within range. A new location is - created if is didn't already exist. - */ -void SUUIDWriteDictionaryToStorageLocation(NSInteger number, NSDictionary* dictionary) { - UIPasteboard* pasteboard; - - // be sure to respect our limits - if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { - return; - } - - // only write out valid structures - if (!SUUIDValidTopLevelObject(dictionary)) { - return; - } - - pasteboard = [UIPasteboard pasteboardWithName:SUUIDPasteboardNameForNumber(number) create:YES]; - if (!pasteboard) { - return; - } - - pasteboard.persistent = YES; - - [pasteboard setData:[NSKeyedArchiver archivedDataWithRootObject:dictionary] - forPasteboardType:SUUIDTypeDataDictionary]; -} - -/* - Clear a storage location, removing anything stored there. Useful for dealing with - potential corruption. Be careful with this function, as it can remove Opt-Out markers. - */ -void SUUIDDeleteStorageLocation(NSInteger number) { - UIPasteboard* pasteboard; - NSString* name; - - if (number < 0 || number >= SUUID_MAX_STORAGE_LOCATIONS) { - return; - } - - name = SUUIDPasteboardNameForNumber(number); - pasteboard = [UIPasteboard pasteboardWithName:name create:NO]; - if (!pasteboard) - return; - - // While setting pasteboard data to nil seems to always remove contents, the - // removePasteboardWithName: call doesn't appear to always work. Using both seems - // like the safest thing to do - [pasteboard setData:nil forPasteboardType:SUUIDTypeDataDictionary]; - [UIPasteboard removePasteboardWithName:name]; -} - -/* - SecureUDID leverages UIPasteboards to persistently store its data. - UIPasteboards marked as 'persistent' have the following attributes: - - They persist across application relaunches, device reboots, and OS upgrades. - - They are destroyed when the application that created them is deleted from the device. - - To protect against the latter case, SecureUDID leverages multiple pasteboards (up to - SUUID_MAX_STORAGE_LOCATIONS), creating one for each distinct domain/app that - leverages the system. The permanence of SecureUDIDs increases exponentially with the - number of apps that use it. - - This function searches for a suitable storage location for a SecureUDID structure. It - attempts to find the structure written by ownerKey. If no owner is found and there are - still open locations, the lowest numbered location is selected. If there are no - available locations, the last-written is selected. - - Once a spot is found, the most-recent data is re-written over this location. The location - is then, finally, returned. - */ -NSInteger SUUIDStorageLocationForOwnerKey(NSData *ownerKey, NSMutableDictionary** ownerDictionary) { - NSInteger ownerIndex; - NSInteger lowestUnusedIndex; - NSInteger oldestUsedIndex; - NSDate* mostRecentDate; - NSDate* oldestUsedDate; - NSDictionary* mostRecentDictionary; - BOOL optedOut; - - ownerIndex = -1; - lowestUnusedIndex = -1; - oldestUsedIndex = 0; // make sure this value is always in range - mostRecentDate = [NSDate distantPast]; - oldestUsedDate = [NSDate distantFuture]; - mostRecentDictionary = nil; - optedOut = NO; - - // The array of SecureUDID pasteboards can be sparse, since any number of - // apps may have been deleted. To find a pasteboard owned by the the current - // domain, iterate all of them. - for (NSInteger i = 0; i < SUUID_MAX_STORAGE_LOCATIONS; ++i) { - NSDate* modifiedDate; - NSDictionary* dictionary; - - dictionary = SUUIDDictionaryForStorageLocation(i); - if (!dictionary) { - if (lowestUnusedIndex == -1) { - lowestUnusedIndex = i; - } - - continue; - } - - // Check the 'modified' timestamp of this pasteboard - modifiedDate = [dictionary valueForKey:SUUIDTimeStampKey]; - optedOut = optedOut || [[dictionary valueForKey:SUUIDOptOutKey] boolValue]; - - // Hold a copy of the data if this is the newest we've found so far. - if ([modifiedDate compare:mostRecentDate] == NSOrderedDescending) { - mostRecentDate = modifiedDate; - mostRecentDictionary = dictionary; - } - - // Check for the oldest entry in the structure, used for eviction - if ([modifiedDate compare:oldestUsedDate] == NSOrderedAscending) { - oldestUsedDate = modifiedDate; - oldestUsedIndex = i; - } - - // Finally, check if this is the pasteboard owned by the requesting domain. - if ([[dictionary objectForKey:SUUIDOwnerKey] isEqual:ownerKey]) { - ownerIndex = i; - } - } - - // If no pasteboard is owned by this domain, establish a new one to increase the - // likelihood of permanence. - if (ownerIndex == -1) { - // Unless there are no available slots, then evict the oldest entry - if ((lowestUnusedIndex < 0) || (lowestUnusedIndex >= SUUID_MAX_STORAGE_LOCATIONS)) { - ownerIndex = oldestUsedIndex; - } else { - ownerIndex = lowestUnusedIndex; - } - } - - // pass back the dictionary, by reference - *ownerDictionary = [NSMutableDictionary dictionaryWithDictionary:mostRecentDictionary]; - - // make sure our Opt-Out flag is consistent - if (optedOut) { - [*ownerDictionary setObject:[NSNumber numberWithBool:YES] forKey:SUUIDOptOutKey]; - } - - // Make sure to write the most recent structure to the new location - SUUIDWriteDictionaryToStorageLocation(ownerIndex, mostRecentDictionary); - - return ownerIndex; -} - -/* - Attempts to validate the full SecureUDID structure. - */ -BOOL SUUIDValidTopLevelObject(id object) { - if (![object isKindOfClass:[NSDictionary class]]) { - return NO; - } - - // Now, we need to verify the current schema. There are a few possible valid states: - // - SUUIDTimeStampKey + SUUIDOwnerKey + at least one additional key that is not SUUIDOptOutKey - // - SUUIDTimeStampKey + SUUIDOwnerKey + SUUIDOptOutKey - - if ([(NSDictionary *)object objectForKey:SUUIDTimeStampKey] && [(NSDictionary *)object objectForKey:SUUIDOwnerKey]) { - NSMutableDictionary* ownersOnlyDictionary; - NSData* ownerField; - - if ([(NSDictionary *)object objectForKey:SUUIDOptOutKey]) { - return YES; - } - - // We have to trust future schema versions. Note that the lack of a schema version key will - // always fail this check, since the first schema version was 1. - if ([[(NSDictionary *)object objectForKey:SUUIDSchemaVersionKey] intValue] > SUUID_SCHEMA_VERSION) { - return YES; - } - - ownerField = [(NSDictionary *)object objectForKey:SUUIDOwnerKey]; - if (![ownerField isKindOfClass:[NSData class]]) { - return NO; - } - - ownersOnlyDictionary = [NSMutableDictionary dictionaryWithDictionary:object]; - - [ownersOnlyDictionary removeObjectForKey:SUUIDTimeStampKey]; - [ownersOnlyDictionary removeObjectForKey:SUUIDOwnerKey]; - [ownersOnlyDictionary removeObjectForKey:SUUIDOptOutKey]; - [ownersOnlyDictionary removeObjectForKey:SUUIDModelHashKey]; - [ownersOnlyDictionary removeObjectForKey:SUUIDSchemaVersionKey]; - - // now, iterate through to verify each internal structure - for (id key in [ownersOnlyDictionary allKeys]) { - if ([key isEqual:SUUIDTimeStampKey] || [key isEqual:SUUIDOwnerKey] || [key isEqual:SUUIDOptOutKey]) - continue; - - if (![key isKindOfClass:[NSData class]]) { - return NO; - } - - if (!SUUIDValidOwnerObject([ownersOnlyDictionary objectForKey:key])) { - return NO; - } - } - - // if all these tests pass, this structure is valid - return YES; - } - - // Maybe just the SUUIDOptOutKey, on its own - if ([[(NSDictionary *)object objectForKey:SUUIDOptOutKey] boolValue] == YES) { - return YES; - } - - return NO; -} - -/* - Attempts to validate the structure for an "owner dictionary". - */ -BOOL SUUIDValidOwnerObject(id object) { - if (![object isKindOfClass:[NSDictionary class]]) { - return NO; - } - - return [object valueForKey:SUUIDLastAccessedKey] && [object valueForKey:SUUIDIdentifierKey]; -} - -@end diff --git a/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js b/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js deleted file mode 100644 index be5fd39c..00000000 --- a/iOS/SecureDeviceIdentifier/www/SecureDeviceIdentifier.js +++ /dev/null @@ -1,42 +0,0 @@ -// -// SecureDeviceIdentifier.js -// -// Created by Olivier Louvignes on 05/31/2012. -// -// Copyright 2012 Olivier Louvignes. All rights reserved. -// MIT Licensed - -(function(cordova) { - - function SecureDeviceIdentifier() {} - - SecureDeviceIdentifier.prototype.get = function(options, callback) { - if(!options) options = {}; - var scope = options.scope || null; - delete options.scope; - - var service = 'SecureDeviceIdentifier', - action = 'get', - callbackId = service + (cordova.callbackId + 1); - - var config = { - domain: options.domain || 'com.example.myapp', - key: options.key || 'difficult-to-guess-key' - }; - - var _callback = function(result) { - if(typeof callback == 'function') callback.apply(scope, arguments); - }; - - return cordova.exec(_callback, _callback, service, action, [config]); - - }; - - cordova.addConstructor(function() { - if(!window.plugins) window.plugins = {}; - window.plugins.secureDeviceIdentifier = new SecureDeviceIdentifier(); - }); - -})(window.cordova || window.Cordova); - -/* DEBUG */ window.console.log('SecureDeviceIdentifier.js loaded...'); \ No newline at end of file From c3eff2f82805e6691775eb5d8e9fda9726ed3ceb Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:37:50 -0400 Subject: [PATCH 09/25] 20130731.7 --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitmodules b/.gitmodules index 8b47fbc2..8c9fe765 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,7 @@ url = https://github.com/cemerson/cordova-inappbrowser-ce.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier + url = https://github.com/cemerson/cordova-securedeviceidentifier.git?1 +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement url = https://github.com/cemerson/cordova-securedeviceidentifier.git From 0100230b46ea42cd9636bc0c49229d75872fc234 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:52:56 -0400 Subject: [PATCH 10/25] 20130731.9 --- iOS/PowerManagement | 1 + iOS/SecureDeviceIdentifier | 1 + 2 files changed, 2 insertions(+) create mode 160000 iOS/PowerManagement create mode 160000 iOS/SecureDeviceIdentifier diff --git a/iOS/PowerManagement b/iOS/PowerManagement new file mode 160000 index 00000000..273d3587 --- /dev/null +++ b/iOS/PowerManagement @@ -0,0 +1 @@ +Subproject commit 273d3587e4509e040456756583d0776ab52235e9 diff --git a/iOS/SecureDeviceIdentifier b/iOS/SecureDeviceIdentifier new file mode 160000 index 00000000..0fd64237 --- /dev/null +++ b/iOS/SecureDeviceIdentifier @@ -0,0 +1 @@ +Subproject commit 0fd64237b716a79aceccee84498fb5c95630169d From 14b3800ab82e8fd36a11aeba9a9ed269c627a36f Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:53:08 -0400 Subject: [PATCH 11/25] 20130731.10 --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8c9fe765..aec9e10b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,7 @@ url = https://github.com/cemerson/cordova-inappbrowser-ce.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier - url = https://github.com/cemerson/cordova-securedeviceidentifier.git?1 + url = https://github.com/cemerson/cordova-securedeviceidentifier.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement - url = https://github.com/cemerson/cordova-securedeviceidentifier.git + url = https://github.com/cemerson/cordova-powermanagement.git From 5b8dde5720f00569e9b1fe4e9b91f5a779966452 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 09:55:53 -0400 Subject: [PATCH 12/25] 20130731.12 --- iOS/Badge/Cordova 2.x/Badge.h | 23 - iOS/Badge/Cordova 2.x/Badge.js | 50 - iOS/Badge/Cordova 2.x/Badge.m | 18 - iOS/Badge/README.md | 13 - iOS/Badge/README_old.md | 34 - iOS/Badge/plugin.xml | 26 - iOS/Badge/src/ios/Badge.h | 17 - iOS/Badge/src/ios/Badge.m | 24 - iOS/Badge/www/badge.js | 40 - iOS/InAppBrowser/README.md | 28 - iOS/InAppBrowser/plugin.xml | 60 -- .../src/android/InAppBrowser.java | 832 --------------- iOS/InAppBrowser/src/blackberry10/README.md | 25 - iOS/InAppBrowser/src/ios/CDVInAppBrowser.h | 98 -- iOS/InAppBrowser/src/ios/CDVInAppBrowser.m | 958 ------------------ iOS/InAppBrowser/src/wp/InAppBrowser.cs | 277 ----- iOS/InAppBrowser/www/InAppBrowser.js | 98 -- iOS/PowerManagement | 1 - iOS/SecureDeviceIdentifier | 1 - 19 files changed, 2623 deletions(-) delete mode 100755 iOS/Badge/Cordova 2.x/Badge.h delete mode 100755 iOS/Badge/Cordova 2.x/Badge.js delete mode 100755 iOS/Badge/Cordova 2.x/Badge.m delete mode 100644 iOS/Badge/README.md delete mode 100644 iOS/Badge/README_old.md delete mode 100644 iOS/Badge/plugin.xml delete mode 100644 iOS/Badge/src/ios/Badge.h delete mode 100644 iOS/Badge/src/ios/Badge.m delete mode 100644 iOS/Badge/www/badge.js delete mode 100644 iOS/InAppBrowser/README.md delete mode 100644 iOS/InAppBrowser/plugin.xml delete mode 100644 iOS/InAppBrowser/src/android/InAppBrowser.java delete mode 100644 iOS/InAppBrowser/src/blackberry10/README.md delete mode 100644 iOS/InAppBrowser/src/ios/CDVInAppBrowser.h delete mode 100644 iOS/InAppBrowser/src/ios/CDVInAppBrowser.m delete mode 100644 iOS/InAppBrowser/src/wp/InAppBrowser.cs delete mode 100644 iOS/InAppBrowser/www/InAppBrowser.js delete mode 160000 iOS/PowerManagement delete mode 160000 iOS/SecureDeviceIdentifier diff --git a/iOS/Badge/Cordova 2.x/Badge.h b/iOS/Badge/Cordova 2.x/Badge.h deleted file mode 100755 index a3867f20..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import - -#ifdef CORDOVA_FRAMEWORK - #import -#else - #import "CDVPlugin.h" -#endif - -@interface Badge : CDVPlugin { -} - -- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options; - -@end diff --git a/iOS/Badge/Cordova 2.x/Badge.js b/iOS/Badge/Cordova 2.x/Badge.js deleted file mode 100755 index fc0441b1..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -/* - * Temporary Scope to contain the plugin. - * - More information here: - * https://github.com/apache/incubator-cordova-ios/blob/master/guides/Cordova%20Plugin%20Upgrade%20Guide.md - */ -(function(){ - - /* Get local ref to global PhoneGap/Cordova/cordova object for exec function. - - This increases the compatibility of the plugin. */ - var cordovaRef = window.PhoneGap || window.Cordova || window.cordova; // old to new fallbacks - - /* - * This class exposes the iPhone 'icon badge' functionality to JavaScript - * to add a number (with a red background) to each icon. - */ - function Badge() { } - - /** - * Positive integer sets the badge amount, 0 or negative removes it. - */ - Badge.prototype.set = function(options) { - cordovaRef.exec("Badge.setBadge", options); - }; - - /** - * Shorthand to set the badge to 0 and remove it. - */ - Badge.prototype.clear = function() { - cordovaRef.exec("Badge.setBadge", 0); - }; - - cordovaRef.addConstructor(function() { - if(!window.plugins) { - window.plugins = {}; - } - if(!window.plugins.badge) { - window.plugins.badge = new Badge(); - } - }); - -})(); /* End of Temporary Scope. */ \ No newline at end of file diff --git a/iOS/Badge/Cordova 2.x/Badge.m b/iOS/Badge/Cordova 2.x/Badge.m deleted file mode 100755 index 28b05a9e..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.m +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import "Badge.h" - -@implementation Badge - -- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options { - [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ badgeNumber objectAtIndex:0] intValue]]; -} - -@end \ No newline at end of file diff --git a/iOS/Badge/README.md b/iOS/Badge/README.md deleted file mode 100644 index 1d0f6b59..00000000 --- a/iOS/Badge/README.md +++ /dev/null @@ -1,13 +0,0 @@ -cordova-badge -============= - -Original version/notes here: -https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Badge - -##Install Plugin: -cordova plugin add https://github.com/cemerson/cordova-badge.git - -##Remove Plugin: -cordova plugin rm org.apache.cordova.plugins.Badge - -20130731.5 diff --git a/iOS/Badge/README_old.md b/iOS/Badge/README_old.md deleted file mode 100644 index 757c5839..00000000 --- a/iOS/Badge/README_old.md +++ /dev/null @@ -1,34 +0,0 @@ -// -// Cordova 1.6.1 iOS Badge Plugin -// -// Author: Michael Nachbaur -// - Adapted by: Simon Madine of The Angry Robot Zombie Factory 2010 -// - Updated by: Joseph Stuhr -// -// In the Cordova.plist section, you need to add the plugin with the key/pair value of: -// -// Badge Badge -// -// Code: -// To set the badge number: -// - window.plugins.badge.set(_amount); -// -// To clear the badge: -// - window.plugins.badge.set(0); -// - window.plugins.badge.clear(); -// -// ========================================================= - -License - -The MIT License - -Copyright (c) ???? Michael Nachbaur - - Adapted by Simon Madine of The Angry Robot Zombie Factory 2010 - - Updated by Joseph Stuhr 2012 - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/iOS/Badge/plugin.xml b/iOS/Badge/plugin.xml deleted file mode 100644 index be62a93a..00000000 --- a/iOS/Badge/plugin.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Badge - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Badge/src/ios/Badge.h b/iOS/Badge/src/ios/Badge.h deleted file mode 100644 index 2ae4821a..00000000 --- a/iOS/Badge/src/ios/Badge.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import -#import - -@interface Badge : CDVPlugin { -} -- (void)setBadge:(CDVInvokedUrlCommand*)command; - -@end \ No newline at end of file diff --git a/iOS/Badge/src/ios/Badge.m b/iOS/Badge/src/ios/Badge.m deleted file mode 100644 index 09c3fa0a..00000000 --- a/iOS/Badge/src/ios/Badge.m +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import "Badge.h" - -@implementation Badge - -- (void)setBadge:(CDVInvokedUrlCommand*)command { - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - dispatch_async(dispatch_get_main_queue(), ^(void) { - [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ command.arguments objectAtIndex:0] intValue]]; - }); - }); - -} - -@end \ No newline at end of file diff --git a/iOS/Badge/www/badge.js b/iOS/Badge/www/badge.js deleted file mode 100644 index aeb61eea..00000000 --- a/iOS/Badge/www/badge.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -* This code is adapted from the work of Michael Nachbaur -* by Simon Madine of The Angry Robot Zombie Factory -* - Converted to Cordova 1.6.1 by Joseph Stuhr. -* 2012-04-19 -* MIT licensed -* -*/ - (function(cordova) { - - /* - * This class exposes the iPhone 'icon badge' functionality to JavaScript - * to add a number (with a red background) to each icon. - */ - function Badge() { } - - /** - * Positive integer sets the badge amount, 0 or negative removes it. - */ - Badge.prototype.set = function(options) { - cordova.exec(null,null,"Badge", "setBadge", [options]); - }; - - /** - * Shorthand to set the badge to 0 and remove it. - */ - Badge.prototype.clear = function() { - cordova.exec(null,null,"Badge","setBadge",[0]); - }; - - cordova.addConstructor(function() { - if(!window.plugins) window.plugins = {}; - window.plugins.badge = new Badge(); - }); - -})(window.cordova || window.Cordova); - - -/* DEBUG */ window.console.log('badge.js loaded...'); - diff --git a/iOS/InAppBrowser/README.md b/iOS/InAppBrowser/README.md deleted file mode 100644 index 0eaffafa..00000000 --- a/iOS/InAppBrowser/README.md +++ /dev/null @@ -1,28 +0,0 @@ -cordova-plugin-inappbrowser ------------------------------ -To install this plugin, follow the [Command-line Interface Guide](http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface). - -If you are not using the Cordova Command-line Interface, follow [Using Plugman to Manage Plugins](http://cordova.apache.org/docs/en/edge/guide_plugin_ref_plugman.md.html). - -###Notes: -- Main reason I updated this plugin is to maintain the ability to specify Width/Height and Xposition/YPosition of my web views. I had it working in the Cordova 2.x world - but this updated version blew that all up so I had to go in and hack things up to get it working again. I am not an ace ObjC programmer by any stretch - so please share whatever adjustments, clean-up or polish suggestions if anyone has any! -- New parameters available with this version of InAppBrowser are as follows (example usage below: - - **vw,vh,vx,vy** (width, height, xpos, ypos). . - - **buttoncolorbg** (I got sick of that default blue button so now you can specifyc a html hex color for the button background. Maybe one day I'll add similar stuff for the other UI elements [toolbar, label colors etc]). -- For some reason CoreGraphics framework isn't being auto added to project (even thought its specified in the plugin.xml so it has to be manually added when using this plugin otherwise you'll get a build error. - -###Install Plugin -cordova plugins add https://github.com/cemerson/cordova-inappbrowser-ce.git - -###Remove Plugin -cordova plugins rm org.apache.cordova.core.inappbrowser-ce - -###Usage Examples: -####window.open() no options: - window.open('http://www.ign.com','_blank'); - -####window.open() with fancy options!: - window.open('http://www.ign.com','_blank','vw=568,vh=1004,vx=200,vy=0,buttoncolorbg=#BA8C3C'); - -####window.open() with PDFs - (nothing special to note here - same options from above apply) diff --git a/iOS/InAppBrowser/plugin.xml b/iOS/InAppBrowser/plugin.xml deleted file mode 100644 index f46f40c3..00000000 --- a/iOS/InAppBrowser/plugin.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - InAppBrowserCE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/InAppBrowser/src/android/InAppBrowser.java b/iOS/InAppBrowser/src/android/InAppBrowser.java deleted file mode 100644 index 581a4a08..00000000 --- a/iOS/InAppBrowser/src/android/InAppBrowser.java +++ /dev/null @@ -1,832 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ -package org.apache.cordova.core; - -import java.util.HashMap; -import java.util.StringTokenizer; - - -import org.apache.cordova.Config; -import org.apache.cordova.CordovaWebView; -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.LOG; -import org.apache.cordova.PluginResult; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Bundle; -import android.text.InputType; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.webkit.WebChromeClient; -import android.webkit.GeolocationPermissions.Callback; -import android.webkit.JsPromptResult; -import android.webkit.WebSettings; -import android.webkit.WebStorage; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; - -@SuppressLint("SetJavaScriptEnabled") -public class InAppBrowser extends CordovaPlugin { - - private static final String NULL = "null"; - protected static final String LOG_TAG = "InAppBrowser"; - private static final String SELF = "_self"; - private static final String SYSTEM = "_system"; - // private static final String BLANK = "_blank"; - private static final String EXIT_EVENT = "exit"; - private static final String LOCATION = "location"; - private static final String HIDDEN = "hidden"; - private static final String LOAD_START_EVENT = "loadstart"; - private static final String LOAD_STOP_EVENT = "loadstop"; - private static final String LOAD_ERROR_EVENT = "loaderror"; - private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption"; - private long MAX_QUOTA = 100 * 1024 * 1024; - - private Dialog dialog; - private WebView inAppWebView; - private EditText edittext; - private CallbackContext callbackContext; - private boolean showLocationBar = true; - private boolean openWindowHidden = false; - private String buttonLabel = "Done"; - - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. - * @param callbackId The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. - */ - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { - try { - if (action.equals("open")) { - this.callbackContext = callbackContext; - String url = args.getString(0); - String target = args.optString(1); - if (target == null || target.equals("") || target.equals(NULL)) { - target = SELF; - } - HashMap features = parseFeature(args.optString(2)); - - Log.d(LOG_TAG, "target = " + target); - - url = updateUrl(url); - String result = ""; - - // SELF - if (SELF.equals(target)) { - Log.d(LOG_TAG, "in self"); - // load in webview - if (url.startsWith("file://") || url.startsWith("javascript:") - || Config.isUrlWhiteListed(url)) { - this.webView.loadUrl(url); - } - //Load the dialer - else if (url.startsWith(WebView.SCHEME_TEL)) - { - try { - Intent intent = new Intent(Intent.ACTION_DIAL); - intent.setData(Uri.parse(url)); - this.cordova.getActivity().startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); - } - } - // load in InAppBrowser - else { - result = this.showWebPage(url, features); - } - } - // SYSTEM - else if (SYSTEM.equals(target)) { - Log.d(LOG_TAG, "in system"); - result = this.openExternal(url); - } - // BLANK - or anything else - else { - Log.d(LOG_TAG, "in blank"); - result = this.showWebPage(url, features); - } - - PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result); - pluginResult.setKeepCallback(true); - this.callbackContext.sendPluginResult(pluginResult); - } - else if (action.equals("close")) { - closeDialog(); - this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); - } - else if (action.equals("injectScriptCode")) { - String jsWrapper = null; - if (args.getBoolean(1)) { - jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId()); - } - injectDeferredObject(args.getString(0), jsWrapper); - } - else if (action.equals("injectScriptFile")) { - String jsWrapper; - if (args.getBoolean(1)) { - jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId()); - } else { - jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)"; - } - injectDeferredObject(args.getString(0), jsWrapper); - } - else if (action.equals("injectStyleCode")) { - String jsWrapper; - if (args.getBoolean(1)) { - jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId()); - } else { - jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)"; - } - injectDeferredObject(args.getString(0), jsWrapper); - } - else if (action.equals("injectStyleFile")) { - String jsWrapper; - if (args.getBoolean(1)) { - jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId()); - } else { - jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)"; - } - injectDeferredObject(args.getString(0), jsWrapper); - } - else if (action.equals("show")) { - Runnable runnable = new Runnable() { - @Override - public void run() { - dialog.show(); - } - }; - this.cordova.getActivity().runOnUiThread(runnable); - this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); - } - else { - return false; - } - } catch (JSONException e) { - this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); - } - return true; - } - - /** - * Inject an object (script or style) into the InAppBrowser WebView. - * - * This is a helper method for the inject{Script|Style}{Code|File} API calls, which - * provides a consistent method for injecting JavaScript code into the document. - * - * If a wrapper string is supplied, then the source string will be JSON-encoded (adding - * quotes) and wrapped using string formatting. (The wrapper string should have a single - * '%s' marker) - * - * @param source The source object (filename or script/style text) to inject into - * the document. - * @param jsWrapper A JavaScript string to wrap the source string in, so that the object - * is properly injected, or null if the source string is JavaScript text - * which should be executed directly. - */ - private void injectDeferredObject(String source, String jsWrapper) { - String scriptToInject; - if (jsWrapper != null) { - org.json.JSONArray jsonEsc = new org.json.JSONArray(); - jsonEsc.put(source); - String jsonRepr = jsonEsc.toString(); - String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1); - scriptToInject = String.format(jsWrapper, jsonSourceString); - } else { - scriptToInject = source; - } - // This action will have the side-effect of blurring the currently focused element - this.inAppWebView.loadUrl("javascript:" + scriptToInject); - } - - /** - * Put the list of features into a hash map - * - * @param optString - * @return - */ - private HashMap parseFeature(String optString) { - if (optString.equals(NULL)) { - return null; - } else { - HashMap map = new HashMap(); - StringTokenizer features = new StringTokenizer(optString, ","); - StringTokenizer option; - while(features.hasMoreElements()) { - option = new StringTokenizer(features.nextToken(), "="); - if (option.hasMoreElements()) { - String key = option.nextToken(); - if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) { - this.buttonLabel = option.nextToken(); - } else { - Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE; - map.put(key, value); - } - } - } - return map; - } - } - - /** - * Convert relative URL to full path - * - * @param url - * @return - */ - private String updateUrl(String url) { - Uri newUrl = Uri.parse(url); - if (newUrl.isRelative()) { - url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url; - } - return url; - } - - /** - * Display a new browser with the specified URL. - * - * @param url The url to load. - * @param usePhoneGap Load url in PhoneGap webview - * @return "" if ok, or error message. - */ - public String openExternal(String url) { - try { - Intent intent = null; - intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(url)); - this.cordova.getActivity().startActivity(intent); - return ""; - } catch (android.content.ActivityNotFoundException e) { - Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString()); - return e.toString(); - } - } - - /** - * Closes the dialog - */ - private void closeDialog() { - try { - this.inAppWebView.loadUrl("about:blank"); - JSONObject obj = new JSONObject(); - obj.put("type", EXIT_EVENT); - - sendUpdate(obj, false); - } catch (JSONException ex) { - Log.d(LOG_TAG, "Should never happen"); - } - - if (dialog != null) { - dialog.dismiss(); - } - } - - /** - * Checks to see if it is possible to go back one page in history, then does so. - */ - private void goBack() { - if (this.inAppWebView.canGoBack()) { - this.inAppWebView.goBack(); - } - } - - /** - * Checks to see if it is possible to go forward one page in history, then does so. - */ - private void goForward() { - if (this.inAppWebView.canGoForward()) { - this.inAppWebView.goForward(); - } - } - - /** - * Navigate to the new page - * - * @param url to load - */ - private void navigate(String url) { - InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); - - if (!url.startsWith("http") && !url.startsWith("file:")) { - this.inAppWebView.loadUrl("http://" + url); - } else { - this.inAppWebView.loadUrl(url); - } - this.inAppWebView.requestFocus(); - } - - - /** - * Should we show the location bar? - * - * @return boolean - */ - private boolean getShowLocationBar() { - return this.showLocationBar; - } - - /** - * Display a new browser with the specified URL. - * - * @param url The url to load. - * @param jsonObject - */ - public String showWebPage(final String url, HashMap features) { - // Determine if we should hide the location bar. - showLocationBar = true; - openWindowHidden = false; - if (features != null) { - Boolean show = features.get(LOCATION); - if (show != null) { - showLocationBar = show.booleanValue(); - } - Boolean hidden = features.get(HIDDEN); - if(hidden != null) { - openWindowHidden = hidden.booleanValue(); - } - } - - final CordovaWebView thatWebView = this.webView; - - // Create dialog in new thread - Runnable runnable = new Runnable() { - /** - * Convert our DIP units to Pixels - * - * @return int - */ - private int dpToPixels(int dipValue) { - int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, - (float) dipValue, - cordova.getActivity().getResources().getDisplayMetrics() - ); - - return value; - } - - public void run() { - // Let's create the main dialog - dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar); - dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog; - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - dialog.setCancelable(true); - dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - public void onDismiss(DialogInterface dialog) { - try { - JSONObject obj = new JSONObject(); - obj.put("type", EXIT_EVENT); - - sendUpdate(obj, false); - } catch (JSONException e) { - Log.d(LOG_TAG, "Should never happen"); - } - } - }); - - // Main container layout - LinearLayout main = new LinearLayout(cordova.getActivity()); - main.setOrientation(LinearLayout.VERTICAL); - - // Toolbar layout - RelativeLayout toolbar = new RelativeLayout(cordova.getActivity()); - toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44))); - toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2)); - toolbar.setHorizontalGravity(Gravity.LEFT); - toolbar.setVerticalGravity(Gravity.TOP); - - // Action Button Container layout - RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity()); - actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - actionButtonContainer.setHorizontalGravity(Gravity.LEFT); - actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL); - actionButtonContainer.setId(1); - - // Back button - Button back = new Button(cordova.getActivity()); - RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT); - back.setLayoutParams(backLayoutParams); - back.setContentDescription("Back Button"); - back.setId(2); - back.setText("<"); - back.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - goBack(); - } - }); - - // Forward button - Button forward = new Button(cordova.getActivity()); - RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2); - forward.setLayoutParams(forwardLayoutParams); - forward.setContentDescription("Forward Button"); - forward.setId(3); - forward.setText(">"); - forward.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - goForward(); - } - }); - - // Edit Text Box - edittext = new EditText(cordova.getActivity()); - RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1); - textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5); - edittext.setLayoutParams(textLayoutParams); - edittext.setId(4); - edittext.setSingleLine(true); - edittext.setText(url); - edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI); - edittext.setImeOptions(EditorInfo.IME_ACTION_GO); - edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE - edittext.setOnKeyListener(new View.OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - // If the event is a key-down event on the "enter" button - if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { - navigate(edittext.getText().toString()); - return true; - } - return false; - } - }); - - // Close button - Button close = new Button(cordova.getActivity()); - RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - close.setLayoutParams(closeLayoutParams); - forward.setContentDescription("Close Button"); - close.setId(5); - close.setText(buttonLabel); - close.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - closeDialog(); - } - }); - - // WebView - inAppWebView = new WebView(cordova.getActivity()); - inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView)); - WebViewClient client = new InAppBrowserClient(thatWebView, edittext); - inAppWebView.setWebViewClient(client); - WebSettings settings = inAppWebView.getSettings(); - settings.setJavaScriptEnabled(true); - settings.setJavaScriptCanOpenWindowsAutomatically(true); - settings.setBuiltInZoomControls(true); - settings.setPluginState(android.webkit.WebSettings.PluginState.ON); - - //Toggle whether this is enabled or not! - Bundle appSettings = cordova.getActivity().getIntent().getExtras(); - boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true); - if(enableDatabase) - { - String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath(); - settings.setDatabasePath(databasePath); - settings.setDatabaseEnabled(true); - } - settings.setDomStorageEnabled(true); - - inAppWebView.loadUrl(url); - inAppWebView.setId(6); - inAppWebView.getSettings().setLoadWithOverviewMode(true); - inAppWebView.getSettings().setUseWideViewPort(true); - inAppWebView.requestFocus(); - inAppWebView.requestFocusFromTouch(); - - // Add the back and forward buttons to our action button container layout - actionButtonContainer.addView(back); - actionButtonContainer.addView(forward); - - // Add the views to our toolbar - toolbar.addView(actionButtonContainer); - toolbar.addView(edittext); - toolbar.addView(close); - - // Don't add the toolbar if its been disabled - if (getShowLocationBar()) { - // Add our toolbar to our main view/layout - main.addView(toolbar); - } - - // Add our webview to our main view/layout - main.addView(inAppWebView); - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); - lp.copyFrom(dialog.getWindow().getAttributes()); - lp.width = WindowManager.LayoutParams.MATCH_PARENT; - lp.height = WindowManager.LayoutParams.MATCH_PARENT; - - dialog.setContentView(main); - dialog.show(); - dialog.getWindow().setAttributes(lp); - // the goal of openhidden is to load the url and not display it - // Show() needs to be called to cause the URL to be loaded - if(openWindowHidden) { - dialog.hide(); - } - } - }; - this.cordova.getActivity().runOnUiThread(runnable); - return ""; - } - - /** - * Create a new plugin success result and send it back to JavaScript - * - * @param obj a JSONObject contain event payload information - */ - private void sendUpdate(JSONObject obj, boolean keepCallback) { - sendUpdate(obj, keepCallback, PluginResult.Status.OK); - } - - /** - * Create a new plugin result and send it back to JavaScript - * - * @param obj a JSONObject contain event payload information - * @param status the status code to return to the JavaScript environment - */ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) { - PluginResult result = new PluginResult(status, obj); - result.setKeepCallback(keepCallback); - this.callbackContext.sendPluginResult(result); - } - - public class InAppChromeClient extends WebChromeClient { - - private CordovaWebView webView; - - public InAppChromeClient(CordovaWebView webView) { - super(); - this.webView = webView; - } - /** - * Handle database quota exceeded notification. - * - * @param url - * @param databaseIdentifier - * @param currentQuota - * @param estimatedSize - * @param totalUsedQuota - * @param quotaUpdater - */ - @Override - public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, - long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) - { - LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); - - if (estimatedSize < MAX_QUOTA) - { - //increase for 1Mb - long newQuota = estimatedSize; - LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota); - quotaUpdater.updateQuota(newQuota); - } - else - { - // Set the quota to whatever it is and force an error - // TODO: get docs on how to handle this properly - quotaUpdater.updateQuota(currentQuota); - } - } - - /** - * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. - * - * @param origin - * @param callback - */ - @Override - public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { - super.onGeolocationPermissionsShowPrompt(origin, callback); - callback.invoke(origin, true, false); - } - - /** - * Tell the client to display a prompt dialog to the user. - * If the client returns true, WebView will assume that the client will - * handle the prompt dialog and call the appropriate JsPromptResult method. - * - * The prompt bridge provided for the InAppBrowser is capable of executing any - * oustanding callback belonging to the InAppBrowser plugin. Care has been - * taken that other callbacks cannot be triggered, and that no other code - * execution is possible. - * - * To trigger the bridge, the prompt default value should be of the form: - * - * gap-iab:// - * - * where is the string id of the callback to trigger (something - * like "InAppBrowser0123456789") - * - * If present, the prompt message is expected to be a JSON-encoded value to - * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid. - * - * @param view - * @param url - * @param message - * @param defaultValue - * @param result - */ - @Override - public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { - // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute. - if (defaultValue != null && defaultValue.startsWith("gap-iab://")) { - PluginResult scriptResult; - String scriptCallbackId = defaultValue.substring(10); - if (scriptCallbackId.startsWith("InAppBrowser")) { - if(message == null || message.length() == 0) { - scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray()); - } else { - try { - scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message)); - } catch(JSONException e) { - scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()); - } - } - this.webView.sendPluginResult(scriptResult, scriptCallbackId); - result.confirm(""); - return true; - } - } - return false; - } - - } - - /** - * The webview client receives notifications about appView - */ - public class InAppBrowserClient extends WebViewClient { - EditText edittext; - CordovaWebView webView; - - /** - * Constructor. - * - * @param mContext - * @param edittext - */ - public InAppBrowserClient(CordovaWebView webView, EditText mEditText) { - this.webView = webView; - this.edittext = mEditText; - } - - /** - * Notify the host application that a page has started loading. - * - * @param view The webview initiating the callback. - * @param url The url of the page. - */ - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - super.onPageStarted(view, url, favicon); - String newloc = ""; - if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) { - newloc = url; - } - // If dialing phone (tel:5551212) - else if (url.startsWith(WebView.SCHEME_TEL)) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL); - intent.setData(Uri.parse(url)); - cordova.getActivity().startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); - } - } - - else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(url)); - cordova.getActivity().startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString()); - } - } - // If sms:5551212?body=This is the message - else if (url.startsWith("sms:")) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW); - - // Get address - String address = null; - int parmIndex = url.indexOf('?'); - if (parmIndex == -1) { - address = url.substring(4); - } - else { - address = url.substring(4, parmIndex); - - // If body, then set sms body - Uri uri = Uri.parse(url); - String query = uri.getQuery(); - if (query != null) { - if (query.startsWith("body=")) { - intent.putExtra("sms_body", query.substring(5)); - } - } - } - intent.setData(Uri.parse("sms:" + address)); - intent.putExtra("address", address); - intent.setType("vnd.android-dir/mms-sms"); - cordova.getActivity().startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString()); - } - } - else { - newloc = "http://" + url; - } - - if (!newloc.equals(edittext.getText().toString())) { - edittext.setText(newloc); - } - - try { - JSONObject obj = new JSONObject(); - obj.put("type", LOAD_START_EVENT); - obj.put("url", newloc); - - sendUpdate(obj, true); - } catch (JSONException ex) { - Log.d(LOG_TAG, "Should never happen"); - } - } - - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); - - try { - JSONObject obj = new JSONObject(); - obj.put("type", LOAD_STOP_EVENT); - obj.put("url", url); - - sendUpdate(obj, true); - } catch (JSONException ex) { - Log.d(LOG_TAG, "Should never happen"); - } - } - - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - super.onReceivedError(view, errorCode, description, failingUrl); - - try { - JSONObject obj = new JSONObject(); - obj.put("type", LOAD_ERROR_EVENT); - obj.put("url", failingUrl); - obj.put("code", errorCode); - obj.put("message", description); - - sendUpdate(obj, true, PluginResult.Status.ERROR); - } catch (JSONException ex) { - Log.d(LOG_TAG, "Should never happen"); - } - - } - } -} diff --git a/iOS/InAppBrowser/src/blackberry10/README.md b/iOS/InAppBrowser/src/blackberry10/README.md deleted file mode 100644 index 0b167897..00000000 --- a/iOS/InAppBrowser/src/blackberry10/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# BlackBerry 10 In-App-Browser Plugin - -The in app browser functionality is entirely contained within common js. There is no native implementation required. -To install this plugin, follow the [Command-line Interface Guide](http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface). - -If you are not using the Cordova Command-line Interface, follow [Using Plugman to Manage Plugins](http://cordova.apache.org/docs/en/edge/guide_plugin_ref_plugman.md.html). -./cordova-plugin-battery-status/README.md -./cordova-plugin-camera/README.md -./cordova-plugin-console/README.md -./cordova-plugin-contacts/README.md -./cordova-plugin-device/README.md -./cordova-plugin-device-motion/README.md -./cordova-plugin-device-orientation/README.md -./cordova-plugin-device-orientation/src/blackberry10/README.md -./cordova-plugin-file/README.md -./cordova-plugin-file-transfer/README.md -./cordova-plugin-geolocation/README.md -./cordova-plugin-globalization/README.md -./cordova-plugin-inappbrowser/README.md -./cordova-plugin-inappbrowser/src/blackberry10/README.md -./cordova-plugin-media/README.md -./cordova-plugin-media-capture/README.md -./cordova-plugin-network-information/README.md -./cordova-plugin-splashscreen/README.md -./cordova-plugin-vibration/README.md diff --git a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h deleted file mode 100644 index b79e2e60..00000000 --- a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import -#import -#import -#import - -@class CDVInAppBrowserViewController; - -@interface CDVInAppBrowser : CDVPlugin { - BOOL _injectedIframeBridge; -} - -@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController; -@property (nonatomic, copy) NSString* callbackId; - -- (void)open:(CDVInvokedUrlCommand*)command; -- (void)close:(CDVInvokedUrlCommand*)command; -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command; -- (void)show:(CDVInvokedUrlCommand*)command; - -@end - -@interface CDVInAppBrowserViewController : UIViewController { -@private - NSString* _userAgent; - NSString* _prevUserAgent; - NSInteger _userAgentLockToken; - CDVWebViewDelegate* _webViewDelegate; -} - -@property (nonatomic, strong) IBOutlet UIWebView* webView; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton; -@property (nonatomic, strong) IBOutlet UILabel* addressLabel; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton; -@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton; -@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner; -@property (nonatomic, strong) IBOutlet UIToolbar* toolbar; - -@property (nonatomic, weak) id orientationDelegate; -@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate; -@property (nonatomic) NSURL* currentURL; - -- (void)close; -- (void)navigateTo:(NSURL*)url; -- (void)showLocationBar:(BOOL)show; -- (void)showToolBar:(BOOL)show; - -/* cemerson */ // added buttonBGColor parameter -- (void)setCloseButtonTitle:(NSString*)title buttonBGColor:(UIColor*)buttonBGColor; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent; - -@end - -@interface CDVInAppBrowserOptions : NSObject {} - -@property (nonatomic, assign) BOOL location; -@property (nonatomic, assign) BOOL toolbar; -@property (nonatomic, copy) NSString* closebuttoncaption; - -@property (nonatomic, copy) NSString* presentationstyle; -@property (nonatomic, copy) NSString* transitionstyle; - -@property (nonatomic, assign) BOOL enableviewportscale; -@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction; -@property (nonatomic, assign) BOOL allowinlinemediaplayback; -@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction; -@property (nonatomic, assign) BOOL suppressesincrementalrendering; -@property (nonatomic, assign) BOOL hidden; - -/* cemerson */ @property (nonatomic, assign) CGFloat vw; -/* cemerson */ @property (nonatomic, assign) CGFloat vh; -/* cemerson */ @property (nonatomic, assign) CGFloat vx; -/* cemerson */ @property (nonatomic, assign) CGFloat vy; -/* cemerson */ @property (nonatomic, assign) NSString* buttoncolorbg; - - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options; - -@end \ No newline at end of file diff --git a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m b/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m deleted file mode 100644 index d1a5aa4d..00000000 --- a/iOS/InAppBrowser/src/ios/CDVInAppBrowser.m +++ /dev/null @@ -1,958 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import "CDVInAppBrowser.h" -#import -#import -#import - -#define kInAppBrowserTargetSelf @"_self" -#define kInAppBrowserTargetSystem @"_system" -#define kInAppBrowserTargetBlank @"_blank" - -#define TOOLBAR_HEIGHT 44.0 -#define LOCATIONBAR_HEIGHT 21.0 -#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT)) -#define BUTTON_BACKGROUND_COLOR @"#448EE3" -#define CLOSE_BUTTON_LABEL @"Done" - -#pragma mark CDVInAppBrowser - -CDVInAppBrowserViewController *vc; -CDVInAppBrowserViewController *iabvc; - -BOOL WINDOWED_MODE_SPECIFIED = NO; - -@implementation CDVInAppBrowser - -- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView -{ - self = [super initWithWebView:theWebView]; - if (self != nil) { - // your initialization here - } - - return self; -} - -- (void)onReset -{ - [self close:nil]; -} - -- (void)close:(CDVInvokedUrlCommand*)command -{ - if (self.inAppBrowserViewController != nil) { - [self.inAppBrowserViewController close]; - self.inAppBrowserViewController = nil; - } - - self.callbackId = nil; -} - -- (BOOL) isSystemUrl:(NSURL*)url -{ - if ([[url host] isEqualToString:@"itunes.apple.com"]) { - return YES; - } - - return NO; -} - -- (void)open:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult; - - NSString* url = [command argumentAtIndex:0]; - NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf]; - NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]]; - - if ( - ([options rangeOfString:@"vx"].location == NSNotFound) && - ([options rangeOfString:@"vy"].location == NSNotFound) && - ([options rangeOfString:@"vw"].location == NSNotFound) && - ([options rangeOfString:@"vh"].location == NSNotFound) - ){ - WINDOWED_MODE_SPECIFIED = NO; - }else{ - WINDOWED_MODE_SPECIFIED = YES; - } - - NSLog(@"PLUGIN: InAppBrowser.open()...{WINDOWED_MODE_SPECIFIED:%i} [CDVInAppBrowser.m]", WINDOWED_MODE_SPECIFIED); - - self.callbackId = command.callbackId; - - if (url != nil) { - NSURL* baseUrl = [self.webView.request URL]; - NSURL* absoluteUrl = [[NSURL URLWithString:url relativeToURL:baseUrl] absoluteURL]; - - if ([self isSystemUrl:absoluteUrl]) { - target = kInAppBrowserTargetSystem; - } - - if ([target isEqualToString:kInAppBrowserTargetSelf]) { - [self openInCordovaWebView:absoluteUrl withOptions:options]; - } else if ([target isEqualToString:kInAppBrowserTargetSystem]) { - [self openInSystem:absoluteUrl]; - } else { // _blank or anything else - [self openInInAppBrowser:absoluteUrl withOptions:options]; - } - - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"incorrect number of arguments"]; - } - - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options -{ - - if (self.inAppBrowserViewController == nil) { - NSString* originalUA = [CDVUserAgentUtil originalUserAgent]; - self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]]; - self.inAppBrowserViewController.navigationDelegate = self; - - if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) { - self.inAppBrowserViewController.orientationDelegate = (UIViewController *)self.viewController; - } - } - - /* cemerson */ // set pointer to this viewcontroller for later use - /* cemerson */iabvc = self.inAppBrowserViewController; - - CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options]; - [self.inAppBrowserViewController showLocationBar:browserOptions.location]; - [self.inAppBrowserViewController showToolBar:browserOptions.toolbar]; - - /* cemerson */ // abstract this out into a standalone method? - NSString *stringColor = browserOptions.buttoncolorbg; - NSUInteger red, green, blue; - sscanf([stringColor UTF8String], "#%02X%02X%02X", &red, &green, &blue); - UIColor *buttonbg = [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1]; - - /* cemerson */ // for now calling setCloseButtonTitle() either way to make sure button gets colored - if (browserOptions.closebuttoncaption != nil) { - [self.inAppBrowserViewController setCloseButtonTitle:browserOptions.closebuttoncaption buttonBGColor:buttonbg]; - }else{ - [self.inAppBrowserViewController setCloseButtonTitle:@"Done" buttonBGColor:buttonbg]; - } - - // Set Presentation Style - UIModalPresentationStyle presentationStyle = UIModalPresentationFullScreen; // default - if (browserOptions.presentationstyle != nil) { - if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"pagesheet"]) { - presentationStyle = UIModalPresentationPageSheet; - } else if ([[browserOptions.presentationstyle lowercaseString] isEqualToString:@"formsheet"]) { - presentationStyle = UIModalPresentationFormSheet; - } - } - // NSLog(@"PLUGIN: InAppBrowser.presentationStyle = %@",browserOptions.presentationstyle); - self.inAppBrowserViewController.modalPresentationStyle = presentationStyle; - - // Set Transition Style - UIModalTransitionStyle transitionStyle = UIModalTransitionStyleCoverVertical; // default - if (browserOptions.transitionstyle != nil) { - if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"fliphorizontal"]) { - transitionStyle = UIModalTransitionStyleFlipHorizontal; - } else if ([[browserOptions.transitionstyle lowercaseString] isEqualToString:@"crossdissolve"]) { - transitionStyle = UIModalTransitionStyleCrossDissolve; - } - } - self.inAppBrowserViewController.modalTransitionStyle = transitionStyle; - - // UIWebView options - self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale; - self.inAppBrowserViewController.webView.mediaPlaybackRequiresUserAction = browserOptions.mediaplaybackrequiresuseraction; - self.inAppBrowserViewController.webView.allowsInlineMediaPlayback = browserOptions.allowinlinemediaplayback; - if (IsAtLeastiOSVersion(@"6.0")) { - self.inAppBrowserViewController.webView.keyboardDisplayRequiresUserAction = browserOptions.keyboarddisplayrequiresuseraction; - self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering; - } - - if (! browserOptions.hidden) { - if (self.viewController.modalViewController != self.inAppBrowserViewController) { - - if(WINDOWED_MODE_SPECIFIED){ - //NSLog(@"PLUGIN: InAppBrowser: addSubView Mode"); - - /*cemerson*/ // NEW addSubView APPROACH - /*cemerson*/ vc = (CDVInAppBrowserViewController*)[ super viewController ]; - CGRect vcBoundsInit = CGRectMake(browserOptions.vx, - browserOptions.vh, - browserOptions.vw, - browserOptions.vh); - /*cemerson*/ CGRect vcBounds = CGRectMake(browserOptions.vx, - browserOptions.vy, - browserOptions.vw, - browserOptions.vh); - - /*cemerson*/ // if formsheet mode we dont mess with the frame - /*cemerson*/ iabvc.view.frame = vcBoundsInit; - - /*cemerson*/ iabvc.webView.scalesPageToFit = YES; - /*cemerson*/ [iabvc viewWillAppear:NO]; - /*cemerson*/ [vc.self.view addSubview:iabvc.view]; - - /*cemerson*/ // view animation - [UIView beginAnimations:nil context:nil]; - [UIView setAnimationDuration:0.25]; - [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; - - /*cemerson*/ iabvc.view.frame = vcBounds; - /*cemerson*/ [UIView commitAnimations]; - }else{ - /*cemerson*/ // OLD presentModalViewController APPROACH - //NSLog(@"PLUGIN: InAppBrowser: presentModalViewController Mode"); - [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; - } - - - } - } - [self.inAppBrowserViewController navigateTo:url]; -} - -//- (BOOL)webView:(UIWebView*)theWebView should -- (UIColor*)getUIColorFromHTMLHexColorString: (NSString*)htmlColorString{ - NSString *stringColor = htmlColorString; - NSUInteger red, green, blue; - sscanf([stringColor UTF8String], "#%02X%02X%02X", &red, &green, &blue); - - UIColor *buttonbg = [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1]; - - return buttonbg; - -} - -- (void)show:(CDVInvokedUrlCommand*)command -{ - if ([self.inAppBrowserViewController isViewLoaded] && self.inAppBrowserViewController.view.window) - return; - [self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES]; -} - -- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options -{ - if ([self.commandDelegate URLIsWhitelisted:url]) { - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - [self.webView loadRequest:request]; - } else { // this assumes the InAppBrowser can be excepted from the white-list - [self openInInAppBrowser:url withOptions:options]; - } -} - -- (void)openInSystem:(NSURL*)url -{ - if ([[UIApplication sharedApplication] canOpenURL:url]) { - [[UIApplication sharedApplication] openURL:url]; - } else { // handle any custom schemes to plugins - [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; - } -} - -// This is a helper method for the inject{Script|Style}{Code|File} API calls, which -// provides a consistent method for injecting JavaScript code into the document. -// -// If a wrapper string is supplied, then the source string will be JSON-encoded (adding -// quotes) and wrapped using string formatting. (The wrapper string should have a single -// '%@' marker). -// -// If no wrapper is supplied, then the source string is executed directly. - -- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper -{ - if (!_injectedIframeBridge) { - _injectedIframeBridge = YES; - // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"]; - } - - if (jsWrapper != nil) { - NSString* sourceArrayString = [@[source] JSONString]; - if (sourceArrayString) { - NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)]; - NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString]; - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject]; - } - } else { - [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source]; - } -} - -- (void)injectScriptCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper = nil; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId]; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectScriptFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleCode:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -- (void)injectStyleFile:(CDVInvokedUrlCommand*)command -{ - NSString* jsWrapper; - - if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) { - jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId]; - } else { - jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)"; - } - [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper]; -} - -/** - * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging - * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no - * other code execution is possible. - * - * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form: - * - * gap-iab:/// - * - * where is the string id of the callback to trigger (something like "InAppBrowser0123456789") - * - * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded - * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION - * is returned if the JSON is invalid. - */ -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSURL* url = request.URL; - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute, - // and the path, if present, should be a JSON-encoded value to pass to the callback. - if ([[url scheme] isEqualToString:@"gap-iab"]) { - NSString* scriptCallbackId = [url host]; - CDVPluginResult* pluginResult = nil; - - if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) { - NSString* scriptResult = [url path]; - NSError* __autoreleasing error = nil; - - // The message should be a JSON-encoded array of the result of the script which executed. - if ((scriptResult != nil) && ([scriptResult length] > 1)) { - scriptResult = [scriptResult substringFromIndex:1]; - NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION]; - } - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId]; - return NO; - } - } else if ((self.callbackId != nil) && isTopLevelNavigation) { - // Send a loadstart event for each top-level navigation (includes redirects). - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } - - return YES; -} - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - _injectedIframeBridge = NO; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - if (self.callbackId != nil) { - - /* cemerson */ // if you CLOSE the web view before it finishes loading sometimes it throws and error - if(self.inAppBrowserViewController.currentURL.absoluteString == nil){ - NSLog(@" webViewDidFinishLoad() WARNING: *absoluteString is nil! Did you close the web view before it finished loading?"); - return; - } - - // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected). - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"loadstop", @"url":url}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - if (self.callbackId != nil) { - NSString* url = [self.inAppBrowserViewController.currentURL absoluteString]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - } -} - -- (void)browserExit -{ - if (self.callbackId != nil) { - - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK - messageAsDictionary:@{@"type":@"exit"}]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; - - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; - - // NSLog(@"PLUGIN: InAppBrowser.browserExit(pluginResult: %@)... [CDVInAppBrowser.m]", pluginResult); - - } - // Don't recycle the ViewController since it may be consuming a lot of memory. - // Also - this is required for the PDF/User-Agent bug work-around. - self.inAppBrowserViewController = nil; -} - -@end - -#pragma mark CDVInAppBrowserViewController - -@implementation CDVInAppBrowserViewController - -@synthesize currentURL; - -- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent -{ - self = [super init]; - - if (self != nil) { - _userAgent = userAgent; - _prevUserAgent = prevUserAgent; - _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self]; - [self createViews]; - } - - return self; -} - -- (void)createViews -{ - // We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included - - /*cemerson*/ // inherit frame of parent view - CGRect webViewBounds = CGRectMake(0, - 0, - self.view.frame.size.width, - self.view.frame.size.height); - - webViewBounds.size.height -= FOOTER_HEIGHT; - - self.webView.scalesPageToFit = YES; - - self.webView = [[UIWebView alloc] initWithFrame:webViewBounds]; - - [self.view addSubview:self.webView]; - [self.view sendSubviewToBack:self.webView]; - - self.webView.delegate = _webViewDelegate; - self.webView.backgroundColor = [UIColor clearColor]; - - self.webView.clearsContextBeforeDrawing = YES; - self.webView.clipsToBounds = YES; - self.webView.contentMode = UIViewContentModeScaleToFill; - self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.webView.multipleTouchEnabled = YES; - /* cemerson */ // set webView to transparent so the transition animation is actually covering up the app - /* cemerson */ self.webView.opaque = NO; - self.webView.scalesPageToFit = NO; - self.webView.userInteractionEnabled = YES; - - self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; - self.spinner.alpha = 1.000; - self.spinner.autoresizesSubviews = YES; - self.spinner.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; - self.spinner.clearsContextBeforeDrawing = NO; - self.spinner.clipsToBounds = NO; - self.spinner.contentMode = UIViewContentModeScaleToFill; - self.spinner.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.spinner.frame = CGRectMake(454.0, 231.0, 20.0, 20.0); - self.spinner.hidden = YES; - self.spinner.hidesWhenStopped = YES; - self.spinner.multipleTouchEnabled = NO; - self.spinner.opaque = NO; - self.spinner.userInteractionEnabled = NO; - [self.spinner stopAnimating]; - - self.closeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(close)]; - self.closeButton.enabled = YES; - - UIBarButtonItem* flexibleSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - - UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; - fixedSpaceButton.width = 20; - - self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, (self.view.bounds.size.height - TOOLBAR_HEIGHT), self.view.bounds.size.width, TOOLBAR_HEIGHT)]; - self.toolbar.alpha = 1.000; - self.toolbar.autoresizesSubviews = YES; - self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; - self.toolbar.barStyle = UIBarStyleBlackOpaque; - self.toolbar.clearsContextBeforeDrawing = NO; - self.toolbar.clipsToBounds = NO; - self.toolbar.contentMode = UIViewContentModeScaleToFill; - self.toolbar.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.toolbar.hidden = NO; - self.toolbar.multipleTouchEnabled = NO; - self.toolbar.opaque = NO; - self.toolbar.userInteractionEnabled = YES; - - CGFloat labelInset = 5.0; - self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, (self.view.bounds.size.height - FOOTER_HEIGHT), self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)]; - self.addressLabel.adjustsFontSizeToFitWidth = NO; - self.addressLabel.alpha = 1.000; - self.addressLabel.autoresizesSubviews = YES; - self.addressLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; - self.addressLabel.backgroundColor = [UIColor clearColor]; - self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; - self.addressLabel.clearsContextBeforeDrawing = YES; - self.addressLabel.clipsToBounds = YES; - self.addressLabel.contentMode = UIViewContentModeScaleToFill; - self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}"); - self.addressLabel.enabled = YES; - self.addressLabel.hidden = NO; - self.addressLabel.lineBreakMode = UILineBreakModeTailTruncation; - self.addressLabel.minimumFontSize = 10.000; - self.addressLabel.multipleTouchEnabled = NO; - self.addressLabel.numberOfLines = 1; - self.addressLabel.opaque = NO; - self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0); - self.addressLabel.text = @"Loading..."; - self.addressLabel.textAlignment = UITextAlignmentLeft; - self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000]; - self.addressLabel.userInteractionEnabled = NO; - - NSString* frontArrowString = @"►"; // create arrow from Unicode char - self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)]; - self.forwardButton.enabled = YES; - self.forwardButton.imageInsets = UIEdgeInsetsZero; - - NSString* backArrowString = @"◄"; // create arrow from Unicode char - self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)]; - self.backButton.enabled = YES; - self.backButton.imageInsets = UIEdgeInsetsZero; - - [self.toolbar setItems:@[self.closeButton, flexibleSpaceButton, self.backButton, fixedSpaceButton, self.forwardButton]]; - - /* cemerson */ self.view.backgroundColor = [UIColor grayColor]; - /* cemerson */ self.view.opaque = YES; - - [self.view addSubview:self.toolbar]; - [self.view addSubview:self.addressLabel]; - [self.view addSubview:self.spinner]; -} - -/* cemerson */ // added buttonBGColor parameter -- (void)setCloseButtonTitle:(NSString*)title buttonBGColor:(UIColor*)buttonBGColor -{ - //NSLog(@"setCloseButtonTitle() color:%@", buttonBGColor); - // the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically - // but, if you want to set this yourself, knock yourself out (we can't set the title for a system Done button, so we have to create a new one) - self.closeButton = nil; - self.closeButton = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStyleBordered target:self action:@selector(close)]; - self.closeButton.enabled = YES; - - self.closeButton.tintColor = buttonBGColor; - - NSMutableArray* items = [self.toolbar.items mutableCopy]; - [items replaceObjectAtIndex:0 withObject:self.closeButton]; - [self.toolbar setItems:items]; -} - -- (void)showLocationBar:(BOOL)show -{ - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL toolbarVisible = !self.toolbar.hidden; - - // prevent double show/hide - if (show == !(self.addressLabel.hidden)) { - return; - } - - if (show) { - self.addressLabel.hidden = NO; - - if (toolbarVisible) { - // toolBar at the bottom, leave as is - // put locationBar on top of the toolBar - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= FOOTER_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no toolBar, so put locationBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } - } else { - self.addressLabel.hidden = YES; - - if (toolbarVisible) { - // locationBar is on top of toolBar, hide locationBar - - // webView take up whole height less toolBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - self.webView.frame = webViewBounds; - } else { - // no toolBar, expand webView to screen dimensions - - CGRect webViewBounds = self.view.bounds; - self.webView.frame = webViewBounds; - } - } -} - -- (void)showToolBar:(BOOL)show -{ - CGRect toolbarFrame = self.toolbar.frame; - CGRect locationbarFrame = self.addressLabel.frame; - - BOOL locationbarVisible = !self.addressLabel.hidden; - - // prevent double show/hide - if (show == !(self.toolbar.hidden)) { - return; - } - - if (show) { - self.toolbar.hidden = NO; - - if (locationbarVisible) { - // locationBar at the bottom, move locationBar up - // put toolBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= FOOTER_HEIGHT; - self.webView.frame = webViewBounds; - - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - - toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT); - self.toolbar.frame = toolbarFrame; - } else { - // no locationBar, so put toolBar at the bottom - - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= TOOLBAR_HEIGHT; - self.webView.frame = webViewBounds; - - toolbarFrame.origin.y = webViewBounds.size.height; - self.toolbar.frame = toolbarFrame; - } - } else { - self.toolbar.hidden = YES; - - if (locationbarVisible) { - // locationBar is on top of toolBar, hide toolBar - // put locationBar at the bottom - - // webView take up whole height less locationBar height - CGRect webViewBounds = self.view.bounds; - webViewBounds.size.height -= LOCATIONBAR_HEIGHT; - self.webView.frame = webViewBounds; - - // move locationBar down - locationbarFrame.origin.y = webViewBounds.size.height; - self.addressLabel.frame = locationbarFrame; - } else { - // no locationBar, expand webView to screen dimensions - - CGRect webViewBounds = self.view.bounds; - self.webView.frame = webViewBounds; - } - } -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; -} - -- (void)viewDidUnload -{ - [self.webView loadHTMLString:nil baseURL:nil]; - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - [super viewDidUnload]; -} - -- (void)close -{ - [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; - - /* cemerson */ // TODO: prevent throwing error when closing before web page finished loading (??) - - /* cemerson */ // OLD close actions - if ([self respondsToSelector:@selector(presentingViewController)]) { - [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } else { - [[self parentViewController] dismissModalViewControllerAnimated:YES]; - } - - self.currentURL = nil; - - if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) { - [self.navigationDelegate browserExit]; - } - - /* cemerson */ // if windowsModeSpecified we assume addSubView was used - if(WINDOWED_MODE_SPECIFIED){ - [iabvc.view removeFromSuperview]; - } - - NSLog(@"PLUGIN: InAppBrowser.close()... [CDVInAppBrowser.m]"); - - -} - -- (void)navigateTo:(NSURL*)url -{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; - - if (_userAgentLockToken != 0) { - [self.webView loadRequest:request]; - } else { - [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { - _userAgentLockToken = lockToken; - [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken]; - [self.webView loadRequest:request]; - }]; - } -} - -- (void)goBack:(id)sender -{ - [self.webView goBack]; -} - -- (void)goForward:(id)sender -{ - [self.webView goForward]; -} - -#pragma mark UIWebViewDelegate - -- (void)webViewDidStartLoad:(UIWebView*)theWebView -{ - // loading url, start spinner, update back/forward - - self.addressLabel.text = @"Loading..."; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner startAnimating]; - - return [self.navigationDelegate webViewDidStartLoad:theWebView]; -} - -- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType -{ - BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]]; - - if (isTopLevelNavigation) { - self.currentURL = request.URL; - } - return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType]; -} - -- (void)webViewDidFinishLoad:(UIWebView*)theWebView -{ - // update url, stop spinner, update back/forward - - self.addressLabel.text = [self.currentURL absoluteString]; - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - - [self.spinner stopAnimating]; - - // Work around a bug where the first time a PDF is opened, all UIWebViews - // reload their User-Agent from NSUserDefaults. - // This work-around makes the following assumptions: - // 1. The app has only a single Cordova Webview. If not, then the app should - // take it upon themselves to load a PDF in the background as a part of - // their start-up flow. - // 2. That the PDF does not require any additional network requests. We change - // the user-agent here back to that of the CDVViewController, so requests - // from it must pass through its white-list. This *does* break PDFs that - // contain links to other remote PDF/websites. - // More info at https://issues.apache.org/jira/browse/CB-2225 - BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]]; - if (isPDF) { - [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken]; - } - - [self.navigationDelegate webViewDidFinishLoad:theWebView]; -} - -- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error -{ - // log fail message, stop spinner, update back/forward - NSLog(@"webView:didFailLoadWithError - %@", [error localizedDescription]); - - self.backButton.enabled = theWebView.canGoBack; - self.forwardButton.enabled = theWebView.canGoForward; - [self.spinner stopAnimating]; - - self.addressLabel.text = @"Load Error"; - - [self.navigationDelegate webView:theWebView didFailLoadWithError:error]; -} - -#pragma mark CDVScreenOrientationDelegate - -- (BOOL)shouldAutorotate -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) { - return [self.orientationDelegate shouldAutorotate]; - } - return YES; -} - -- (NSUInteger)supportedInterfaceOrientations -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) { - return [self.orientationDelegate supportedInterfaceOrientations]; - } - - return 1 << UIInterfaceOrientationPortrait; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { - return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation]; - } - - return YES; -} - -@end - -@implementation CDVInAppBrowserOptions - -- (id)init -{ - if (self = [super init]) { - // default values - - self.location = YES; - self.toolbar = YES; - self.enableviewportscale = NO; - self.mediaplaybackrequiresuseraction = NO; - self.allowinlinemediaplayback = NO; - self.keyboarddisplayrequiresuseraction = YES; - self.suppressesincrementalrendering = NO; - self.hidden = NO; - - /* cemerson */ self.closebuttoncaption = CLOSE_BUTTON_LABEL; - /* cemerson */ self.vw = iabvc.view.frame.size.width; - /* cemerson */ self.vh = iabvc.view.frame.size.height; // - (FOOTER_HEIGHT); - /* cemerson */ self.vx = iabvc.view.frame.origin.x; - /* cemerson */ self.vy = 0; - /* cemerson */ self.buttoncolorbg = BUTTON_BACKGROUND_COLOR; - } - - return self; -} - -+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options -{ - CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init]; - - // NOTE: this parsing does not handle quotes within values - NSArray* pairs = [options componentsSeparatedByString:@","]; - - // parse keys and values, set the properties - for (NSString* pair in pairs) { - NSArray* keyvalue = [pair componentsSeparatedByString:@"="]; - - if ([keyvalue count] == 2) { - NSString* key = [[keyvalue objectAtIndex:0] lowercaseString]; - NSString* value = [keyvalue objectAtIndex:1]; - NSString* value_lc = [value lowercaseString]; - - BOOL isBoolean = [value_lc isEqualToString:@"yes"] || [value_lc isEqualToString:@"no"]; - NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; - [numberFormatter setAllowsFloats:YES]; - BOOL isNumber = [numberFormatter numberFromString:value_lc] != nil; - - // set the property according to the key name - if ([obj respondsToSelector:NSSelectorFromString(key)]) { - //NSLog(@"....parsing browserOption[%@] ...", key); - if (isNumber) { - [obj setValue:[numberFormatter numberFromString:value_lc] forKey:key]; - } else if (isBoolean) { - [obj setValue:[NSNumber numberWithBool:[value_lc isEqualToString:@"yes"]] forKey:key]; - } else { // string - [obj setValue:value forKey:key]; - } - } - } - } - - return obj; -} - -@end diff --git a/iOS/InAppBrowser/src/wp/InAppBrowser.cs b/iOS/InAppBrowser/src/wp/InAppBrowser.cs deleted file mode 100644 index 46e13849..00000000 --- a/iOS/InAppBrowser/src/wp/InAppBrowser.cs +++ /dev/null @@ -1,277 +0,0 @@ -using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; -using Microsoft.Phone.Controls; -using System.Diagnostics; -using System.Runtime.Serialization; -using WPCordovaClassLib.Cordova; -using WPCordovaClassLib.Cordova.Commands; -using WPCordovaClassLib.Cordova.JSON; -using Microsoft.Phone.Shell; -using Microsoft.Phone.Tasks; - -namespace WPCordovaClassLib.Cordova.Commands -{ - [DataContract] - public class BrowserOptions - { - [DataMember] - public string url; - - [DataMember] - public bool isGeolocationEnabled; - } - - public class InAppBrowser : BaseCommand - { - - private static WebBrowser browser; - private static ApplicationBarIconButton backButton; - private static ApplicationBarIconButton fwdButton; - - public void open(string options) - { - string[] args = JSON.JsonHelper.Deserialize(options); - //BrowserOptions opts = JSON.JsonHelper.Deserialize(options); - string urlLoc = args[0]; - string target = args[1]; - /* - _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser - _blank - always open in the InAppBrowser - _system - always open in the system web browser - */ - switch (target) - { - case "_blank": - ShowInAppBrowser(urlLoc); - break; - case "_self": - ShowCordovaBrowser(urlLoc); - break; - case "_system": - ShowSystemBrowser(urlLoc); - break; - } - - - } - - private void ShowCordovaBrowser(string url) - { - Uri loc = new Uri(url, UriKind.RelativeOrAbsolute); - Deployment.Current.Dispatcher.BeginInvoke(() => - { - PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; - if (frame != null) - { - PhoneApplicationPage page = frame.Content as PhoneApplicationPage; - if (page != null) - { - CordovaView cView = page.FindName("CordovaView") as CordovaView; - if (cView != null) - { - WebBrowser br = cView.Browser; - br.Navigate(loc); - } - } - - } - }); - } - - private void ShowSystemBrowser(string url) - { - WebBrowserTask webBrowserTask = new WebBrowserTask(); - webBrowserTask.Uri = new Uri(url, UriKind.Absolute); - webBrowserTask.Show(); - } - - - private void ShowInAppBrowser(string url) - { - Uri loc = new Uri(url); - - Deployment.Current.Dispatcher.BeginInvoke(() => - { - if (browser != null) - { - //browser.IsGeolocationEnabled = opts.isGeolocationEnabled; - browser.Navigate(loc); - } - else - { - PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; - if (frame != null) - { - PhoneApplicationPage page = frame.Content as PhoneApplicationPage; - - string baseImageUrl = "Images/"; - - if (page != null) - { - Grid grid = page.FindName("LayoutRoot") as Grid; - if (grid != null) - { - browser = new WebBrowser(); - browser.IsScriptEnabled = true; - browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted); - - browser.Navigating += new EventHandler(browser_Navigating); - browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed); - browser.Navigated += new EventHandler(browser_Navigated); - browser.Navigate(loc); - //browser.IsGeolocationEnabled = opts.isGeolocationEnabled; - grid.Children.Add(browser); - } - - ApplicationBar bar = new ApplicationBar(); - bar.BackgroundColor = Colors.Gray; - bar.IsMenuEnabled = false; - - backButton = new ApplicationBarIconButton(); - backButton.Text = "Back"; - - backButton.IconUri = new Uri(baseImageUrl + "appbar.back.rest.png", UriKind.Relative); - backButton.Click += new EventHandler(backButton_Click); - bar.Buttons.Add(backButton); - - - fwdButton = new ApplicationBarIconButton(); - fwdButton.Text = "Forward"; - fwdButton.IconUri = new Uri(baseImageUrl + "appbar.next.rest.png", UriKind.Relative); - fwdButton.Click += new EventHandler(fwdButton_Click); - bar.Buttons.Add(fwdButton); - - ApplicationBarIconButton closeBtn = new ApplicationBarIconButton(); - closeBtn.Text = "Close"; - closeBtn.IconUri = new Uri(baseImageUrl + "appbar.close.rest.png", UriKind.Relative); - closeBtn.Click += new EventHandler(closeBtn_Click); - bar.Buttons.Add(closeBtn); - - page.ApplicationBar = bar; - } - - } - } - }); - } - - void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) - { - - } - - void fwdButton_Click(object sender, EventArgs e) - { - if (browser != null) - { - try - { -#if WP8 - browser.GoForward(); -#else - browser.InvokeScript("execScript", "history.forward();"); -#endif - } - catch (Exception) - { - - } - } - } - - void backButton_Click(object sender, EventArgs e) - { - if (browser != null) - { - try - { -#if WP8 - browser.GoBack(); -#else - browser.InvokeScript("execScript", "history.back();"); -#endif - } - catch (Exception) - { - - } - } - } - - void closeBtn_Click(object sender, EventArgs e) - { - this.close(); - } - - - public void close(string options = "") - { - if (browser != null) - { - Deployment.Current.Dispatcher.BeginInvoke(() => - { - PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; - if (frame != null) - { - PhoneApplicationPage page = frame.Content as PhoneApplicationPage; - if (page != null) - { - Grid grid = page.FindName("LayoutRoot") as Grid; - if (grid != null) - { - grid.Children.Remove(browser); - } - page.ApplicationBar = null; - } - } - browser = null; - string message = "{\"type\":\"exit\"}"; - PluginResult result = new PluginResult(PluginResult.Status.OK, message); - result.KeepCallback = false; - this.DispatchCommandResult(result); - }); - } - } - - void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) - { -#if WP8 - if (browser != null) - { - backButton.IsEnabled = browser.CanGoBack; - fwdButton.IsEnabled = browser.CanGoForward; - - } -#endif - string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}"; - PluginResult result = new PluginResult(PluginResult.Status.OK, message); - result.KeepCallback = true; - this.DispatchCommandResult(result); - } - - void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e) - { - string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}"; - PluginResult result = new PluginResult(PluginResult.Status.ERROR, message); - result.KeepCallback = true; - this.DispatchCommandResult(result); - } - - void browser_Navigating(object sender, NavigatingEventArgs e) - { - string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}"; - PluginResult result = new PluginResult(PluginResult.Status.OK, message); - result.KeepCallback = true; - this.DispatchCommandResult(result); - } - - } -} diff --git a/iOS/InAppBrowser/www/InAppBrowser.js b/iOS/InAppBrowser/www/InAppBrowser.js deleted file mode 100644 index 75a35453..00000000 --- a/iOS/InAppBrowser/www/InAppBrowser.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -var exec = require('cordova/exec'); -var channel = require('cordova/channel'); -var modulemapper = require('cordova/modulemapper'); - -function InAppBrowser() { - this.channels = { - 'loadstart': channel.create('loadstart'), - 'loadstop' : channel.create('loadstop'), - 'loaderror' : channel.create('loaderror'), - 'exit' : channel.create('exit') - }; -} - -InAppBrowser.prototype = { -_eventHandler: function (event) { - if (event.type in this.channels) { - this.channels[event.type].fire(event); - } -}, -close: function (eventname) { - exec(null, null, "InAppBrowser", "close", []); -}, -show: function (eventname) { - exec(null, null, "InAppBrowser", "show", []); -}, -addEventListener: function (eventname,f) { - if (eventname in this.channels) { - this.channels[eventname].subscribe(f); - } -}, -removeEventListener: function(eventname, f) { - if (eventname in this.channels) { - this.channels[eventname].unsubscribe(f); - } -}, - -executeScript: function(injectDetails, cb) { - if (injectDetails.code) { - exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]); - } else if (injectDetails.file) { - exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]); - } else { - throw new Error('executeScript requires exactly one of code or file to be specified'); - } -}, - -insertCSS: function(injectDetails, cb) { - if (injectDetails.code) { - exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]); - } else if (injectDetails.file) { - exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]); - } else { - throw new Error('insertCSS requires exactly one of code or file to be specified'); - } -} -}; - - -module.exports = function(strUrl, strWindowName, strWindowFeatures) { - var iab = new InAppBrowser(); - var cb = function(eventname) { - iab._eventHandler(eventname); - }; - - // Don't catch calls that write to existing frames (e.g. named iframes). - if (window.frames && window.frames[strWindowName]) { - var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open'); - return origOpenFunc.apply(window, arguments); - } - - exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); - - return iab; -}; - - -window.console.log('inappbrowser.js loaded...'); \ No newline at end of file diff --git a/iOS/PowerManagement b/iOS/PowerManagement deleted file mode 160000 index 273d3587..00000000 --- a/iOS/PowerManagement +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 273d3587e4509e040456756583d0776ab52235e9 diff --git a/iOS/SecureDeviceIdentifier b/iOS/SecureDeviceIdentifier deleted file mode 160000 index 0fd64237..00000000 --- a/iOS/SecureDeviceIdentifier +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0fd64237b716a79aceccee84498fb5c95630169d From f2950ffb14ac9c48168bf3f7eba1cd16ee23329a Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:06:36 -0400 Subject: [PATCH 13/25] 20130731.13 --- iOS/Badge/Cordova 2.x/Badge.h | 23 ++++++++++++++++ iOS/Badge/Cordova 2.x/Badge.js | 50 ++++++++++++++++++++++++++++++++++ iOS/Badge/Cordova 2.x/Badge.m | 18 ++++++++++++ iOS/Badge/README.md | 13 +++++++++ iOS/Badge/README_old.md | 34 +++++++++++++++++++++++ iOS/Badge/plugin.xml | 26 ++++++++++++++++++ iOS/Badge/src/ios/Badge.h | 17 ++++++++++++ iOS/Badge/src/ios/Badge.m | 24 ++++++++++++++++ iOS/Badge/www/badge.js | 40 +++++++++++++++++++++++++++ 9 files changed, 245 insertions(+) create mode 100755 iOS/Badge/Cordova 2.x/Badge.h create mode 100755 iOS/Badge/Cordova 2.x/Badge.js create mode 100755 iOS/Badge/Cordova 2.x/Badge.m create mode 100644 iOS/Badge/README.md create mode 100644 iOS/Badge/README_old.md create mode 100644 iOS/Badge/plugin.xml create mode 100644 iOS/Badge/src/ios/Badge.h create mode 100644 iOS/Badge/src/ios/Badge.m create mode 100644 iOS/Badge/www/badge.js diff --git a/iOS/Badge/Cordova 2.x/Badge.h b/iOS/Badge/Cordova 2.x/Badge.h new file mode 100755 index 00000000..a3867f20 --- /dev/null +++ b/iOS/Badge/Cordova 2.x/Badge.h @@ -0,0 +1,23 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import + +#ifdef CORDOVA_FRAMEWORK + #import +#else + #import "CDVPlugin.h" +#endif + +@interface Badge : CDVPlugin { +} + +- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options; + +@end diff --git a/iOS/Badge/Cordova 2.x/Badge.js b/iOS/Badge/Cordova 2.x/Badge.js new file mode 100755 index 00000000..fc0441b1 --- /dev/null +++ b/iOS/Badge/Cordova 2.x/Badge.js @@ -0,0 +1,50 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +/* + * Temporary Scope to contain the plugin. + * - More information here: + * https://github.com/apache/incubator-cordova-ios/blob/master/guides/Cordova%20Plugin%20Upgrade%20Guide.md + */ +(function(){ + + /* Get local ref to global PhoneGap/Cordova/cordova object for exec function. + - This increases the compatibility of the plugin. */ + var cordovaRef = window.PhoneGap || window.Cordova || window.cordova; // old to new fallbacks + + /* + * This class exposes the iPhone 'icon badge' functionality to JavaScript + * to add a number (with a red background) to each icon. + */ + function Badge() { } + + /** + * Positive integer sets the badge amount, 0 or negative removes it. + */ + Badge.prototype.set = function(options) { + cordovaRef.exec("Badge.setBadge", options); + }; + + /** + * Shorthand to set the badge to 0 and remove it. + */ + Badge.prototype.clear = function() { + cordovaRef.exec("Badge.setBadge", 0); + }; + + cordovaRef.addConstructor(function() { + if(!window.plugins) { + window.plugins = {}; + } + if(!window.plugins.badge) { + window.plugins.badge = new Badge(); + } + }); + +})(); /* End of Temporary Scope. */ \ No newline at end of file diff --git a/iOS/Badge/Cordova 2.x/Badge.m b/iOS/Badge/Cordova 2.x/Badge.m new file mode 100755 index 00000000..28b05a9e --- /dev/null +++ b/iOS/Badge/Cordova 2.x/Badge.m @@ -0,0 +1,18 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import "Badge.h" + +@implementation Badge + +- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options { + [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ badgeNumber objectAtIndex:0] intValue]]; +} + +@end \ No newline at end of file diff --git a/iOS/Badge/README.md b/iOS/Badge/README.md new file mode 100644 index 00000000..1d0f6b59 --- /dev/null +++ b/iOS/Badge/README.md @@ -0,0 +1,13 @@ +cordova-badge +============= + +Original version/notes here: +https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Badge + +##Install Plugin: +cordova plugin add https://github.com/cemerson/cordova-badge.git + +##Remove Plugin: +cordova plugin rm org.apache.cordova.plugins.Badge + +20130731.5 diff --git a/iOS/Badge/README_old.md b/iOS/Badge/README_old.md new file mode 100644 index 00000000..757c5839 --- /dev/null +++ b/iOS/Badge/README_old.md @@ -0,0 +1,34 @@ +// +// Cordova 1.6.1 iOS Badge Plugin +// +// Author: Michael Nachbaur +// - Adapted by: Simon Madine of The Angry Robot Zombie Factory 2010 +// - Updated by: Joseph Stuhr +// +// In the Cordova.plist section, you need to add the plugin with the key/pair value of: +// +// Badge Badge +// +// Code: +// To set the badge number: +// - window.plugins.badge.set(_amount); +// +// To clear the badge: +// - window.plugins.badge.set(0); +// - window.plugins.badge.clear(); +// +// ========================================================= + +License + +The MIT License + +Copyright (c) ???? Michael Nachbaur + - Adapted by Simon Madine of The Angry Robot Zombie Factory 2010 + - Updated by Joseph Stuhr 2012 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/iOS/Badge/plugin.xml b/iOS/Badge/plugin.xml new file mode 100644 index 00000000..be62a93a --- /dev/null +++ b/iOS/Badge/plugin.xml @@ -0,0 +1,26 @@ + + + + + Badge + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Badge/src/ios/Badge.h b/iOS/Badge/src/ios/Badge.h new file mode 100644 index 00000000..2ae4821a --- /dev/null +++ b/iOS/Badge/src/ios/Badge.h @@ -0,0 +1,17 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import +#import + +@interface Badge : CDVPlugin { +} +- (void)setBadge:(CDVInvokedUrlCommand*)command; + +@end \ No newline at end of file diff --git a/iOS/Badge/src/ios/Badge.m b/iOS/Badge/src/ios/Badge.m new file mode 100644 index 00000000..09c3fa0a --- /dev/null +++ b/iOS/Badge/src/ios/Badge.m @@ -0,0 +1,24 @@ +/* + * This code is adapted from the work of Michael Nachbaur + * by Simon Madine of The Angry Robot Zombie Factory + * - Converted to Cordova 1.6.1 by Joseph Stuhr. + * 2012-04-19 + * MIT licensed + * + */ + +#import "Badge.h" + +@implementation Badge + +- (void)setBadge:(CDVInvokedUrlCommand*)command { + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(dispatch_get_main_queue(), ^(void) { + [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ command.arguments objectAtIndex:0] intValue]]; + }); + }); + +} + +@end \ No newline at end of file diff --git a/iOS/Badge/www/badge.js b/iOS/Badge/www/badge.js new file mode 100644 index 00000000..aeb61eea --- /dev/null +++ b/iOS/Badge/www/badge.js @@ -0,0 +1,40 @@ +/* +* This code is adapted from the work of Michael Nachbaur +* by Simon Madine of The Angry Robot Zombie Factory +* - Converted to Cordova 1.6.1 by Joseph Stuhr. +* 2012-04-19 +* MIT licensed +* +*/ + (function(cordova) { + + /* + * This class exposes the iPhone 'icon badge' functionality to JavaScript + * to add a number (with a red background) to each icon. + */ + function Badge() { } + + /** + * Positive integer sets the badge amount, 0 or negative removes it. + */ + Badge.prototype.set = function(options) { + cordova.exec(null,null,"Badge", "setBadge", [options]); + }; + + /** + * Shorthand to set the badge to 0 and remove it. + */ + Badge.prototype.clear = function() { + cordova.exec(null,null,"Badge","setBadge",[0]); + }; + + cordova.addConstructor(function() { + if(!window.plugins) window.plugins = {}; + window.plugins.badge = new Badge(); + }); + +})(window.cordova || window.Cordova); + + +/* DEBUG */ window.console.log('badge.js loaded...'); + From e350a2e407b8709f9456bf80be5f97a8b96db6c9 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:06:50 -0400 Subject: [PATCH 14/25] 20130731.14 --- .gitmodules | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index aec9e10b..7e14b474 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge - url = https://github.com/cemerson/cordova-badge.git + url = git://github.com/cemerson/cordova-badge.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser - url = https://github.com/cemerson/cordova-inappbrowser-ce.git + url = git://github.com/cemerson/cordova-inappbrowser-ce.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier - url = https://github.com/cemerson/cordova-securedeviceidentifier.git + url = git://github.com/cemerson/cordova-securedeviceidentifier.git [submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement - url = https://github.com/cemerson/cordova-powermanagement.git + url = git://github.com/cemerson/cordova-powermanagement.git From e9d6a37325d3ac5f45e90f11ff9386f3a30ddf29 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:08:51 -0400 Subject: [PATCH 15/25] 20130731.15 --- .gitmodules | 12 -------- iOS/Badge/Cordova 2.x/Badge.h | 23 ---------------- iOS/Badge/Cordova 2.x/Badge.js | 50 ---------------------------------- iOS/Badge/Cordova 2.x/Badge.m | 18 ------------ iOS/Badge/README.md | 13 --------- iOS/Badge/README_old.md | 34 ----------------------- iOS/Badge/plugin.xml | 26 ------------------ iOS/Badge/src/ios/Badge.h | 17 ------------ iOS/Badge/src/ios/Badge.m | 24 ---------------- iOS/Badge/www/badge.js | 40 --------------------------- 10 files changed, 257 deletions(-) delete mode 100755 iOS/Badge/Cordova 2.x/Badge.h delete mode 100755 iOS/Badge/Cordova 2.x/Badge.js delete mode 100755 iOS/Badge/Cordova 2.x/Badge.m delete mode 100644 iOS/Badge/README.md delete mode 100644 iOS/Badge/README_old.md delete mode 100644 iOS/Badge/plugin.xml delete mode 100644 iOS/Badge/src/ios/Badge.h delete mode 100644 iOS/Badge/src/ios/Badge.m delete mode 100644 iOS/Badge/www/badge.js diff --git a/.gitmodules b/.gitmodules index 7e14b474..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +0,0 @@ -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge - url = git://github.com/cemerson/cordova-badge.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser - url = git://github.com/cemerson/cordova-inappbrowser-ce.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier - url = git://github.com/cemerson/cordova-securedeviceidentifier.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement - url = git://github.com/cemerson/cordova-powermanagement.git diff --git a/iOS/Badge/Cordova 2.x/Badge.h b/iOS/Badge/Cordova 2.x/Badge.h deleted file mode 100755 index a3867f20..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import - -#ifdef CORDOVA_FRAMEWORK - #import -#else - #import "CDVPlugin.h" -#endif - -@interface Badge : CDVPlugin { -} - -- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options; - -@end diff --git a/iOS/Badge/Cordova 2.x/Badge.js b/iOS/Badge/Cordova 2.x/Badge.js deleted file mode 100755 index fc0441b1..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -/* - * Temporary Scope to contain the plugin. - * - More information here: - * https://github.com/apache/incubator-cordova-ios/blob/master/guides/Cordova%20Plugin%20Upgrade%20Guide.md - */ -(function(){ - - /* Get local ref to global PhoneGap/Cordova/cordova object for exec function. - - This increases the compatibility of the plugin. */ - var cordovaRef = window.PhoneGap || window.Cordova || window.cordova; // old to new fallbacks - - /* - * This class exposes the iPhone 'icon badge' functionality to JavaScript - * to add a number (with a red background) to each icon. - */ - function Badge() { } - - /** - * Positive integer sets the badge amount, 0 or negative removes it. - */ - Badge.prototype.set = function(options) { - cordovaRef.exec("Badge.setBadge", options); - }; - - /** - * Shorthand to set the badge to 0 and remove it. - */ - Badge.prototype.clear = function() { - cordovaRef.exec("Badge.setBadge", 0); - }; - - cordovaRef.addConstructor(function() { - if(!window.plugins) { - window.plugins = {}; - } - if(!window.plugins.badge) { - window.plugins.badge = new Badge(); - } - }); - -})(); /* End of Temporary Scope. */ \ No newline at end of file diff --git a/iOS/Badge/Cordova 2.x/Badge.m b/iOS/Badge/Cordova 2.x/Badge.m deleted file mode 100755 index 28b05a9e..00000000 --- a/iOS/Badge/Cordova 2.x/Badge.m +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import "Badge.h" - -@implementation Badge - -- (void)setBadge:(NSMutableArray*)badgeNumber withDict:(NSMutableDictionary*)options { - [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ badgeNumber objectAtIndex:0] intValue]]; -} - -@end \ No newline at end of file diff --git a/iOS/Badge/README.md b/iOS/Badge/README.md deleted file mode 100644 index 1d0f6b59..00000000 --- a/iOS/Badge/README.md +++ /dev/null @@ -1,13 +0,0 @@ -cordova-badge -============= - -Original version/notes here: -https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Badge - -##Install Plugin: -cordova plugin add https://github.com/cemerson/cordova-badge.git - -##Remove Plugin: -cordova plugin rm org.apache.cordova.plugins.Badge - -20130731.5 diff --git a/iOS/Badge/README_old.md b/iOS/Badge/README_old.md deleted file mode 100644 index 757c5839..00000000 --- a/iOS/Badge/README_old.md +++ /dev/null @@ -1,34 +0,0 @@ -// -// Cordova 1.6.1 iOS Badge Plugin -// -// Author: Michael Nachbaur -// - Adapted by: Simon Madine of The Angry Robot Zombie Factory 2010 -// - Updated by: Joseph Stuhr -// -// In the Cordova.plist section, you need to add the plugin with the key/pair value of: -// -// Badge Badge -// -// Code: -// To set the badge number: -// - window.plugins.badge.set(_amount); -// -// To clear the badge: -// - window.plugins.badge.set(0); -// - window.plugins.badge.clear(); -// -// ========================================================= - -License - -The MIT License - -Copyright (c) ???? Michael Nachbaur - - Adapted by Simon Madine of The Angry Robot Zombie Factory 2010 - - Updated by Joseph Stuhr 2012 - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/iOS/Badge/plugin.xml b/iOS/Badge/plugin.xml deleted file mode 100644 index be62a93a..00000000 --- a/iOS/Badge/plugin.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Badge - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Badge/src/ios/Badge.h b/iOS/Badge/src/ios/Badge.h deleted file mode 100644 index 2ae4821a..00000000 --- a/iOS/Badge/src/ios/Badge.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import -#import - -@interface Badge : CDVPlugin { -} -- (void)setBadge:(CDVInvokedUrlCommand*)command; - -@end \ No newline at end of file diff --git a/iOS/Badge/src/ios/Badge.m b/iOS/Badge/src/ios/Badge.m deleted file mode 100644 index 09c3fa0a..00000000 --- a/iOS/Badge/src/ios/Badge.m +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This code is adapted from the work of Michael Nachbaur - * by Simon Madine of The Angry Robot Zombie Factory - * - Converted to Cordova 1.6.1 by Joseph Stuhr. - * 2012-04-19 - * MIT licensed - * - */ - -#import "Badge.h" - -@implementation Badge - -- (void)setBadge:(CDVInvokedUrlCommand*)command { - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - dispatch_async(dispatch_get_main_queue(), ^(void) { - [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[[ command.arguments objectAtIndex:0] intValue]]; - }); - }); - -} - -@end \ No newline at end of file diff --git a/iOS/Badge/www/badge.js b/iOS/Badge/www/badge.js deleted file mode 100644 index aeb61eea..00000000 --- a/iOS/Badge/www/badge.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -* This code is adapted from the work of Michael Nachbaur -* by Simon Madine of The Angry Robot Zombie Factory -* - Converted to Cordova 1.6.1 by Joseph Stuhr. -* 2012-04-19 -* MIT licensed -* -*/ - (function(cordova) { - - /* - * This class exposes the iPhone 'icon badge' functionality to JavaScript - * to add a number (with a red background) to each icon. - */ - function Badge() { } - - /** - * Positive integer sets the badge amount, 0 or negative removes it. - */ - Badge.prototype.set = function(options) { - cordova.exec(null,null,"Badge", "setBadge", [options]); - }; - - /** - * Shorthand to set the badge to 0 and remove it. - */ - Badge.prototype.clear = function() { - cordova.exec(null,null,"Badge","setBadge",[0]); - }; - - cordova.addConstructor(function() { - if(!window.plugins) window.plugins = {}; - window.plugins.badge = new Badge(); - }); - -})(window.cordova || window.Cordova); - - -/* DEBUG */ window.console.log('badge.js loaded...'); - From 13f70a7ee781d519462884f1f222af2ca80108bb Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:11:30 -0400 Subject: [PATCH 16/25] 20130731.17 --- .gitmodules | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitmodules b/.gitmodules index e69de29b..aec9e10b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge + url = https://github.com/cemerson/cordova-badge.git +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser + url = https://github.com/cemerson/cordova-inappbrowser-ce.git +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier + url = https://github.com/cemerson/cordova-securedeviceidentifier.git +[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] + path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement + url = https://github.com/cemerson/cordova-powermanagement.git From 6a5ee0f68e799b307d7fc0fd931b06cdee088283 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:25:50 -0400 Subject: [PATCH 17/25] 20130731.26 --- .gitmodules | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.gitmodules b/.gitmodules index aec9e10b..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +0,0 @@ -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/Badge - url = https://github.com/cemerson/cordova-badge.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/InAppBrowser - url = https://github.com/cemerson/cordova-inappbrowser-ce.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/SecureDeviceIdentifier - url = https://github.com/cemerson/cordova-securedeviceidentifier.git -[submodule "/Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement"] - path = /Users/Administrator/Dropbox/Projects/github/phonegap-plugins/iOS/PowerManagement - url = https://github.com/cemerson/cordova-powermanagement.git From ed82dae276a2395a0e3752cc4bc1d1b1ba35b041 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:36:37 -0400 Subject: [PATCH 18/25] 20130731.31 --- .gitmodules | 12 ++++++++++++ iOS/Badge | 1 + iOS/InAppBrowser | 1 + iOS/PowerManagement | 1 + iOS/SecureDeviceIdentifier | 1 + 5 files changed, 16 insertions(+) create mode 160000 iOS/Badge create mode 160000 iOS/InAppBrowser create mode 160000 iOS/PowerManagement create mode 160000 iOS/SecureDeviceIdentifier diff --git a/.gitmodules b/.gitmodules index e69de29b..1d52b44b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "iOS/SecureDeviceIdentifier"] + path = iOS/SecureDeviceIdentifier + url = https://github.com/cemerson/cordova-securedeviceidentifier.git +[submodule "iOS/PowerManagement"] + path = iOS/PowerManagement + url = https://github.com/cemerson/cordova-powermanagement.git +[submodule "iOS/Badge"] + path = iOS/Badge + url = https://github.com/cemerson/cordova-badge.git +[submodule "iOS/InAppBrowser"] + path = iOS/InAppBrowser + url = https://github.com/cemerson/cordova-inappbrowser-ce.git diff --git a/iOS/Badge b/iOS/Badge new file mode 160000 index 00000000..60e6388d --- /dev/null +++ b/iOS/Badge @@ -0,0 +1 @@ +Subproject commit 60e6388dc9673148bf57052978b6b60fae71f69d diff --git a/iOS/InAppBrowser b/iOS/InAppBrowser new file mode 160000 index 00000000..0fd64237 --- /dev/null +++ b/iOS/InAppBrowser @@ -0,0 +1 @@ +Subproject commit 0fd64237b716a79aceccee84498fb5c95630169d diff --git a/iOS/PowerManagement b/iOS/PowerManagement new file mode 160000 index 00000000..92c9676c --- /dev/null +++ b/iOS/PowerManagement @@ -0,0 +1 @@ +Subproject commit 92c9676c5b36b262440fbe264353c5daf0754fb7 diff --git a/iOS/SecureDeviceIdentifier b/iOS/SecureDeviceIdentifier new file mode 160000 index 00000000..273d3587 --- /dev/null +++ b/iOS/SecureDeviceIdentifier @@ -0,0 +1 @@ +Subproject commit 273d3587e4509e040456756583d0776ab52235e9 From d29e26134316ec72ee162a0ff2652b25b9cd5123 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:39:10 -0400 Subject: [PATCH 19/25] 20130731.35 --- iOS/Badge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/Badge b/iOS/Badge index 60e6388d..eb5abb94 160000 --- a/iOS/Badge +++ b/iOS/Badge @@ -1 +1 @@ -Subproject commit 60e6388dc9673148bf57052978b6b60fae71f69d +Subproject commit eb5abb940b50c373b7fed7b2209aad119c233edf From 2c06486d1e5e97bfa5e85ab7b1a4dddcd68cdc1f Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:46:56 -0400 Subject: [PATCH 20/25] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e61336b4..4802d4bf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +**cemerson fork note**: My fork of this repo uses submodules for each plugin. To clone with all submodules intact use: + + git clone --recursive https://github.com/cemerson/phonegap-plugins.git + + **NOTE**: We don’t want to “clutter” this repo with code anymore. Authors should maintain the code in their own repos and just put a pointer in a README.md in this repo. It would be best for everyone if the individual authors of the plugins were able to manage issues and pull requests while still allowing this to be an easier way for users to discover the plugins they need. @@ -20,4 +25,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 64c3ab1694d51b3c2d5bc60752ff00c6055c712c Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Wed, 31 Jul 2013 10:48:12 -0400 Subject: [PATCH 21/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4802d4bf..00337e06 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**cemerson fork note**: My fork of this repo uses submodules for each plugin. To clone with all submodules intact use: +**cemerson fork note**: My fork of this repo uses submodules for a few plugins. To clone with all submodules intact use: git clone --recursive https://github.com/cemerson/phonegap-plugins.git From a2fcaa4ec47f51a7916e4cb0da93be7dc6af91b7 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Tue, 6 Aug 2013 09:28:40 -0400 Subject: [PATCH 22/25] 20130806.7 --- iOS/InAppBrowser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/InAppBrowser b/iOS/InAppBrowser index 0fd64237..e304e900 160000 --- a/iOS/InAppBrowser +++ b/iOS/InAppBrowser @@ -1 +1 @@ -Subproject commit 0fd64237b716a79aceccee84498fb5c95630169d +Subproject commit e304e900091e8a6bc024565da707aa9e11179813 From 8f0dae628cf5c5de7a01975d9dad47d70557f09f Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Tue, 6 Aug 2013 10:24:13 -0400 Subject: [PATCH 23/25] 20130806.02 --- iOS/InAppBrowser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/InAppBrowser b/iOS/InAppBrowser index e304e900..e2cae20d 160000 --- a/iOS/InAppBrowser +++ b/iOS/InAppBrowser @@ -1 +1 @@ -Subproject commit e304e900091e8a6bc024565da707aa9e11179813 +Subproject commit e2cae20d131977b782d4e6a1ce3c91a3995b5e77 From 967c1665990173c4168b6dc6016656d14af0a93f Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Tue, 6 Aug 2013 10:35:30 -0400 Subject: [PATCH 24/25] 20130806.03 --- iOS/InAppBrowser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/InAppBrowser b/iOS/InAppBrowser index e2cae20d..83ce367d 160000 --- a/iOS/InAppBrowser +++ b/iOS/InAppBrowser @@ -1 +1 @@ -Subproject commit e2cae20d131977b782d4e6a1ce3c91a3995b5e77 +Subproject commit 83ce367d97187fc32fb8192ee99ca99b03aaa740 From 0a9a0d37accbe5e84b50ad12638faefde95191a1 Mon Sep 17 00:00:00 2001 From: Chris Emerson Date: Tue, 6 Aug 2013 13:25:31 -0400 Subject: [PATCH 25/25] 20130806.17 --- iOS/InAppBrowser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/InAppBrowser b/iOS/InAppBrowser index 83ce367d..86983705 160000 --- a/iOS/InAppBrowser +++ b/iOS/InAppBrowser @@ -1 +1 @@ -Subproject commit 83ce367d97187fc32fb8192ee99ca99b03aaa740 +Subproject commit 86983705b59aede3f33a65f4ab7cb05982f9ee6e