Rework Overlay menu to be another view within the main webview.
Much more performant and less complicated this way!
diff --git a/AppHarnessUI/AppHarnessUI.java b/AppHarnessUI/AppHarnessUI.java
index 2a80dd8..9e6eb82 100644
--- a/AppHarnessUI/AppHarnessUI.java
+++ b/AppHarnessUI/AppHarnessUI.java
@@ -27,7 +27,6 @@
import org.apache.cordova.CordovaWebViewClient;
import org.apache.cordova.IceCreamCordovaWebViewClient;
import org.apache.cordova.LinearLayoutSoftKeyboardDetect;
-import org.apache.cordova.PluginEntry;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
@@ -46,13 +45,9 @@
ViewGroup contentView;
View origMainView;
CustomCordovaWebView slaveWebView;
- CordovaWebView overlayWebView;
+ boolean slaveVisible;
CallbackContext eventsCallback;
- public CordovaWebView getSlave() {
- return slaveWebView;
- }
-
@Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if ("create".equals(action)) {
@@ -68,17 +63,11 @@
destroy(callbackContext);
}
});
- } else if ("createOverlay".equals(action)) {
- final String url = args.getString(0);
+ } else if ("setVisible".equals(action)) {
+ final boolean value = args.getBoolean(0);
this.cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
- createOverlay(url, callbackContext);
- }
- });
- } else if ("destroyOverlay".equals(action)) {
- this.cordova.getActivity().runOnUiThread(new Runnable() {
- public void run() {
- destroyOverlay(callbackContext);
+ setSlaveVisible(value, callbackContext);
}
});
} else if ("evalJs".equals(action)) {
@@ -96,7 +85,7 @@
return true;
}
- void sendEvent(String eventName) {
+ private void sendEvent(String eventName) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, eventName);
pluginResult.setKeepCallback(true);
eventsCallback.sendPluginResult(pluginResult );
@@ -127,9 +116,8 @@
if (activity.getBooleanProperty("DisallowOverscroll", false)) {
slaveWebView.setOverScrollMode(CordovaWebView.OVER_SCROLL_NEVER);
}
- contentView.removeAllViews();
- contentView.addView((View)slaveWebView.getParent());
slaveWebView.loadUrl(url);
+ setSlaveVisible(true, null);
}
callbackContext.success();
}
@@ -138,45 +126,38 @@
if (slaveWebView == null) {
Log.w(LOG_TAG, "destroy: already destroyed");
} else {
- contentView.removeAllViews();
- contentView.addView(origMainView);
+ setSlaveVisible(false, null);
slaveWebView.destroy();
slaveWebView = null;
+ sendEvent("destroyed");
}
if (eventsCallback != null) {
- eventsCallback.success();
+ eventsCallback.success("");
eventsCallback = null;
}
callbackContext.success();
}
- private void createOverlay(String url, CallbackContext callbackContext) {
- if (overlayWebView != null) {
- Log.w(LOG_TAG, "createOverlay: already exists");
+ private void setSlaveVisible(boolean value, CallbackContext callbackContext) {
+ if (value == slaveVisible) {
+ return;
+ }
+ if (slaveWebView == null) {
+ Log.w(LOG_TAG, "setSlaveVisible: slave not created");
} else {
- overlayWebView = new CordovaWebView(cordova.getActivity());
- initWebView(overlayWebView);
- overlayWebView.pluginManager.addService(new PluginEntry("OverlayPlugin", new OverlayPlugin()));
- overlayWebView.setOverScrollMode(CordovaWebView.OVER_SCROLL_NEVER);
- contentView.addView((View)overlayWebView.getParent());
- overlayWebView.loadUrl(url);
+ slaveVisible = value;
+ contentView.removeAllViews();
+ View newView = value ? (View)slaveWebView.getParent() : origMainView;
+ // Back button capturing breaks without these:
+ contentView.addView(newView);
+ newView.requestFocus();
}
- callbackContext.success();
- }
-
- private void destroyOverlay(CallbackContext callbackContext) {
- if (overlayWebView == null) {
- Log.w(LOG_TAG, "destroyOverlay: already destroyed");
- } else {
- contentView.removeView((View)overlayWebView.getParent());
- overlayWebView.destroy();
- overlayWebView = null;
+ if (callbackContext != null) {
+ callbackContext.success();
}
- callbackContext.success();
}
-
private void initWebView(CordovaWebView newWebView) {
CordovaActivity activity = (CordovaActivity)cordova.getActivity();
if (contentView == null) {
@@ -205,17 +186,6 @@
layoutView.addView(newWebView);
}
- private class OverlayPlugin extends CordovaPlugin {
- @Override
- public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
- if ("sendEvent".equals(action)) {
- sendEvent(args.getString(0));
- return true;
- }
- return false;
- }
- }
-
// Based on: http://stackoverflow.com/questions/12414680/how-to-implement-a-two-finger-double-click-in-android
private class TwoFingerDoubleTapGestureDetector {
private final int TIMEOUT = ViewConfiguration.getDoubleTapTimeout() + 100;
diff --git a/AppHarnessUI/appharnessui.js b/AppHarnessUI/appharnessui.js
index 65864a6..a902f60 100644
--- a/AppHarnessUI/appharnessui.js
+++ b/AppHarnessUI/appharnessui.js
@@ -20,7 +20,7 @@
var exec = cordova.require('cordova/exec');
function eventHandler(type) {
- exports.onEvent && exports.onEvent(type);
+ type && exports.onEvent && exports.onEvent(type);
}
exports.onEvent = null;
@@ -34,12 +34,8 @@
exec(win, null, 'AppHarnessUI', 'destroy', []);
};
-exports.createOverlay = function(url, win) {
- exec(win, null, 'AppHarnessUI', 'createOverlay', [url]);
-};
-
-exports.destroyOverlay = function(win) {
- exec(win, null, 'AppHarnessUI', 'destroyOverlay', []);
+exports.setVisible = function(value, win) {
+ exec(win, null, 'AppHarnessUI', 'setVisible', [value]);
};
exports.evalJs = function(code, win) {
diff --git a/www/cdvah/css/style.css b/www/cdvah/css/style.css
index daab765..a52ee24 100644
--- a/www/cdvah/css/style.css
+++ b/www/cdvah/css/style.css
@@ -55,3 +55,8 @@
.notification-error {
background-color: #f2dede;
}
+
+.in-app-menu-container button {
+ margin: 20px;
+ text-align: center;
+}
diff --git a/www/cdvah/harnessmenu.html b/www/cdvah/harnessmenu.html
index 41b9d6a..8526930 100644
--- a/www/cdvah/harnessmenu.html
+++ b/www/cdvah/harnessmenu.html
@@ -35,6 +35,7 @@
<script type="text/javascript" src="js/UrlRemap.js"></script>
<script type="text/javascript" src="js/ListCtrl.js"></script>
<script type="text/javascript" src="js/DetailsCtrl.js"></script>
+ <script type="text/javascript" src="js/InAppMenuCtrl.js"></script>
<script type="text/javascript" src="js/Notify.js"></script>
<script type="text/javascript" src="js/HttpServer.js"></script>
<script type="text/javascript" src="js/HarnessServer.js"></script>
diff --git a/www/cdvah/js/AppHarnessUI.js b/www/cdvah/js/AppHarnessUI.js
index eaaca59..01abf65 100644
--- a/www/cdvah/js/AppHarnessUI.js
+++ b/www/cdvah/js/AppHarnessUI.js
@@ -31,14 +31,9 @@
cordova.plugins.appharnessui.destroy(deferred.resolve);
return deferred.promise;
},
- createOverlay: function() {
+ setVisible: function(value) {
var deferred = $q.defer();
- cordova.plugins.appharnessui.createOverlay('app-harness:///cdvahcm/contextMenu.html', deferred.resolve);
- return deferred.promise;
- },
- destroyOverlay: function() {
- var deferred = $q.defer();
- cordova.plugins.appharnessui.destroyOverlay(deferred.resolve);
+ cordova.plugins.appharnessui.setVisible(value, deferred.resolve);
return deferred.promise;
},
setEventHandler: function(f) {
diff --git a/www/cdvah/js/AppsService.js b/www/cdvah/js/AppsService.js
index 43adc0c..a7cb71a 100644
--- a/www/cdvah/js/AppsService.js
+++ b/www/cdvah/js/AppsService.js
@@ -19,7 +19,7 @@
(function() {
'use strict';
/* global myApp */
- myApp.factory('AppsService', ['$q', 'ResourcesLoader', 'INSTALL_DIRECTORY', 'APPS_JSON', 'notifier', 'AppHarnessUI', function($q, ResourcesLoader, INSTALL_DIRECTORY, APPS_JSON, notifier, AppHarnessUI) {
+ myApp.factory('AppsService', ['$q', '$location', 'ResourcesLoader', 'INSTALL_DIRECTORY', 'APPS_JSON', 'notifier', 'AppHarnessUI', function($q, $location, ResourcesLoader, INSTALL_DIRECTORY, APPS_JSON, notifier, AppHarnessUI) {
// Map of type -> installer.
var _installerFactories = Object.create(null);
// Array of installer objects.
@@ -90,23 +90,6 @@
return ResourcesLoader.writeFileContents(APPS_JSON, stringContents);
}
- AppHarnessUI.setEventHandler(function(eventName) {
- console.log('Got event from UI: ' + eventName);
- if (eventName == 'showMenu') {
- AppHarnessUI.createOverlay();
- } else if (eventName == 'hideMenu') {
- AppHarnessUI.destroyOverlay();
- } else if (eventName == 'restartApp') {
- // TODO: Restart in place?
- AppsService.launchApp(activeInstaller)
- .then(null, notifier.error);
- } else if (eventName == 'quitApp') {
- AppsService.quitApp();
- } else {
- console.warn('Unknown message from AppHarnessUI: ' + eventName);
- }
- });
-
var AppsService = {
// return promise with the array of apps
getAppList : function() {
@@ -149,8 +132,8 @@
quitApp : function() {
if (activeInstaller) {
activeInstaller.unlaunch();
- AppHarnessUI.destroy();
activeInstaller = null;
+ return AppHarnessUI.destroy();
}
return $q.when();
},
@@ -167,6 +150,8 @@
return AppHarnessUI.create(launchUrl);
}, function() {
throw new Error('Start file does not exist: ' + launchUrl.replace(/.*?\/www\//, 'www/'));
+ }).then(function() {
+ $location.path('/inappmenu');
});
});
},
diff --git a/www/cdvah/js/InAppMenuCtrl.js b/www/cdvah/js/InAppMenuCtrl.js
new file mode 100644
index 0000000..1ffb1da
--- /dev/null
+++ b/www/cdvah/js/InAppMenuCtrl.js
@@ -0,0 +1,70 @@
+/*
+ * 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 myApp */
+ myApp.controller('InAppMenuCtrl', ['$rootScope', '$scope', '$window', 'AppsService', 'AppHarnessUI', function($rootScope, $scope, $window, AppsService, AppHarnessUI) {
+ var activeApp = AppsService.getActiveApp();
+ if (!activeApp) {
+ $window.history.back();
+ }
+
+ function backButtonListener() {
+ $scope.$apply($scope.hideMenu);
+ }
+ document.addEventListener('backbutton', backButtonListener);
+ $scope.$on('$destroy', function() {
+ document.removeEventListener('backbutton', backButtonListener);
+ });
+
+ $scope.app = activeApp;
+
+ $scope.hideMenu = function() {
+ return AppHarnessUI.setVisible(true);
+ };
+
+ $scope.restartApp = function() {
+ return AppsService.launchApp(activeApp);
+ };
+
+ $scope.quitApp = function() {
+ return AppsService.quitApp();
+ };
+
+ AppHarnessUI.setEventHandler(function(eventName) {
+ $scope.$apply(function() {
+ if (eventName == 'showMenu') {
+ AppHarnessUI.setVisible(false);
+ } else if (eventName == 'hideMenu') {
+ AppHarnessUI.setVisible(true);
+ } else if (eventName == 'restartApp') {
+ // TODO: Restart in place?
+ AppsService.launchApp(activeApp);
+ } else if (eventName == 'quitApp') {
+ AppsService.quitApp();
+ } else if (eventName == 'destroyed') {
+ $window.history.back();
+ } else {
+ console.warn('Unknown message from AppHarnessUI: ' + eventName);
+ }
+ });
+ });
+ }]);
+})();
diff --git a/www/cdvah/js/app.js b/www/cdvah/js/app.js
index 8b84a1a..df30b53 100644
--- a/www/cdvah/js/app.js
+++ b/www/cdvah/js/app.js
@@ -27,6 +27,10 @@
templateUrl: 'views/list.html',
controller: 'ListCtrl'
});
+ $routeProvider.when('/inappmenu', {
+ templateUrl: 'views/inappmenu.html',
+ controller: 'InAppMenuCtrl'
+ });
$routeProvider.when('/details/:index', {
templateUrl: 'views/details.html',
controller: 'DetailsCtrl'
diff --git a/www/cdvah/views/inappmenu.html b/www/cdvah/views/inappmenu.html
new file mode 100644
index 0000000..404735c
--- /dev/null
+++ b/www/cdvah/views/inappmenu.html
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<div class="in-app-menu-container">
+ <h1>{{app.appName || app.appId}}</h1>
+ <button ng-click="hideMenu()">Resume App</button>
+ <button ng-click="restartApp()">Restart App</button><br>
+ <button ng-click="quitApp()">Quit App</button>
+</div>
diff --git a/www/cdvahcm/contextMenu.html b/www/cdvahcm/contextMenu.html
deleted file mode 100644
index 39848aa..0000000
--- a/www/cdvahcm/contextMenu.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<!--
- 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.
--->
-<html onclick="sendEvent('hideMenu')">
-<head>
- <style>
- body
- {
- background-color:rgba(0,0,0,0.75);
- width: 100%;
- height: 100%;
- }
- p, label
- {
- color: white;
- text-align: center;
- }
- ul
- {
- list-style-type: none;
- margin-left: 20%;
- margin-right: 20%;
- padding: 0;
- width: 60%;
- }
- li
- {
- margin-bottom: 0.5cm;
- width : 100%;
- min-height: 1cm;
- border-bottom: 1px solid grey;
- }
- .fullwidthElement
- {
- width: 100%;
- min-height: 1cm;
- }
- .halfwidthElement
- {
- min-height: 1cm;
- width: 48%;
- padding-left: 0;
- padding-right: 0;
- }
- </style>
- <script src="app-harness:///cordova.js"></script>
-</head>
-<body>
- <p>Tap Anywhere to Close</p>
- <ul>
- <li>
- <button class="fullwidthElement" onclick="sendEvent('restartApp')">Restart</button>
- </li>
- <li>
- <button class="fullwidthElement" onclick="sendEvent('quitApp')">Back to Main Menu</button>
- </li>
- </ul>
-</body>
-<script>
- function sendEvent(eventName) {
- cordova.exec(null, null, 'OverlayPlugin', 'sendEvent', [eventName]);
- }
-</script>
-</html>