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 2014/06/24 20:35:36 UTC
[1/2] git commit: Add plugin dependency info to prepare hook
Repository: cordova-app-harness
Updated Branches:
refs/heads/master da50af87c -> 3f7bd69cc
Add plugin dependency info to prepare hook
This can be used to run apps without the need for platforms/ directory.
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/a7d4a444
Tree: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/tree/a7d4a444
Diff: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/diff/a7d4a444
Branch: refs/heads/master
Commit: a7d4a4446b8c02cb137a214dea721c7806a035f1
Parents: da50af8
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 12:45:16 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 14:32:08 2014 -0400
----------------------------------------------------------------------
template-overrides/after-hook.js | 27 ++++--
www/cdvah/harnessmenu.html | 2 +-
www/cdvah/js/CrxInstaller.js | 164 ++++++++++++++++++++++++++++++++++
3 files changed, 185 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/a7d4a444/template-overrides/after-hook.js
----------------------------------------------------------------------
diff --git a/template-overrides/after-hook.js b/template-overrides/after-hook.js
index 85c0a5d..7046a88 100755
--- a/template-overrides/after-hook.js
+++ b/template-overrides/after-hook.js
@@ -31,11 +31,11 @@ if (platforms.length === 0) {
return;
}
-function generatePluginToServiceNamesFile() {
+function generatePluginInfoFile() {
var idToServiceNameMap = {};
+ var depsMap = {};
- function extractServiceNames(p) {
- var contents = fs.readFileSync(p, 'utf8');
+ function extractServiceNames(contents) {
var foundNames = {};
var pattern = /<feature\s+name="(.+?)"/g;
var match;
@@ -45,21 +45,34 @@ function generatePluginToServiceNamesFile() {
return Object.keys(foundNames);
}
+ function extractDependencies(contents) {
+ var foundIds = {};
+ var pattern = /<dependency\s+id="(.+?)"/g;
+ var match;
+ while (match = pattern.exec(contents)) {
+ foundIds[match[1]] = true;
+ }
+ return Object.keys(foundIds);
+ }
+
fs.readdirSync('plugins').forEach(function(p) {
var pluginXmlPath = path.join('plugins', p, 'plugin.xml');
if (fs.existsSync(pluginXmlPath)) {
- idToServiceNameMap[p] = extractServiceNames(pluginXmlPath);
+ var contents = fs.readFileSync(pluginXmlPath, 'utf8');
+ idToServiceNameMap[p] = extractServiceNames(contents);
+ depsMap[p] = extractDependencies(contents);
}
});
- var fileContents = 'myApp.value("pluginIdToServiceNames", ' + JSON.stringify(idToServiceNameMap, null, 4) + ');\n'
+ var fileContents = 'myApp.value("pluginIdToServiceNames", ' + JSON.stringify(idToServiceNameMap, null, 4) + ');\n' +
+ 'myApp.value("pluginDepsMap", ' + JSON.stringify(depsMap, null, 4) + ');\n'
platforms.forEach(function(platformId) {
var wwwPath = preparedWwwPathMap[platformId];
if (!fs.existsSync(path.join(wwwPath, 'cdvah', 'generated'))) {
fs.mkdirSync(path.join(wwwPath, 'cdvah', 'generated'));
}
- var outPath = path.join(wwwPath, 'cdvah', 'generated', 'pluginIdToServiceNames.js');
+ var outPath = path.join(wwwPath, 'cdvah', 'generated', 'installedPluginsMetadata.js');
fs.writeFileSync(outPath, fileContents);
console.log('Wrote ' + outPath);
});
@@ -78,5 +91,5 @@ function renameCordovaPluginsFile() {
console.log('Renamed cordova_plugins.js -> ' + path.join(wwwPath, 'cordova_plugins_harness.js'));
});
}
-generatePluginToServiceNamesFile();
+generatePluginInfoFile();
renameCordovaPluginsFile();
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/a7d4a444/www/cdvah/harnessmenu.html
----------------------------------------------------------------------
diff --git a/www/cdvah/harnessmenu.html b/www/cdvah/harnessmenu.html
index b12f047..9721caa 100644
--- a/www/cdvah/harnessmenu.html
+++ b/www/cdvah/harnessmenu.html
@@ -40,8 +40,8 @@
<script type="text/javascript" src="js/InAppMenuCtrl.js"></script>
<script type="text/javascript" src="js/HttpServer.js"></script>
<script type="text/javascript" src="js/HarnessServer.js"></script>
+ <script type="text/javascript" src="generated/installedPluginsMetadata.js"></script>
<link rel="stylesheet" type="text/css" href="css/topcoat-mobile-light.min.css" />
- <script type="text/javascript" src="generated/pluginIdToServiceNames.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body ng-cloak>
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/a7d4a444/www/cdvah/js/CrxInstaller.js
----------------------------------------------------------------------
diff --git a/www/cdvah/js/CrxInstaller.js b/www/cdvah/js/CrxInstaller.js
new file mode 100644
index 0000000..b0d0c50
--- /dev/null
+++ b/www/cdvah/js/CrxInstaller.js
@@ -0,0 +1,164 @@
+/*
+ * 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.
+*/
+(function(){
+ 'use strict';
+ /* global cca */
+
+ // The only things that matters here at the moment
+ // are the appId and <content>.
+ var CONFIG_XML_TEMPLATE = '<?xml version="1.0" encoding="UTF-8"?>\n' +
+ '<widget id = "__APP_PACKAGE_ID__" version = "__APP_VERSION__">\n' +
+ '<name>__APP_NAME__</name>\n' +
+ '<description>__DESCRIPTION__</description>\n' +
+ '<author>__AUTHOR__</author>\n' +
+ '<preference name="KeyboardShrinksView" value="true" />\n' +
+ '<preference name="StatusBarOverlaysWebView" value="false" />\n' +
+ '<preference name="StatusBarBackgroundColor" value="#000000" />\n' +
+ '<preference name="iosPersistentFileLocation" value="Library" />\n' +
+ '<preference name="AndroidPersistentFileLocation" value="Internal" />\n' +
+ '<icon src="__ICON_SRC__" />\n' +
+ '<content src="plugins/org.chromium.bootstrap/chromeapp.html" />\n' +
+ '</widget>\n';
+
+
+ function generateConfigXmlData(appId, manifest) {
+ var iconSrc = '';
+ var iconSize = 0;
+ if (typeof manifest.icons == 'object') {
+ for (var size in manifest.icons) {
+ if (+size > iconSize) {
+ iconSize = +size;
+ iconSrc = 'www/' + manifest.icons[size];
+ }
+ }
+ }
+ return CONFIG_XML_TEMPLATE
+ .replace(/__APP_NAME__/, manifest.name || appId)
+ .replace(/__APP_PACKAGE_ID__/, appId)
+ .replace(/__APP_VERSION__/, manifest.version || '0.0.1')
+ .replace(/__DESCRIPTION__/, manifest.description || 'Missing description')
+ .replace(/__AUTHOR__/, manifest.author || 'Missing author')
+ .replace(/__ICON_SRC__/, iconSrc);
+ }
+
+ /* global myApp */
+ myApp.factory('CrxInstaller', ['$q', 'Installer', 'AppsService', 'ResourcesLoader', 'pluginDepsMap', function($q, Installer, AppsService, ResourcesLoader, pluginDepsMap) {
+
+ function CrxInstaller() {
+ this.manifestJson_ = null;
+ this.manifestMobileJson_ = null;
+ }
+ CrxInstaller.prototype = Object.create(Installer.prototype);
+ CrxInstaller.prototype.constructor = CrxInstaller;
+ CrxInstaller.type = 'chrome';
+
+ CrxInstaller.prototype.initFromJson = function(json) {
+ var self = this;
+ return Installer.prototype.initFromJson.call(this, json)
+ .then(function() {
+ return self.readManifest_();
+ }).then(function() {
+ return self.updateDerivedFiles();
+ }).then(function() {
+ return self;
+ }, function(e) {
+ console.warn('Deleting broken app: ' + json['installPath']);
+ ResourcesLoader.delete(json['installPath']);
+ throw e;
+ });
+ };
+
+ CrxInstaller.prototype.onFileAdded = function(path, etag) {
+ var self = this;
+ return $q.when(Installer.prototype.onFileAdded.call(this, path, etag))
+ .then(function() {
+ if (path == 'www/manifest.json' || (path == 'www/manifest.mobile.json' && self.manifestJson_)) {
+ return self.readManifest_()
+ .then(function() {
+ return self.updateDerivedFiles();
+ });
+ }
+ });
+ };
+
+ CrxInstaller.prototype.readManifest_ = function() {
+ var self = this;
+ return ResourcesLoader.readFileContents(this.directoryManager.rootURL + 'www/manifest.json')
+ .then(function(manifestData) {
+ // jshint evil:true
+ self.manifestJson_ = eval('(' + manifestData + ')');
+ // jshint evil:false
+ return ResourcesLoader.readFileContents(self.directoryManager.rootURL + 'www/manifest.mobile.json')
+ .then(function(manifestMobileData) {
+ // jshint evil:true
+ self.manifestMobileJson_ = eval('(' + manifestMobileData + ')');
+ // jshint evil:false
+ // TODO: Should we update App ID if this happens?
+ // Unlikely that this *can* happen unless the request has ?appId=oldId
+ // self.appId = self.manifestMobileJson_['packageId'] || self.manifestJson_['packageId'] || self.appId;
+ }, function() {});
+ });
+ };
+
+ CrxInstaller.prototype.updateDerivedFiles = function() {
+ var self = this;
+ var contents = generateConfigXmlData(this.appId, this.manifestJson_);
+ var combinedEtag = this.directoryManager.getAssetEtag('www/manifest.json') + this.directoryManager.getAssetEtag('www/manifest.mobile.json');
+ return this.directoryManager.writeFile(contents, 'config.xml', combinedEtag)
+ .then(function() {
+ return self.updateCordovaPluginsFile(self.directoryManager.getAssetEtag('www/manifest.json'));
+ });
+ };
+
+ function expandPluginIdsWithDeps(ids) {
+ var idMap = {};
+ function addAll(arr) {
+ arr.forEach(function(pluginId) {
+ if (!idMap[pluginId]) {
+ idMap[pluginId] = true;
+ var deps = pluginDepsMap[pluginId];
+ if (deps) {
+ addAll(deps);
+ }
+ }
+ });
+ }
+ addAll(ids);
+ return Object.keys(idMap);
+ }
+
+ CrxInstaller.prototype.getPluginMetadata = function() {
+ var pluginIds = cca.extractPluginsFromManifest(this.manifestJson_).concat(cca.getDefaultPluginIds());
+ pluginIds = expandPluginIdsWithDeps(pluginIds);
+ var harnessPluginMetadata = cordova.require('cordova/plugin_list').metadata;
+ var ret = {};
+ // Make all versions match what is installed.
+ for (var i = 0; i < pluginIds.length; ++i) {
+ ret[pluginIds[i]] = harnessPluginMetadata[pluginIds[i]] || '0';
+ }
+ return ret;
+ };
+
+ return CrxInstaller;
+ }]);
+
+ myApp.run(['CrxInstaller', 'AppsService', function(CrxInstaller, AppsService) {
+ AppsService.registerInstallerFactory(CrxInstaller);
+ }]);
+})();
[2/2] git commit: First attempt at hooking back button up to exit app.
Posted by ag...@apache.org.
First attempt at hooking back button up to exit app.
Requires changes to cordova-android and x-walk plugin (so use master).
Currently has a bug where hitting back navigates to about:blank before
minimizing.
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/3f7bd69c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/tree/3f7bd69c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-app-harness/diff/3f7bd69c
Branch: refs/heads/master
Commit: 3f7bd69cc1f9005a1d20e2c00a6587e25867e8d1
Parents: a7d4a44
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 14:16:28 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 14:35:16 2014 -0400
----------------------------------------------------------------------
AppHarnessUI/AppHarnessUI.java | 24 +++++++++++++++++++++++-
createproject.sh | 11 +++++++++++
template-overrides/Activity.java | 29 +++++++++++++++++++++++++++++
www/cdvah/js/InAppMenuCtrl.js | 2 ++
4 files changed, 65 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/3f7bd69c/AppHarnessUI/AppHarnessUI.java
----------------------------------------------------------------------
diff --git a/AppHarnessUI/AppHarnessUI.java b/AppHarnessUI/AppHarnessUI.java
index 834603b..fd64295 100644
--- a/AppHarnessUI/AppHarnessUI.java
+++ b/AppHarnessUI/AppHarnessUI.java
@@ -58,6 +58,14 @@ public class AppHarnessUI extends CordovaPlugin {
boolean slaveVisible;
CallbackContext eventsCallback;
+ public boolean isSlaveVisible() {
+ return slaveVisible;
+ }
+
+ public boolean isSlaveCreated() {
+ return slaveWebView != null && slaveWebView.getParent() != null;
+ }
+
@Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if ("create".equals(action)) {
@@ -100,7 +108,7 @@ public class AppHarnessUI extends CordovaPlugin {
return true;
}
- private void sendEvent(String eventName) {
+ public void sendEvent(String eventName) {
if (eventsCallback != null) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, eventName);
pluginResult.setKeepCallback(true);
@@ -281,5 +289,19 @@ public class AppHarnessUI extends CordovaPlugin {
// Needed for the view to stay in the bottom when rotating.
setPivotY(h);
}
+
+ @Override
+ public boolean backHistory() {
+ if (getView().getNavigationHistory().canGoBack()) {
+ return super.backHistory();
+ }
+ if (slaveVisible) {
+ sendEvent("showMenu");
+ return true;
+ }
+ // Should never get here since the webview does not have focus.
+ Log.w(LOG_TAG, "Somehow back button was pressed when app not visible");
+ return false;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/3f7bd69c/createproject.sh
----------------------------------------------------------------------
diff --git a/createproject.sh b/createproject.sh
index 9c79286..e1094c9 100755
--- a/createproject.sh
+++ b/createproject.sh
@@ -92,6 +92,17 @@ set -x
$CORDOVA platform add $PLATFORM_ARGS || exit 1
set +x
+if [[ "$PLATFORMS" = *android* ]]; then
+ echo 'var fs = require("fs");
+ var fname = "platforms/android/src/org/chromium/appdevtool/ChromeAppDeveloperTool.java";
+ var tname = "'$AH_PATH'/template-overrides/Activity.java";
+ var orig = fs.readFileSync(fname, "utf8");
+ var templ = fs.readFileSync(tname, "utf8");
+ var newData = orig.replace(/}\s*$/, templ + "\n}\n").replace(/import.*?$/m, "import org.apache.appharness.AppHarnessUI;\n$&");
+ fs.writeFileSync(fname, newData);
+ ' | node || exit $?
+fi
+
mkdir -p hooks/after_prepare
cp "$AH_PATH"/template-overrides/after-hook.js hooks/after_prepare
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/3f7bd69c/template-overrides/Activity.java
----------------------------------------------------------------------
diff --git a/template-overrides/Activity.java b/template-overrides/Activity.java
new file mode 100644
index 0000000..1a6de33
--- /dev/null
+++ b/template-overrides/Activity.java
@@ -0,0 +1,29 @@
+
+ @Override
+ public void onBackPressed() {
+ // If app is running, quit it.
+ AppHarnessUI ahui = (AppHarnessUI)appView.getPlugin("AppHarnessUI");
+ if (ahui != null) {
+ if (ahui.isSlaveCreated()) {
+ ahui.sendEvent("quitApp");
+ return;
+ }
+ }
+ // Otherwise, hide instead of calling .finish().
+ moveTaskToBack(true);
+ }
+
+ @Override
+ public Object onMessage(String id, Object data) {
+ // Capture the app calling navigator.app.exitApp().
+ if ("exit".equals(id)) {
+ AppHarnessUI ahui = (AppHarnessUI)appView.getPlugin("AppHarnessUI");
+ if (ahui != null) {
+ if (ahui.isSlaveCreated()) {
+ ahui.sendEvent("quitApp");
+ return new Object();
+ }
+ }
+ }
+ return super.onMessage(id, data);
+ }
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/3f7bd69c/www/cdvah/js/InAppMenuCtrl.js
----------------------------------------------------------------------
diff --git a/www/cdvah/js/InAppMenuCtrl.js b/www/cdvah/js/InAppMenuCtrl.js
index ee21620..9ec9ed4 100644
--- a/www/cdvah/js/InAppMenuCtrl.js
+++ b/www/cdvah/js/InAppMenuCtrl.js
@@ -53,6 +53,8 @@
AppHarnessUI.setVisible(false);
} else if (eventName == 'hideMenu') {
AppHarnessUI.setVisible(true);
+ } else if (eventName == 'quitApp') {
+ return AppsService.quitApp();
} else if (eventName == 'destroyed') {
$window.history.back();
} else {