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 {