You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/05/23 22:03:47 UTC
[24/30] git commit: Support installation of crx files
Support installation of crx files
Conflicts:
www/index.html
Project: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/commit/4d4e0b46
Tree: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/tree/4d4e0b46
Diff: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/diff/4d4e0b46
Branch: refs/heads/master
Commit: 4d4e0b46caec4db39cb2d3113c208657939029f6
Parents: 6492417
Author: Shravan Narayan <sh...@google.com>
Authored: Fri Apr 26 14:39:15 2013 -0400
Committer: Braden Shepherdson <br...@google.com>
Committed: Thu May 16 15:29:29 2013 -0400
----------------------------------------------------------------------
www/cdvah_index.html | 1 +
www/cdvah_js/CrxPackageHandler.js | 54 ++++
www/crx_files/config.android.xml | 47 +++
www/crx_files/config.ios.xml | 51 ++++
www/crx_files/www/chromeapp.html | 15 +
www/crx_files/www/chromeappstyles.css | 14 +
www/crx_files/www/chromebgpage.html | 11 +
www/crx_files/www/cordova_plugins.json | 1 +
www/crx_files/www/plugins/chrome.common/events.js | 53 ++++
.../www/plugins/chrome.fileSystem/fileSystem.js | 142 ++++++++++
www/crx_files/www/plugins/chrome.i18n/i18n.js | 185 ++++++++++++
.../www/plugins/chrome.identity/identity.js | 161 +++++++++++
www/crx_files/www/plugins/chrome.socket/socket.js | 216 +++++++++++++++
.../www/plugins/chrome.storage/storage.js | 202 ++++++++++++++
.../www/plugins/chrome/api/app/runtime.js | 7 +
www/crx_files/www/plugins/chrome/api/app/window.js | 156 +++++++++++
www/crx_files/www/plugins/chrome/api/bootstrap.js | 13 +
.../www/plugins/chrome/api/helpers/stubs.js | 11 +
www/crx_files/www/plugins/chrome/api/mobile.js | 58 ++++
www/crx_files/www/plugins/chrome/api/runtime.js | 58 ++++
20 files changed, 1456 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/cdvah_index.html
----------------------------------------------------------------------
diff --git a/www/cdvah_index.html b/www/cdvah_index.html
index 8850f80..3eaede1 100644
--- a/www/cdvah_index.html
+++ b/www/cdvah_index.html
@@ -14,6 +14,7 @@
<script type="text/javascript" src="cdvah_js/AppBundleAlias.js"></script>
<script type="text/javascript" src="cdvah_js/KnownExtensionDownloader.js"></script>
<script type="text/javascript" src="cdvah_js/CdvhPackageHandler.js"></script>
+ <script type="text/javascript" src="cdvah_js/CrxPackageHandler.js"></script>
<script type="text/javascript" src="cdvah_js/ListCtrl.js"></script>
<script type="text/javascript" src="cdvah_js/AddCtrl.js"></script>
</head>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/cdvah_js/CrxPackageHandler.js
----------------------------------------------------------------------
diff --git a/www/cdvah_js/CrxPackageHandler.js b/www/cdvah_js/CrxPackageHandler.js
new file mode 100644
index 0000000..2627fd7
--- /dev/null
+++ b/www/cdvah_js/CrxPackageHandler.js
@@ -0,0 +1,54 @@
+(function(){
+ "use strict";
+ /* global myApp */
+ myApp.run(["AppsService", "ResourcesLoader", function(AppsService, ResourcesLoader){
+
+ function copyFile(startUrl, targetLocation){
+ /************ Begin Work around for File system bug ************/
+ if(targetLocation.indexOf("file://") === 0) {
+ targetLocation = targetLocation.substring("file://".length);
+ }
+ /************ End Work around for File system bug **************/
+ return ResourcesLoader.xhrGet(startUrl)
+ .then(function(xhr){
+ return ResourcesLoader.ensureDirectoryExists(targetLocation)
+ .then(function(){
+ return ResourcesLoader.writeFileContents(targetLocation, xhr.responseText);
+ });
+ });
+ }
+
+ AppsService.registerPackageHandler("crx", {
+ extractPackageToDirectory : function (fileName, outputDirectory){
+ return ResourcesLoader.ensureDirectoryExists(outputDirectory + "/www")
+ .then(function(){
+ return ResourcesLoader.extractZipFile(fileName, outputDirectory + "/www");
+ })
+ .then(function(){
+ return Q.all([
+ copyFile("cdv-app-harness:///direct/cordova.js", outputDirectory + "/www/cordova.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/config.android.xml", outputDirectory + "/config.android.xml"),
+ copyFile("cdv-app-harness:///direct/crx_files/config.ios.xml", outputDirectory + "/config.ios.xml"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/cordova_plugins.json", outputDirectory + "/www/cordova_plugins.json"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/chromeapp.html", outputDirectory + "/www/chromeapp.html"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/chromeappstyles.css", outputDirectory + "/www/chromeappstyles.css"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/chromebgpage.html", outputDirectory + "/www/chromebgpage.html"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/app/runtime.js", outputDirectory + "/www/plugins/chrome/api/app/runtime.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/app/window.js", outputDirectory + "/www/plugins/chrome/api/app/window.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/bootstrap.js", outputDirectory + "/www/plugins/chrome/api/bootstrap.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/helpers/stubs.js", outputDirectory + "/www/plugins/chrome/api/helpers/stubs.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/mobile.js", outputDirectory + "/www/plugins/chrome/api/mobile.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome/api/runtime.js", outputDirectory + "/www/plugins/chrome/api/runtime.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.common/events.js", outputDirectory + "/www/plugins/chrome.common/events.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.fileSystem/fileSystem.js", outputDirectory + "/www/plugins/chrome.fileSystem/fileSystem.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.i18n/i18n.js", outputDirectory + "/www/plugins/chrome.i18n/i18n.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.identity/identity.js", outputDirectory + "/www/plugins/chrome.identity/identity.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.socket/socket.js", outputDirectory + "/www/plugins/chrome.socket/socket.js"),
+ copyFile("cdv-app-harness:///direct/crx_files/www/plugins/chrome.storage/storage.js", outputDirectory + "/www/plugins/chrome.storage/storage.js")
+ ]);
+ });
+ }
+ });
+
+ }]);
+})();
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/config.android.xml
----------------------------------------------------------------------
diff --git a/www/crx_files/config.android.xml b/www/crx_files/config.android.xml
new file mode 100644
index 0000000..27da959
--- /dev/null
+++ b/www/crx_files/config.android.xml
@@ -0,0 +1,47 @@
+<?xml version='1.0' encoding='utf-8'?>
+<cordova>
+ <content src="index.html" />
+ <log level="DEBUG" />
+ <plugins>
+ <plugin name="App" value="org.apache.cordova.App" />
+ <plugin name="Geolocation" value="org.apache.cordova.GeoBroker" />
+ <plugin name="Device" value="org.apache.cordova.Device" />
+ <plugin name="Accelerometer" value="org.apache.cordova.AccelListener" />
+ <plugin name="Compass" value="org.apache.cordova.CompassListener" />
+ <plugin name="Media" value="org.apache.cordova.AudioHandler" />
+ <plugin name="Camera" value="org.apache.cordova.CameraLauncher" />
+ <plugin name="Contacts" value="org.apache.cordova.ContactManager" />
+ <plugin name="File" value="org.apache.cordova.FileUtils" />
+ <plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager" />
+ <plugin name="Notification" value="org.apache.cordova.Notification" />
+ <plugin name="Storage" value="org.apache.cordova.Storage" />
+ <plugin name="FileTransfer" value="org.apache.cordova.FileTransfer" />
+ <plugin name="Capture" value="org.apache.cordova.Capture" />
+ <plugin name="Battery" value="org.apache.cordova.BatteryListener" />
+ <plugin name="SplashScreen" value="org.apache.cordova.SplashScreen" />
+ <plugin name="Echo" value="org.apache.cordova.Echo" />
+ <plugin name="Globalization" value="org.apache.cordova.Globalization" />
+ <plugin name="InAppBrowser" value="org.apache.cordova.InAppBrowser" />
+ <plugin name="Zip" value="org.apache.cordova.Zip" />
+ <plugin name="ChromeExtensionURLs" value="com.google.cordova.ChromeExtensionURLs">
+ <url-filter value="chrome-extension://" />
+ </plugin>
+ <plugin name="ChromeI18n" onload="true" value="com.google.cordova.ChromeI18n" />
+ <plugin name="ChromeIdentity" value="com.google.cordova.ChromeIdentity" />
+ <plugin name="ChromeSocket" value="com.google.cordova.ChromeSocket" />
+ <plugin name="ChromeStorage" value="com.google.cordova.ChromeStorage" />
+ <plugin name="CordovaAppHarnessRedirect" value="org.apache.cordova.cordovaappharness.CordovaAppHarnessRedirect">
+ <url-filter value="cdv-app-harness://" />
+ </plugin>
+ </plugins>
+ <content src="chromeapp.html" />
+ <access origin="*" />
+ <access origin="chrome-extension://*" />
+ <access origin="cdv-app-harness://*" />
+ <preference name="useBrowserHistory" value="true" />
+ <preference name="exit-on-suspend" value="false" />
+ <preference name="phonegap-version" value="1.9.0" />
+ <preference name="orientation" value="default" />
+ <preference name="target-device" value="universal" />
+ <preference name="fullscreen" value="false" />
+</cordova>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/config.ios.xml
----------------------------------------------------------------------
diff --git a/www/crx_files/config.ios.xml b/www/crx_files/config.ios.xml
new file mode 100644
index 0000000..bfba1c9
--- /dev/null
+++ b/www/crx_files/config.ios.xml
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget>
+ <content src="index.html" />
+ <plugins>
+ <plugin name="Device" value="CDVDevice" />
+ <plugin name="Logger" value="CDVLogger" />
+ <plugin name="Compass" value="CDVLocation" />
+ <plugin name="Accelerometer" value="CDVAccelerometer" />
+ <plugin name="Camera" value="CDVCamera" />
+ <plugin name="NetworkStatus" value="CDVConnection" />
+ <plugin name="Contacts" value="CDVContacts" />
+ <plugin name="Debug Console" value="CDVDebugConsole" />
+ <plugin name="Echo" value="CDVEcho" />
+ <plugin name="File" value="CDVFile" />
+ <plugin name="FileTransfer" value="CDVFileTransfer" />
+ <plugin name="Geolocation" value="CDVLocation" />
+ <plugin name="Notification" value="CDVNotification" />
+ <plugin name="Media" value="CDVSound" />
+ <plugin name="Capture" value="CDVCapture" />
+ <plugin name="SplashScreen" value="CDVSplashScreen" />
+ <plugin name="Battery" value="CDVBattery" />
+ <plugin name="Globalization" value="CDVGlobalization" />
+ <plugin name="InAppBrowser" value="CDVInAppBrowser" />
+ <plugin name="Zip" value="Zip" />
+ <plugin name="ChromeExtensionURLs" onload="true" value="ChromeExtensionURLs" />
+ <plugin name="ChromeI18n" value="ChromeI18n" />
+ <plugin name="ChromeSocket" value="ChromeSocket" />
+ <plugin name="ChromeStorage" value="ChromeStorage" />
+ <plugin name="CordovaAppHarnessRedirect" onload="true" value="CordovaAppHarnessRedirect" />
+ </plugins>
+ <content src="chromeapp.html" />
+ <access origin="*" />
+ <access origin="chrome-extension://*" />
+ <access origin="cdv-app-harness://*" />
+ <preference name="KeyboardDisplayRequiresUserAction" value="true" />
+ <preference name="SuppressesIncrementalRendering" value="false" />
+ <preference name="UIWebViewBounce" value="true" />
+ <preference name="TopActivityIndicator" value="gray" />
+ <preference name="EnableLocation" value="false" />
+ <preference name="EnableViewportScale" value="false" />
+ <preference name="AutoHideSplashScreen" value="true" />
+ <preference name="ShowSplashScreenSpinner" value="true" />
+ <preference name="MediaPlaybackRequiresUserAction" value="false" />
+ <preference name="AllowInlineMediaPlayback" value="false" />
+ <preference name="OpenAllWhitelistURLsInWebView" value="false" />
+ <preference name="BackupWebStorage" value="cloud" />
+ <preference name="phonegap-version" value="1.9.0" />
+ <preference name="orientation" value="default" />
+ <preference name="target-device" value="universal" />
+ <preference name="fullscreen" value="false" />
+</widget>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/chromeapp.html
----------------------------------------------------------------------
diff --git a/www/crx_files/www/chromeapp.html b/www/crx_files/www/chromeapp.html
new file mode 100644
index 0000000..3cbd68d
--- /dev/null
+++ b/www/crx_files/www/chromeapp.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2012 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="format-detection" content="telephone=no">
+ <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
+ <script src="cordova.js"></script>
+ </head>
+ <body></body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/chromeappstyles.css
----------------------------------------------------------------------
diff --git a/www/crx_files/www/chromeappstyles.css b/www/crx_files/www/chromeappstyles.css
new file mode 100644
index 0000000..277f4fe
--- /dev/null
+++ b/www/crx_files/www/chromeappstyles.css
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Contains extra user-agent styles to apply to all Chrome App windows.
+ *
+ * These should be kept in sync with:
+ * http://code.google.com/searchframe#OAMlx_jo-ck/src/chrome/renderer/resources/extensions/platform_app.css
+ */
+body { -webkit-user-select: none; }
+html, body { overflow: hidden; }
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/chromebgpage.html
----------------------------------------------------------------------
diff --git a/www/crx_files/www/chromebgpage.html b/www/crx_files/www/chromebgpage.html
new file mode 100644
index 0000000..b732eaa
--- /dev/null
+++ b/www/crx_files/www/chromebgpage.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!--
+Copyright (c) 2012 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<html>
+ <body>
+ <script>parent.chrome.mobile.impl.bgInit(this)</script>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/cordova_plugins.json
----------------------------------------------------------------------
diff --git a/www/crx_files/www/cordova_plugins.json b/www/crx_files/www/cordova_plugins.json
new file mode 100644
index 0000000..fe11f7c
--- /dev/null
+++ b/www/crx_files/www/cordova_plugins.json
@@ -0,0 +1 @@
+[{"file":"plugins/chrome/api/bootstrap.js","id":"chrome.bootstrap","runs":true},{"file":"plugins/chrome/api/app/runtime.js","id":"chrome.app.runtime","clobbers":["chrome.app.runtime"]},{"file":"plugins/chrome/api/app/window.js","id":"chrome.app.window","clobbers":["chrome.app.window"]},{"file":"plugins/chrome/api/helpers/stubs.js","id":"chrome.helpers.stubs"},{"file":"plugins/chrome/api/mobile.js","id":"chrome.mobile.impl","clobbers":["chrome.mobile.impl"]},{"file":"plugins/chrome/api/runtime.js","id":"chrome.runtime","clobbers":["chrome.runtime"]},{"file":"plugins/chrome.common/events.js","id":"chrome.common.events","clobbers":["chrome.Event"]},{"file":"plugins/chrome.fileSystem/fileSystem.js","id":"chrome.fileSystem.FileSystem","clobbers":["chrome.fileSystem"]},{"file":"plugins/chrome.i18n/i18n.js","id":"chrome.i18n.I18n","clobbers":["chrome.i18n"]},{"file":"plugins/chrome.identity/identity.js","id":"chrome.identity.Identity","clobbers":["chrome.identity","chrome.experimental.iden
tity"]},{"file":"plugins/chrome.socket/socket.js","id":"chrome.socket.Socket","clobbers":["chrome.socket"]},{"file":"plugins/chrome.storage/storage.js","id":"chrome.storage.Storage","clobbers":["chrome.storage"]}]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.common/events.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.common/events.js b/www/crx_files/www/plugins/chrome.common/events.js
new file mode 100644
index 0000000..6f868b1
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.common/events.js
@@ -0,0 +1,53 @@
+cordova.define("chrome.common.events", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var Event = function(opt_eventName) {
+ this.name = opt_eventName || '';
+ this.listeners = [];
+};
+
+// Deliberately not filtering functions that are already added.
+// I tested on desktop and it will call your callback once for each addListener.
+Event.prototype.addListener = function(cb) {
+ this.listeners.push(cb);
+};
+
+Event.prototype.findListener_ = function(cb) {
+ for(var i = 0; i < this.listeners.length; i++) {
+ if (this.listeners[i] == cb) {
+ return i;
+ }
+ }
+
+ return -1;
+};
+
+Event.prototype.removeListener = function(cb) {
+ var index = this.findListener_(cb);
+ if (index >= 0) {
+ this.listeners.splice(index, 1);
+ }
+};
+
+Event.prototype.hasListener = function(cb) {
+ return this.findListener_(cb) >= 0;
+};
+
+Event.prototype.hasListeners = function() {
+ return this.listeners.length > 0;
+};
+
+Event.prototype.fire = function() {
+ for (var i = 0; i < this.listeners.length; i++) {
+ this.listeners[i].apply(this, arguments);
+ }
+};
+
+// Stubs since we don't support Rules.
+Event.prototype.addRules = function() { };
+Event.prototype.getRules = function() { };
+Event.prototype.removeRules = function() { };
+
+module.exports = Event;
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.fileSystem/fileSystem.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.fileSystem/fileSystem.js b/www/crx_files/www/plugins/chrome.fileSystem/fileSystem.js
new file mode 100644
index 0000000..ce613e5
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.fileSystem/fileSystem.js
@@ -0,0 +1,142 @@
+cordova.define("chrome.fileSystem.FileSystem", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var platformId = cordova.require('cordova/platform').id;
+var FileEntry = cordova.require('cordova/plugin/FileEntry');
+
+exports.getDisplayPath = function(fileEntry, callback) {
+ callback(fileEntry.fullPath);
+};
+
+exports.getWritableEntry = function(fileEntry, callback) {
+ callback(null);
+};
+
+exports.isWritableEntry = function(fileEntry, callback) {
+ callback(false);
+};
+
+exports.chooseEntry = function(options, callback) {
+ // Ensure that the type is either unspecified or specified as 'openFile', as nothing else is supported.
+ if (options.type && options.type != 'openFile') {
+ // TODO(maxw): Determine a "more correct" way to fail here.
+ callback(null);
+ return;
+ }
+
+ // Create the callback for getFile.
+ // It creates a file entry and passes it to the chooseEntry callback.
+ var onFileReceived = function(nativeUri) {
+ var onUriResolved = function(fileEntry) {
+ callback(fileEntry);
+ };
+
+ var onUriResolveError = function(e) {
+ console.log(e.target.error.code);
+ };
+
+ resolveLocalFileSystemURI(nativeUri, onUriResolved, onUriResolveError);
+ };
+
+ if (platformId == 'ios') {
+ getFileIos(options, onFileReceived);
+ } else if (platformId == 'android') {
+ getFileAndroid(options, onFileReceived);
+ }
+};
+
+function getFileIos(options, onFileReceivedCallback) {
+ // Determine the media type.
+ var mediaType = determineMediaType(options.accepts, options.acceptsAllTypes);
+
+ // Prepare the options for getting the file.
+ var getFileOptions = { destinationType: navigator.camera.DestinationType.NATIVE_URI,
+ sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY,
+ mediaType: mediaType };
+
+ // Use the camera to get an image or video.
+ navigator.camera.getPicture(onFileReceivedCallback, null, getFileOptions);
+}
+
+function getFileAndroid(options, onFileReceivedCallback) {
+ var AndroidFileChooser = cordova.require('cordova/plugin/android/filechooser');
+
+ // Determine the relevant mime types.
+ var mimeTypes = determineMimeTypes(options.accepts, options.acceptsAllTypes);
+
+ // Use the file chooser to get a file.
+ AndroidFileChooser.chooseFile(onFileReceivedCallback, null, mimeTypes);
+}
+
+function determineMediaType(acceptOptions, acceptsAllTypes) {
+ if (acceptsAllTypes) {
+ return navigator.camera.MediaType.ALLMEDIA;
+ }
+
+ var imageMimeTypeRegex = /^image\//;
+ var videoMimeTypeRegex = /^video\//;
+ var imageExtensionRegex = /^(?:jpg|png)$/;
+ var videoExtensionRegex = /^mov$/;
+ var imagesAllowed = false;
+ var videosAllowed = false;
+
+ // Iterate through all accept options.
+ // If we see anything image related, allow images. If we see anything video related, allow videos.
+ if (acceptOptions) {
+ for (var i = 0; i < acceptOptions.length; i++) {
+ if (acceptOptions[i].mimeTypes) {
+ for (var j = 0; j < acceptOptions[i].mimeTypes.length; j++) {
+ if (imageMimeTypeRegex.test(acceptOptions[i].mimeTypes[j])) {
+ imagesAllowed = true;
+ } else if (videoMimeTypeRegex.test(acceptOptions[i].mimeTypes[j])) {
+ videosAllowed = true;
+ }
+ }
+ }
+ if (acceptOptions[i].extensions) {
+ for (var k = 0; k < acceptOptions[i].extensions.length; k++) {
+ if (imageExtensionRegex.test(acceptOptions[i].extensions[k])) {
+ imagesAllowed = true;
+ } else if (videoExtensionRegex.test(acceptOptions[i].extensions[k])) {
+ videosAllowed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (imagesAllowed && !videosAllowed) {
+ return navigator.camera.MediaType.PICTURE;
+ } else if (!imagesAllowed && videosAllowed) {
+ return navigator.camera.MediaType.VIDEO;
+ }
+
+ return navigator.camera.MediaType.ALLMEDIA;
+}
+
+function determineMimeTypes(acceptOptions, acceptsAllTypes) {
+ if (acceptsAllTypes) {
+ return [ '*/*' ];
+ }
+
+ // Pull out all the mime types.
+ // TODO(maxw): Determine mime types from extensions and add them to the returned list.
+ var mimeTypes = [ ];
+ if (acceptOptions) {
+ for (var i = 0; i < acceptOptions.length; i++) {
+ if (acceptOptions[i].mimeTypes) {
+ for (var j = 0; j < acceptOptions[i].mimeTypes.length; j++) {
+ mimeTypes.push(acceptOptions[i].mimeTypes[j]);
+ }
+ }
+ }
+ }
+
+ if (mimeTypes.length !== 0) {
+ return mimeTypes;
+ }
+
+ return [ '*/*' ];
+}
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.i18n/i18n.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.i18n/i18n.js b/www/crx_files/www/plugins/chrome.i18n/i18n.js
new file mode 100644
index 0000000..905466c
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.i18n/i18n.js
@@ -0,0 +1,185 @@
+cordova.define("chrome.i18n.I18n", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var exec = cordova.require('cordova/exec');
+var runtime = require('chrome.runtime');
+
+exports.getAcceptLanguages = function(callback) {
+ // In the chrome implementation, acceptLanguage value can change with updates so we make a native call to get the system language
+ exec(callback, callback, 'ChromeI18n', 'getAcceptLanguages', []);
+};
+
+exports.getMessage = function(messageName, substitutions) {
+ // In the chrome implementation, the locale to translate to DOES NOT change with updates, it is keyed of window.navigator.language which is static for a session.
+ // This is implemented in _getLocalesToUse()
+ if(
+ (typeof messageName !== 'string') ||
+ (Array.isArray(substitutions) && substitutions.length > 9)
+ ) {
+ return;
+ }
+ messageName = messageName.toLowerCase();
+ var ret = '';
+ var localeChain = _getLocalesToUse();
+ var contentsForMessageName = _getMessageFromMessageJson(messageName, localeChain);
+ if(contentsForMessageName) {
+ ret = _applySubstitutions(contentsForMessageName, substitutions);
+ }
+ return ret;
+};
+
+function _endsWith(string, endString) {
+ if(endString.length > string.length) {
+ return false;
+ } else {
+ return (string.lastIndexOf(endString) === string.length - endString.length);
+ }
+}
+
+function _getFilePathForLocale(locale) {
+ return 'locales/' + locale.toLowerCase() + '/messages.json';
+}
+
+function _toLowerCaseMessageAndPlaceholders(obj) {
+ if(typeof obj !== 'undefined') {
+ var newObj = {};
+ for(var field in obj) {
+ if(obj[field].placeholders) {
+ var newPlaceholders = {};
+ for(var placeholderField in obj[field].placeholders) {
+ newPlaceholders[placeholderField.toLowerCase()] = obj[field].placeholders[placeholderField];
+ }
+ obj[field].placeholders = newPlaceholders;
+ }
+ newObj[field.toLowerCase()] = obj[field];
+ }
+ return newObj;
+ }
+}
+
+function _getDefaultLocale() {
+ var manifestJson = runtime.getManifest();
+ if(manifestJson.default_locale) {
+ return manifestJson.default_locale;
+ } else {
+ throw new Error('Default locale not defined');
+ }
+}
+
+var memoizedJsonContents = {};
+function _getMessageFromMessageJson(messageName, localeChain) {
+ for(var i = 0; i < localeChain.length; i++) {
+ var locale = localeChain[i];
+ if (!memoizedJsonContents[locale]) {
+ var fileName = _getFilePathForLocale(locale);
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', fileName, false /* sync */);
+ xhr.send(null);
+ var contents = eval('(' + xhr.responseText + ')');
+ // convert all fields to lower case to check case insensitively
+ contents = _toLowerCaseMessageAndPlaceholders(contents);
+ memoizedJsonContents[locale] = contents;
+ }
+ if(memoizedJsonContents[locale][messageName]) {
+ return memoizedJsonContents[locale][messageName];
+ }
+ }
+}
+
+function _isLocaleAvailable(locale) {
+ var fileName = _getFilePathForLocale(locale);
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', fileName, false /* sync */);
+ xhr.send(null);
+ availableLocales[locale] = (xhr.status === 200);
+}
+
+var chosenLocales;
+function _getLocalesToUse() {
+ if(!chosenLocales) {
+ // language returned by window.navigator is in format en-US, need to change it to en_us
+ var windowLocale = window.navigator.language.replace('-', '_').toLowerCase();
+ var localesToUse = [windowLocale];
+ // Construct fallback chain
+ var lastIndex;
+ while((lastIndex = windowLocale.lastIndexOf('_')) !== -1) {
+ windowLocale = windowLocale.substring(0, lastIndex);
+ localesToUse.push(windowLocale);
+ }
+ var defaultLocale = _getDefaultLocale().toLowerCase();
+ if(localesToUse.indexOf(defaultLocale) == -1) {
+ localesToUse.push(defaultLocale);
+ }
+
+ chosenLocales = [] ;
+ for(var i = 0; i < localesToUse.length; i++) {
+ var currentLocale = localesToUse[i];
+ if(_isLocaleAvailable(currentLocale)) {
+ chosenLocales.push(currentLocale);
+ }
+ }
+ }
+ if(chosenLocales.length == 0) {
+ throw new Error('No usable locale.');
+ }
+ return chosenLocales;
+}
+
+function _getSubstitutionString(match, substitutions) {
+ if(match == '$$') {
+ return '$';
+ } else if(match == '$') {
+ return '';
+ }
+ else {
+ var locBaseOne = parseInt(match.substring(1));
+ if(isNaN(locBaseOne) || locBaseOne <= 0) {
+ return '';
+ }
+
+ if(substitutions[locBaseOne - 1]) {
+ return substitutions[locBaseOne - 1];
+ } else {
+ return '';
+ }
+ }
+}
+
+function _getPlaceholderText(placeholders, substitutions, match) {
+ // Switch to lower case to do case insensitive checking for matches
+ var placeholderField = match.substring(1, match.length - 1);
+ placeholderField = placeholderField.toLowerCase();
+ if(placeholders[placeholderField]) {
+ // form $1, $2 etc or '$$' or '$'
+ var placeholderText = placeholders[placeholderField].content.replace(/\$(([0-9]+)|\$)?/g, function(match) {
+ var substitutionString = _getSubstitutionString(match, substitutions);
+ return substitutionString;
+ });
+ return placeholderText;
+ } else {
+ return '';
+ }
+}
+
+function _applySubstitutions(messageObject, substitutions) {
+ if(typeof substitutions === 'undefined') {
+ substitutions = [];
+ } else if(Object.prototype.toString.call(substitutions) !== '[object Array]') {
+ substitutions = [substitutions];
+ }
+ // Look for any strings of form $WORD$ eg: $1stName$, form $1, $2 etc or any lone '$'
+ // Order of preference is as in this comment
+ var ret = messageObject.message.replace( /\$(([0-9a-zA-Z_]*\$)|([0-9]*))?/g, function(matchedString) {
+ // check which category of matchedString it is
+ if(matchedString.match(/\$[0-9a-zA-Z_]+\$/)) { // form $WORD$
+ var placeholderText = _getPlaceholderText(messageObject.placeholders, substitutions, matchedString);
+ return placeholderText;
+ } else { // form $1, $2 etc or '$$' or '$'
+ var substitutionString = _getSubstitutionString(matchedString, substitutions);
+ return substitutionString;
+ }
+ });
+ return ret;
+}
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.identity/identity.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.identity/identity.js b/www/crx_files/www/plugins/chrome.identity/identity.js
new file mode 100644
index 0000000..54f1597
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.identity/identity.js
@@ -0,0 +1,161 @@
+cordova.define("chrome.identity.Identity", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var platformId = cordova.require('cordova/platform').id;
+var runtime = require('chrome.runtime');
+
+exports.TokenDetails = function(interactive) {
+ this.interactive = interactive || false;
+};
+
+exports.WebAuthFlowDetails = function(url, interactive, width, height, left, top) {
+ if (typeof url == 'undefined') {
+ throw new Error('Url required');
+ }
+ this.url = url;
+ this.interactive = interactive || false;
+ this.width = width;
+ this.height = height;
+ this.left = left;
+ this.top = top;
+};
+
+exports.getAuthToken = function(details, callback) {
+ if(typeof details == 'function') {
+ callback = details;
+ details = new exports.TokenDetails();
+ }
+ if (typeof callback == 'undefined') {
+ chrome.runtime.lastError = { 'message' : 'Callback function required' };
+ // Not calling callback as it wasnt provided
+ return;
+ }
+ var win = function(token) {
+ callback(token);
+ };
+ var fail = function() {
+ callback();
+ };
+
+ if (platformId == 'android') {
+ // Use native implementation for logging into google accounts
+ cordova.exec(win, fail, 'ChromeIdentity', 'getAuthToken', [details]);
+ } else {
+ // Use web app oauth flow
+ _getAuthTokenJS(win, fail, details);
+ }
+};
+
+exports.launchWebAuthFlow = function(details, callback) {
+ var failed = false;
+ var failMessage;
+ if (typeof details == 'undefined') {
+ failed = true;
+ failMessage = 'WebAuthFlowDetails required';
+ } else if (typeof callback == 'undefined') {
+ failed = true;
+ failMessage = 'Callback function required';
+ }
+
+ if(failed === true) {
+ chrome.runtime.lastError = { 'message' : failMessage };
+ // Not calling callback as it wasnt provided
+ return;
+ }
+
+ var finalURL = details.url;
+ var extractedRedirectedURL = _getParameterFromUrl(finalURL, 'redirect_uri', '?', '#');
+
+ if(typeof extractedRedirectedURL == 'undefined') {
+ chrome.runtime.lastError = { 'message' : 'launchWebAuthFlow: Parameter redirect_uri not found.' };
+ callback();
+ } else {
+ _launchInAppBrowser(finalURL, extractedRedirectedURL, callback);
+ }
+};
+
+function _getAuthTokenJS(win, fail , details) {
+ var failed = false;
+ var failMessage;
+ if(!details.interactive) {
+ // We cannot support non interactive mode.
+ // This requires the ability to use invisible InAppBrowser windows, which is not currently supported
+ failed = true;
+ failMessage = 'Unsupported mode - Non interactive mode is not supported';
+ }
+ var manifestJson = runtime.getManifest();
+ if(typeof manifestJson == 'undefined') {
+ failed = true;
+ failMessage = 'manifest.json is not defined';
+ } else if(typeof manifestJson.oauth2 == 'undefined') {
+ failed = true;
+ failMessage = 'oauth2 missing from manifest.json';
+ } else if(typeof manifestJson.oauth2.client_id == 'undefined') {
+ failed = true;
+ failMessage = 'client_id missing from manifest.json';
+ } else if(typeof manifestJson.oauth2.scopes == 'undefined') {
+ failed = true;
+ failMessage = 'scopes missing from manifest.json';
+ }
+
+ if(failed === true) {
+ chrome.runtime.lastError = { 'message' : failMessage };
+ fail();
+ }
+
+ var authURLBase = 'https://accounts.google.com/o/oauth2/auth?response_type=token';
+ var redirect_uri = 'http://www.google.com';
+ var client_id = manifestJson.oauth2.client_id;
+ var scope = manifestJson.oauth2.scopes;
+ var finalURL = authURLBase + '&redirect_uri=' + encodeURIComponent(redirect_uri) + '&client_id=' + encodeURIComponent(client_id) + '&scope=' + encodeURIComponent(scope.join('&'));
+
+ _launchInAppBrowser(finalURL, redirect_uri, function(newLoc) {
+ var token = _getParameterFromUrl(newLoc, 'access_token', '#');
+ if(typeof token == 'undefined') {
+ chrome.runtime.lastError = { 'message' : 'The redirect uri did not have the access token' };
+ fail();
+ } else {
+ win(token);
+ }
+ });
+}
+
+function _getParameterFromUrl(url, param, startString, endString) {
+ var splitUrl = url;
+ var urlParts;
+ if(typeof startString != 'undefined') {
+ urlParts = splitUrl.split(startString);
+ if(urlParts.length < 2) {
+ return;
+ } else {
+ splitUrl = urlParts[1];
+ }
+ }
+ if(typeof endString != 'undefined') {
+ urlParts = splitUrl.split(endString);
+ splitUrl = urlParts[0];
+ }
+ var vars = splitUrl.split('&');
+ for (var i = 0; i < vars.length; i++) {
+ var pair = vars[i].split('=');
+ // If first entry with this name
+ if (pair[0] === param) {
+ return decodeURIComponent(pair[1]);
+ }
+ }
+}
+
+function _launchInAppBrowser(authURL, redirectedURL, callback) {
+ var oAuthBrowser = window.open(authURL, '_blank', 'location=yes');
+ var listener = function(event) {
+ var newLoc = event.url;
+ if(newLoc.indexOf(redirectedURL) === 0 && newLoc.indexOf('#') !== -1) {
+ oAuthBrowser.removeEventListener('loadstart', listener);
+ oAuthBrowser.close();
+ callback(newLoc);
+ }
+ };
+ oAuthBrowser.addEventListener('loadstart', listener);
+}
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.socket/socket.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.socket/socket.js b/www/crx_files/www/plugins/chrome.socket/socket.js
new file mode 100644
index 0000000..389eec9
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.socket/socket.js
@@ -0,0 +1,216 @@
+cordova.define("chrome.socket.Socket", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var platform = cordova.require('cordova/platform');
+var exec = cordova.require('cordova/exec');
+
+exports.create = function(socketMode, stuff, callback) {
+ if (typeof stuff == 'function') {
+ callback = stuff;
+ stuff = {};
+ }
+ var win = callback && function(socketId) {
+ var socketInfo = {
+ socketId: socketId
+ };
+ callback(socketInfo);
+ };
+ exec(win, null, 'ChromeSocket', 'create', [socketMode]);
+};
+
+exports.destroy = function(socketId) {
+ exec(null, null, 'ChromeSocket', 'destroy', [socketId]);
+};
+
+
+exports.connect = function(socketId, address, port, callback) {
+ var win = callback && function() {
+ callback(0);
+ };
+ var fail = callback && function() {
+ callback(-1);
+ };
+ exec(win, fail, 'ChromeSocket', 'connect', [socketId, address, port]);
+};
+
+exports.bind = function(socketId, address, port, callback) {
+ var win = callback && function() {
+ callback(0);
+ };
+ var fail = callback && function() {
+ callback(-1);
+ };
+ exec(win, fail, 'ChromeSocket', 'bind', [socketId, address, port]);
+};
+
+exports.disconnect = function(socketId) {
+ exec(null, null, 'ChromeSocket', 'disconnect', [socketId]);
+};
+
+
+exports.read = function(socketId, bufferSize, callback) {
+ if (typeof bufferSize == 'function') {
+ callback = bufferSize;
+ bufferSize = 0;
+ }
+ var win = callback && function(data) {
+ var readInfo = {
+ resultCode: data.byteLength || 1,
+ data: data
+ };
+ callback(readInfo);
+ };
+ var fail = callback && function() {
+ var readInfo = {
+ resultCode: 0
+ };
+ callback(readInfo);
+ };
+ exec(win, fail, 'ChromeSocket', 'read', [socketId, bufferSize]);
+};
+
+exports.write = function(socketId, data, callback) {
+ var type = Object.prototype.toString.call(data).slice(8, -1);
+ if (type != 'ArrayBuffer') {
+ throw new Error('chrome.socket.write - data is not an ArrayBuffer! (Got: ' + type + ')');
+ }
+ var win = callback && function(bytesWritten) {
+ var writeInfo = {
+ bytesWritten: bytesWritten
+ };
+ callback(writeInfo);
+ };
+ var fail = callback && function() {
+ var writeInfo = {
+ bytesWritten: 0
+ };
+ callback(writeInfo);
+ };
+ exec(win, fail, 'ChromeSocket', 'write', [socketId, data]);
+};
+
+
+exports.recvFrom = function(socketId, bufferSize, callback) {
+ if (typeof bufferSize == 'function') {
+ callback = bufferSize;
+ bufferSize = 0;
+ }
+ var win;
+ if (platform.id == 'android') {
+ win = callback && (function() {
+ var data;
+ var call = 0;
+ return function(arg) {
+ if (call === 0) {
+ data = arg;
+ call++;
+ } else {
+ var recvFromInfo = {
+ resultCode: data.byteLength || 1,
+ data: data,
+ address: arg.address,
+ port: arg.port
+ };
+
+ callback(recvFromInfo);
+ }
+ };
+ })();
+ } else {
+ win = callback && function(data, address, port) {
+ var recvFromInfo = {
+ resultCode: data.byteLength || 1,
+ data: data,
+ address: address,
+ port: port
+ };
+ callback(recvFromInfo);
+ };
+ }
+
+ var fail = callback && function() {
+ var readInfo = {
+ resultCode: 0
+ };
+ callback(readInfo);
+ };
+ exec(win, fail, 'ChromeSocket', 'recvFrom', [socketId, bufferSize]);
+};
+
+exports.sendTo = function(socketId, data, address, port, callback) {
+ var type = Object.prototype.toString.call(data).slice(8, -1);
+ if (type != 'ArrayBuffer') {
+ throw new Error('chrome.socket.write - data is not an ArrayBuffer! (Got: ' + type + ')');
+ }
+ var win = callback && function(bytesWritten) {
+ var writeInfo = {
+ bytesWritten: bytesWritten
+ };
+ callback(writeInfo);
+ };
+ var fail = callback && function() {
+ var writeInfo = {
+ bytesWritten: 0
+ };
+ callback(writeInfo);
+ };
+ exec(win, fail, 'ChromeSocket', 'sendTo', [{ socketId: socketId, address: address, port: port }, data]);
+};
+
+
+exports.listen = function(socketId, address, port, backlog, callback) {
+ if (typeof backlog == 'function') {
+ callback = backlog;
+ backlog = 0;
+ }
+ var win = callback && function() {
+ callback(0);
+ };
+ var fail = callback && function() {
+ callback(-1);
+ };
+ exec(win, fail, 'ChromeSocket', 'listen', [socketId, address, port, backlog]);
+};
+
+exports.accept = function(socketId, callback) {
+ var win = callback && function(acceptedSocketId) {
+ var acceptInfo = {
+ resultCode: 0,
+ socketId: acceptedSocketId
+ };
+ callback(acceptInfo);
+ };
+ exec(win, null, 'ChromeSocket', 'accept', [socketId]);
+};
+
+
+exports.setKeepAlive = function() {
+ console.warn('chrome.socket.setKeepAlive not implemented yet');
+};
+
+exports.setNoDelay = function() {
+ console.warn('chrome.socket.setNoDelay not implemented yet');
+};
+
+exports.getInfo = function(socketId, callback) {
+ if (platform.id == 'android') {
+ console.warn('chrome.socket.getInfo not implemented yet');
+ return;
+ }
+ var win = callback && function(result) {
+ result.connected = !!result.connected;
+ callback(result);
+ };
+ exec(win, null, 'ChromeSocket', 'getInfo', [socketId]);
+};
+
+exports.getNetworkList = function(callback) {
+ if (platform.id == 'android') {
+ console.warn('chrome.socket.getNetworkList not implemented yet');
+ return;
+ }
+ exec(callback, null, 'ChromeSocket', 'getNetworkList', []);
+};
+
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome.storage/storage.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome.storage/storage.js b/www/crx_files/www/plugins/chrome.storage/storage.js
new file mode 100644
index 0000000..4d6da75
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome.storage/storage.js
@@ -0,0 +1,202 @@
+cordova.define("chrome.storage.Storage", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var exports = module.exports;
+var exec = cordova.require('cordova/exec');
+
+function StorageChange(oldValue, newValue) {
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+}
+
+function _jsonReplacer(key) {
+ // Don't use the value passed in since it has already gone through toJSON().
+ var value = this[key];
+ // Refer to:
+ // chrome/src/content/renderer/v8_value_converter_impl.cc&l=165
+ if (value && (typeof value == 'object' || typeof value == 'function')) {
+ var typeName = Object.prototype.toString.call(value).slice(8, -1);
+ if (typeName != 'Array' && typeName != 'Object') {
+ value = {};
+ }
+ }
+ return value;
+}
+
+function _scrubValues(o) {
+ if (typeof o != 'undefined') {
+ var t = JSON.stringify(o, _jsonReplacer);
+ return JSON.parse(t);
+ }
+}
+
+function _calculateChanges(oldKeyVals, newKeyVals) {
+ var ret = {};
+ for(var key in newKeyVals) {
+ if (newKeyVals.hasOwnProperty(key)) {
+ ret[key] = new StorageChange(oldKeyVals[key], newKeyVals[key]);
+ }
+ }
+ return ret;
+}
+
+function _convertToObject(obj) {
+ var ret;
+ if (Array.isArray(obj)) {
+ ret = {};
+ for(var i = 0; i < obj.length; i++) {
+ ret[obj[i]] = undefined;
+ }
+ } else if (typeof obj == 'object') {
+ ret = obj;
+ } else if (typeof obj === 'string') {
+ ret = {};
+ ret[obj] = undefined;
+ }
+ return ret;
+}
+
+function StorageArea(syncStorage, changedEvent) {
+ this._sync = syncStorage;
+ this._changedEvent = changedEvent;
+}
+
+StorageArea.prototype._getAreaName = function() {
+ return (this._sync? 'sync' : 'local');
+};
+
+StorageArea.prototype.get = function(keys, callback) {
+ if (typeof keys == 'function') {
+ callback = keys;
+ keys = null;
+ } else if (typeof keys === 'string') {
+ keys = [keys];
+ }
+ var win = callback && function(args) {
+ callback(args);
+ };
+ var fail = callback && function() {
+ callback();
+ };
+ var param = _scrubValues(keys);
+ exec(win, fail, 'ChromeStorage', 'get', [this._sync, param]);
+};
+
+StorageArea.prototype.getBytesInUse = function(keys, callback) {
+ if (typeof keys == 'function') {
+ callback = keys;
+ keys = null;
+ } else if (typeof keys === 'string') {
+ keys = [keys];
+ }
+ var win = callback && function(bytes) {
+ callback(bytes);
+ };
+ var fail = callback && function() {
+ callback(-1);
+ };
+ var param = _scrubValues(keys);
+ exec(win, fail, 'ChromeStorage', 'getBytesInUse', [this._sync, param]);
+};
+
+StorageArea.prototype.set = function(keyVals, callback) {
+ if (typeof keyVals == 'function') {
+ callback = keyVals;
+ keyVals = null;
+ }
+ var self = this;
+ var param = _scrubValues(keyVals);
+ var fail = callback && function() {
+ callback(-1);
+ };
+ var win;
+ if(self._changedEvent.hasListeners()) {
+ win = function(oldKeyVals) {
+ if(callback) {
+ callback(0);
+ }
+ var newKeyVals = _convertToObject(param);
+ var storageChanges = _calculateChanges(oldKeyVals, newKeyVals);
+ self._changedEvent.fire(storageChanges, self._getAreaName());
+ };
+ } else {
+ win = callback && function() {
+ callback(0);
+ };
+ }
+ exec(win, fail, 'ChromeStorage', 'set', [self._sync, param]);
+};
+
+StorageArea.prototype.remove = function(keys, callback) {
+ if (typeof keys == 'function') {
+ callback = keys;
+ keys = null;
+ } else if (typeof keys === 'string') {
+ keys = [keys];
+ }
+ var self = this;
+ var param = _scrubValues(keys);
+ var fail = callback && function() {
+ callback(-1);
+ };
+ var win;
+ if(self._changedEvent.hasListeners()) {
+ win = function(oldKeyVals) {
+ if(callback) {
+ callback(0);
+ }
+ var newKeyVals = _convertToObject(Object.keys(oldKeyVals));
+ var storageChanges = _calculateChanges(oldKeyVals, newKeyVals);
+ self._changedEvent.fire(storageChanges, self._getAreaName());
+ };
+ } else {
+ win = callback && function() {
+ callback(0);
+ };
+ }
+ exec(win, fail, 'ChromeStorage', 'remove', [self._sync, param]);
+};
+
+StorageArea.prototype.clear = function(callback) {
+ var self = this;
+ var fail = callback && function() {
+ callback(-1);
+ };
+ var win;
+ if(self._changedEvent.hasListeners()) {
+ win = function(oldKeyVals) {
+ if(callback) {
+ callback(0);
+ }
+ var newKeyVals = _convertToObject(Object.keys(oldKeyVals));
+ var storageChanges = _calculateChanges(oldKeyVals, newKeyVals);
+ self._changedEvent.fire(storageChanges, self._getAreaName());
+ };
+ } else {
+ win = callback && function() {
+ callback(0);
+ };
+ }
+ exec(win, fail, 'ChromeStorage', 'clear', [self._sync]);
+};
+
+// TODO(braden): How do we want to handle this event when we're not in a Chrome app?
+var Event = require('chrome.common.events');
+if (Event) {
+ exports.onChanged = new Event('onChanged');
+}
+
+var local = new StorageArea(false, exports.onChanged);
+local.QUOTA_BYTES = 5242880;
+var sync = new StorageArea(true, exports.onChanged);
+sync.MAX_ITEMS = 512;
+sync.MAX_WRITE_OPERATIONS_PER_HOUR = 1000;
+sync.QUOTA_BYTES_PER_ITEM = 4096;
+sync.MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE = 10;
+sync.QUOTA_BYTES = 102400;
+
+exports.local = local;
+exports.sync = sync;
+
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/app/runtime.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/app/runtime.js b/www/crx_files/www/plugins/chrome/api/app/runtime.js
new file mode 100644
index 0000000..4a2288c
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/app/runtime.js
@@ -0,0 +1,7 @@
+cordova.define("chrome.app.runtime", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var Event = require('chrome.common.events');
+exports.onLaunched = new Event('onLaunched');
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/app/window.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/app/window.js b/www/crx_files/www/plugins/chrome/api/app/window.js
new file mode 100644
index 0000000..3a6484d
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/app/window.js
@@ -0,0 +1,156 @@
+cordova.define("chrome.app.window", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var Event = require('chrome.common.events');
+var mobile = require('chrome.mobile.impl');
+
+// The AppWindow created by chrome.app.window.create.
+var createdAppWindow = null;
+var dummyNode = document.createElement('a');
+
+function AppWindow() {
+ this.contentWindow = mobile.fgWindow;
+ this.id = '';
+}
+
+function unsupportedApi(api) {
+ return function() {
+ console.warn(api + ' is not supported on mobile.');
+ };
+}
+
+AppWindow.prototype = {
+ restore: unsupportedApi('AppWindow.restore'),
+ moveTo: unsupportedApi('AppWindow.moveTo'),
+ clearAttention: unsupportedApi('AppWindow.clearAttention'),
+ minimize: unsupportedApi('AppWindow.minimize'),
+ drawAttention: unsupportedApi('AppWindow.drawAttention'),
+ focus: unsupportedApi('AppWindow.focus'),
+ resizeTo: unsupportedApi('AppWindow.resizeTo'),
+ maximize: unsupportedApi('AppWindow.maximize'),
+ close: unsupportedApi('AppWindow.close'),
+ setBounds: unsupportedApi('AppWindow.setBounds'),
+ onBoundsChanged: new Event('onBoundsChanged'),
+ onClosed: new Event('onClosed')
+};
+AppWindow.prototype.getBounds = function() {
+ return {
+ width: 0,
+ height: 0,
+ left: 0,
+ top: 0
+ };
+};
+
+function copyAttributes(srcNode, destNode) {
+ var attrs = srcNode.attributes;
+ for (var i = 0, attr; attr = attrs[i]; ++i) {
+ destNode.setAttribute(attr.name, attr.value);
+ }
+}
+
+function applyAttributes(attrText, destNode) {
+ dummyNode.innerHTML = '<a ' + attrText + '>';
+ copyAttributes(dummyNode.firstChild, destNode);
+}
+
+// Evals the scripts serially since sometimes browsers don't execute
+// them in the order they are injected :(.
+// TODO: This is clearly slower for multiple scripts. We could maybe see if
+// injecting after DOM mutation events fire?
+function evalScripts(rootNode, afterFunc) {
+ var scripts = Array.prototype.slice.call(rootNode.getElementsByTagName('script'));
+ var doc = rootNode.ownerDocument;
+ function helper() {
+ var script = scripts.shift();
+ if (!script) {
+ afterFunc && afterFunc();
+ // Don't bother with inline scripts since they aren't evalled on desktop.
+ } else if (script.src) {
+ var replacement = doc.createElement('script');
+ copyAttributes(script, replacement);
+ replacement.onload = helper;
+ script.parentNode.replaceChild(replacement, script);
+ } else {
+ helper();
+ }
+ }
+ helper();
+}
+
+function rewritePage(pageContent, filePath) {
+ var fgBody = mobile.fgWindow.document.body;
+ var fgHead = fgBody.previousElementSibling;
+
+ // fgHead.innerHTML causes a DOMException on Android 2.3.
+ while (fgHead.lastChild) {
+ fgHead.removeChild(fgHead.lastChild);
+ }
+
+ var startIndex = pageContent.search(/<html([\s\S]*?)>/i);
+ if (startIndex != -1) {
+ startIndex += RegExp.lastMatch.length;
+ // Copy over the attributes of the <html> tag.
+ applyAttributes(RegExp.lastParen, fgBody.parentNode);
+ } else {
+ startIndex = 0;
+ }
+
+ function afterBase() {
+ fgHead.insertAdjacentHTML('beforeend', headHtml);
+ evalScripts(fgHead, function() {
+ mobile.eventIframe.insertAdjacentHTML('afterend', pageContent);
+ evalScripts(fgBody)
+ });
+ }
+ // Put everything before the body tag in the head.
+ var endIndex = pageContent.search(/<body([\s\S]*?)>/i);
+ if (endIndex == -1) {
+ mobile.eventIframe.insertAdjacentHTML('afterend', 'Load error: Page is missing body tag.');
+ } else {
+ applyAttributes(RegExp.lastParen, fgBody);
+
+ // Don't bother removing the <body>, </body>, </html>. The browser's sanitizer removes them for us.
+ var headHtml = pageContent.slice(startIndex, endIndex);
+ pageContent = pageContent.slice(endIndex);
+
+ fgHead.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="chromeappstyles.css">');
+ var baseUrl = filePath.replace(/\/.*?$/, '');
+ if (baseUrl != filePath) {
+ fgHead.insertAdjacentHTML('beforeend', '<base href="' + encodeURIComponent(baseUrl) + '/">\n');
+ // setTimeout required for <base> to take effect for <link> elements (browser bug).
+ window.setTimeout(afterBase, 0);
+ } else {
+ afterBase();
+ }
+ }
+}
+
+exports.create = function(filePath, options, callback) {
+ if (createdAppWindow) {
+ console.log('ERROR - chrome.app.window.create called multiple times. This is unsupported.');
+ return;
+ }
+ createdAppWindow = new AppWindow();
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', filePath, true);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ // Call the callback before the page contents loads.
+ if (callback) {
+ callback(createdAppWindow);
+ }
+ var pageContent = xhr.responseText || 'Page load failed.';
+ rewritePage(pageContent, filePath);
+ cordova.fireWindowEvent('DOMContentReady');
+ cordova.fireWindowEvent('load');
+ }
+ };
+ xhr.send();
+};
+
+exports.current = function() {
+ return window == mobile.fgWindow ? createdAppWindow : null;
+};
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/bootstrap.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/bootstrap.js b/www/crx_files/www/plugins/chrome/api/bootstrap.js
new file mode 100644
index 0000000..51c28dc
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/bootstrap.js
@@ -0,0 +1,13 @@
+cordova.define("chrome.bootstrap", function(require, exports, module) {// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Initialization code for the Chrome plugins API.
+// Adds a deviceready listener that initializes the Chrome wrapper.
+
+console.log('adding event');
+document.addEventListener('deviceready', function() {
+ console.log('deviceready caught');
+ require('chrome.mobile.impl').init();
+});
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/helpers/stubs.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/helpers/stubs.js b/www/crx_files/www/plugins/chrome/api/helpers/stubs.js
new file mode 100644
index 0000000..ef57b83
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/helpers/stubs.js
@@ -0,0 +1,11 @@
+cordova.define("chrome.helpers.stubs", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+exports.createStub = function(obj, propName, value) {
+ obj.__defineGetter__(propName, function() {
+ console.warn('Access made to stub: ' + obj.__namespace__ + '.' + propName);
+ return value;
+ });
+};
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/mobile.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/mobile.js b/www/crx_files/www/plugins/chrome/api/mobile.js
new file mode 100644
index 0000000..28af8b8
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/mobile.js
@@ -0,0 +1,58 @@
+cordova.define("chrome.mobile.impl", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var chrome = window.chrome;
+
+exports.fgWindow = window;
+exports.bgWindow = null;
+exports.eventIframe = null;
+
+function createBgChrome() {
+ return {
+ __proto__: chrome,
+ app: {
+ __proto__: chrome.app,
+ window: {
+ __proto__: chrome.app.window,
+ current: function() { return null; }
+ }
+ }
+ };
+}
+
+exports.init = function() {
+ // Self-destruct so that code in here can be GC'ed.
+ exports.init = null;
+ var iframe = document.createElement('iframe');
+ iframe.src = 'chromebgpage.html';
+ iframe.style.display = 'none';
+ exports.eventIframe = iframe;
+ document.body.appendChild(iframe);
+};
+
+exports.bgInit = function(bgWnd) {
+ // Self-destruct so that code in here can be GC'ed.
+ exports.bgInit = null;
+ exports.bgWindow = bgWnd;
+ bgWnd.chrome = createBgChrome();
+ bgWnd.cordova = cordova;
+ exports.fgWindow.opener = exports.bgWindow;
+
+ function onLoad() {
+ bgWnd.removeEventListener('load', onLoad, false);
+ setTimeout(function() {
+ chrome.app.runtime.onLaunched.fire();
+ }, 0);
+ }
+ bgWnd.addEventListener('load', onLoad, false);
+
+ var manifestJson = chrome.runtime.getManifest();
+ var scripts = manifestJson.app.background.scripts;
+ var toWrite = '';
+ for (var i = 0, src; src = scripts[i]; ++i) {
+ toWrite += '<script src="' + encodeURI(src) + '"></sc' + 'ript>\n';
+ }
+ bgWnd.document.write(toWrite);
+};
+});
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/4d4e0b46/www/crx_files/www/plugins/chrome/api/runtime.js
----------------------------------------------------------------------
diff --git a/www/crx_files/www/plugins/chrome/api/runtime.js b/www/crx_files/www/plugins/chrome/api/runtime.js
new file mode 100644
index 0000000..58b3970
--- /dev/null
+++ b/www/crx_files/www/plugins/chrome/api/runtime.js
@@ -0,0 +1,58 @@
+cordova.define("chrome.runtime", function(require, exports, module) {// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var argscheck = cordova.require('cordova/argscheck');
+var Event = require('chrome.common.events');
+var stubs = require('chrome.helpers.stubs');
+var mobile = require('chrome.mobile.impl');
+var manifestJson = null;
+
+exports.onSuspend = new Event('onSuspend');
+exports.onInstalled = new Event('onInstalled');
+exports.onStartup = new Event('onStartup');
+exports.onSuspendCanceled = new Event('onSuspendCanceled');
+exports.onUpdateAvailable = new Event('onUpdateAvailable');
+
+var original_addListener = exports.onSuspend.addListener;
+
+// Uses a trampoline to bind the Cordova pause event on the first call.
+exports.onSuspend.addListener = function(f) {
+ window.document.addEventListener('pause', exports.onSuspend.fire, false);
+ exports.onSuspend.addListener = original_addListener;
+ exports.onSuspend.addListener(f);
+};
+
+exports.getManifest = function() {
+ if (!manifestJson) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'manifest.json', false /* sync */);
+ xhr.send(null);
+ manifestJson = eval('(' + xhr.responseText + ')'); //JSON.parse(xhr.responseText);
+ }
+ return manifestJson;
+};
+
+exports.getBackgroundPage = function(callback) {
+ argscheck.checkArgs('f', 'chrome.runtime.getBackgroundPage', arguments);
+ setTimeout(function() {
+ callback(mobile.bgWindow);
+ }, 0);
+};
+
+exports.getURL = function(subResource) {
+ argscheck.checkArgs('s', 'chrome.runtime.getURL', arguments);
+ if (subResource.charAt(0) == '/') {
+ subResource = subResource.slice(1);
+ }
+ var prefix = location.href.replace(/[^\/]*$/, '');
+ return prefix + subResource;
+};
+
+exports.reload = function() {
+ location.reload();
+};
+
+stubs.createStub(exports, 'id', '{appId}');
+stubs.createStub(exports, 'requestUpdateCheck', function(){});
+});