feature (GH-128) ios/android: enable programmatic dismissal of open dialogs
diff --git a/README.md b/README.md
index 482b16d..d7156c7 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,8 @@
- `navigator.notification.confirm`
- `navigator.notification.prompt`
- `navigator.notification.beep`
+- `navigator.notification.dismissPrevious`
+- `navigator.notification.dismissAll`
## navigator.notification.alert
@@ -223,3 +225,63 @@
### Android Quirks
- Android plays the default __Notification ringtone__ specified under the __Settings/Sound & Display__ panel.
+
+## navigator.notification.dismissPrevious
+
+Dismisses the previously opened dialog box.
+If no dialog box is currently open, the `errorCallback` will be called.
+
+ navigator.notification.dismissPrevious([successCallback], [errorCallback])
+
+- __successCallback__: Callback to invoke when previously opened dialog has been dismissed. _(Function)_ (Optional)
+- __errorCallback__: Callback to invoke on failure to dismiss previously opened dialog. Will be passed the error message. _(Function)_ (Optional)
+
+### Example
+
+ function successCallback() {
+ console.log("Successfully dismissed previously opened dialog.");
+ }
+
+ function errorCallback(error) {
+ console.log("Failed to dismiss previously opened dialog: " + error);
+ }
+
+ navigator.notification.dismissPrevious(
+ successCallback,
+ errorCallback
+ );
+
+### Supported Platforms
+
+- Android
+- iOS
+
+## navigator.notification.dismissAll
+
+Dismisses all previously opened dialog boxes.
+If no dialog box is currently open, the `errorCallback` will be called.
+
+ navigator.notification.dismissAll([successCallback], [errorCallback])
+
+- __successCallback__: Callback to invoke when all previously opened dialogs have been dismissed. _(Function)_ (Optional)
+- __errorCallback__: Callback to invoke on failure to dismiss all previously opened dialogs. Will be passed the error message. _(Function)_ (Optional)
+
+### Example
+
+ function successCallback() {
+ console.log("Successfully dismissed all previously opened dialogs.");
+ }
+
+ function errorCallback(error) {
+ console.log("Failed to dismiss all previously opened dialogs: " + error);
+ }
+
+ navigator.notification.dismissAll(
+ successCallback,
+ errorCallback
+ );
+
+### Supported Platforms
+
+- Android
+- iOS
diff --git a/src/android/Notification.java b/src/android/Notification.java
index 8e34e54..5a0f83b 100644
--- a/src/android/Notification.java
+++ b/src/android/Notification.java
@@ -38,6 +38,7 @@
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.ArrayList;
/**
@@ -61,10 +62,14 @@
private static final String ACTION_PROGRESS_START = "progressStart";
private static final String ACTION_PROGRESS_VALUE = "progressValue";
private static final String ACTION_PROGRESS_STOP = "progressStop";
+ private static final String ACTION_DISMISS_PREVIOUS = "dismissPrevious";
+ private static final String ACTION_DISMISS_ALL = "dismissAll";
private static final long BEEP_TIMEOUT = 5000;
private static final long BEEP_WAIT_TINE = 100;
+ private ArrayList<AlertDialog> dialogs = new ArrayList<AlertDialog>();
+
public int confirmResult = -1;
public ProgressDialog spinnerDialog = null;
public ProgressDialog progressDialog = null;
@@ -122,6 +127,12 @@
else if (action.equals(ACTION_PROGRESS_STOP)) {
this.progressStop();
}
+ else if (action.equals(ACTION_DISMISS_PREVIOUS)) {
+ this.dismissPrevious(callbackContext);
+ }
+ else if (action.equals(ACTION_DISMISS_ALL)) {
+ this.dismissAll(callbackContext);
+ }
else {
return false;
}
@@ -397,6 +408,33 @@
}
/**
+ * Close previously opened dialog
+ */
+ public synchronized void dismissPrevious(final CallbackContext callbackContext){
+ if(!dialogs.isEmpty()){
+ dialogs.remove(dialogs.size()-1).dismiss();
+ callbackContext.success();
+ }else{
+ callbackContext.error("No previously opened dialog to dismiss");
+ }
+ }
+
+ /**
+ * Close any open dialog.
+ */
+ public synchronized void dismissAll(final CallbackContext callbackContext){
+ if(!dialogs.isEmpty()){
+ for(AlertDialog dialog: dialogs){
+ dialog.dismiss();
+ }
+ dialogs = new ArrayList<AlertDialog>();
+ callbackContext.success();
+ }else{
+ callbackContext.error("No previously opened dialogs to dismiss");
+ }
+ }
+
+ /**
* Show the spinner.
*
* @param title Title of the dialog
@@ -517,7 +555,8 @@
private void changeTextDirection(Builder dlg){
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
dlg.create();
- AlertDialog dialog = dlg.show();
+ AlertDialog dialog = dlg.show();
+ dialogs.add(dialog);
if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
TextView messageview = (TextView)dialog.findViewById(android.R.id.message);
messageview.setTextDirection(android.view.View.TEXT_DIRECTION_LOCALE);
diff --git a/src/ios/CDVNotification.h b/src/ios/CDVNotification.h
index df06c72..fb0885c 100644
--- a/src/ios/CDVNotification.h
+++ b/src/ios/CDVNotification.h
@@ -28,5 +28,7 @@
- (void)confirm:(CDVInvokedUrlCommand*)command;
- (void)prompt:(CDVInvokedUrlCommand*)command;
- (void)beep:(CDVInvokedUrlCommand*)command;
+- (void)dismissPrevious:(CDVInvokedUrlCommand*)command;
+- (void)dismissAll:(CDVInvokedUrlCommand*)command;
@end
diff --git a/src/ios/CDVNotification.m b/src/ios/CDVNotification.m
index 92001a0..bea6466 100644
--- a/src/ios/CDVNotification.m
+++ b/src/ios/CDVNotification.m
@@ -24,6 +24,7 @@
static void soundCompletionCallback(SystemSoundID ssid, void* data);
static NSMutableArray *alertList = nil;
+static NSMutableArray *openAlertList = nil;
@implementation CDVNotification
@@ -67,10 +68,11 @@
}
[weakNotif.commandDelegate sendPluginResult:result callbackId:callbackId];
+ [openAlertList removeObject:alertController];
}]];
}
if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) {
-
+
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.text = defaultText;
}];
@@ -159,15 +161,60 @@
}
-(void)presentAlertcontroller {
-
+
__weak CDVNotification* weakNotif = self;
- [self.getTopPresentedViewController presentViewController:[alertList firstObject] animated:YES completion:^{
- [alertList removeObject:[alertList firstObject]];
+ UIAlertController* alertController = [alertList firstObject];
+ [self.getTopPresentedViewController presentViewController:alertController animated:YES completion:^{
+ [alertList removeObject:alertController];
+ if (!openAlertList) {
+ openAlertList = [[NSMutableArray alloc] init];
+ }
+ [openAlertList addObject:alertController];
if ([alertList count]>0) {
[weakNotif presentAlertcontroller];
}
}];
-
+
}
+
+- (void)dismissPrevious:(CDVInvokedUrlCommand*)command
+{
+ if(openAlertList != nil && [openAlertList count]>0){
+ __weak CDVNotification* weakNotif = self;
+ UIAlertController* alertController = [openAlertList lastObject];
+ [alertController dismissViewControllerAnimated:NO completion:^{
+ [openAlertList removeObject:alertController];
+ [weakNotif.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
+ }];
+ }else{
+ [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No previously opened dialog to dismiss"] callbackId:command.callbackId];
+ }
+}
+
+- (void)dismissAll:(CDVInvokedUrlCommand*)command
+{
+ if(openAlertList != nil && [openAlertList count]>0){
+ __weak CDVNotification* weakNotif = self;
+ [self dismissUIAlertControllers:^{
+ openAlertList = [[NSMutableArray alloc] init];
+ [weakNotif.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK] callbackId:command.callbackId];
+ }];
+ }else{
+ [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No previously opened dialogs to dismiss"] callbackId:command.callbackId];
+ }
+}
+
+- (void)dismissUIAlertControllers:(void (^)(void))completeBlock{
+ if([self.getTopPresentedViewController isKindOfClass:[UIAlertController class]]){
+ __weak CDVNotification* weakNotif = self;
+ [self.getTopPresentedViewController dismissViewControllerAnimated:NO completion:^{
+ [weakNotif dismissUIAlertControllers:completeBlock];
+ }];
+ }else{
+ completeBlock();
+ }
+}
+
+
@end
diff --git a/src/windows/NotificationProxy.js b/src/windows/NotificationProxy.js
index 1ccc18e..a3b04bb 100644
--- a/src/windows/NotificationProxy.js
+++ b/src/windows/NotificationProxy.js
@@ -261,6 +261,14 @@
};
snd.addEventListener('ended', onEvent);
onEvent();
+ },
+
+ dismissPrevious: function () {
+ console.warn('dismissPrevious() is not available on browser platform');
+ },
+
+ dismissAll: function () {
+ console.warn('dismissAll() is not available on browser platform');
}
};
diff --git a/tests/tests.js b/tests/tests.js
index a6a67a4..7eb5ab7 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -46,6 +46,16 @@
expect(typeof navigator.notification.prompt).toBeDefined();
expect(typeof navigator.notification.prompt).toBe('function');
});
+
+ it('should contain a dismissPrevious function', function () {
+ expect(typeof navigator.notification.dismissPrevious).toBeDefined();
+ expect(typeof navigator.notification.dismissPrevious).toBe('function');
+ });
+
+ it('should contain a dismissAll function', function () {
+ expect(typeof navigator.notification.dismissAll).toBeDefined();
+ expect(typeof navigator.notification.dismissAll).toBe('function');
+ });
});
};
@@ -143,7 +153,19 @@
);
};
+ var dismissPrevious = function (successCallback, errorCallback) {
+ console.log('dismissPrevious()');
+ navigator.notification.dismissPrevious(successCallback, errorCallback);
+ };
+
+ var dismissAll = function (successCallback, errorCallback) {
+ console.log('dismissAll()');
+ navigator.notification.dismissAll(successCallback, errorCallback);
+ };
+
/******************************************************************************/
+ var isRunningOnAndroid = cordova.platformId === 'android';
+ var isRunningOniOS = cordova.platformId === 'ios';
var dialogs_tests =
'<div id="beep"></div>' +
@@ -167,6 +189,14 @@
'<p/> <h3>CB-8947 Tests</h3><div id="cb8947"></div>' +
'Expected results: Dialogs will not crash iOS';
+ if (isRunningOnAndroid || isRunningOniOS) {
+ dialogs_tests += '<h3>Dismissable dialogs</h3>' +
+ '<p/> <div id="dismiss_previous"></div>' +
+ 'Expected results: 2 dialogs will open; one will automatically dismiss after 5 seconds' +
+ '<p/> <div id="dismiss_all"></div>' +
+ 'Expected results: 2 dialogs will open; both will automatically dismiss after 5 seconds';
+ }
+
contentEl.innerHTML = '<div id="info"></div>' + dialogs_tests;
createActionButton(
@@ -306,4 +336,46 @@
},
'cb8947'
);
+
+ // Dismissable dialogs (supported on Android & iOS only)
+ if (isRunningOnAndroid || isRunningOniOS) {
+ var open2Dialogs = function () {
+ var openDialogs = function () {
+ alertDialog('Alert Dialog 1 pressed', 'Alert Dialog 1', 'Continue');
+ alertDialog('Alert Dialog 2 pressed', 'Alert Dialog 2', 'Continue');
+ };
+ // dismiss any currently open dialogs first
+ dismissAll(openDialogs, openDialogs);
+ };
+
+ createActionButton(
+ 'Dismiss Previous',
+ function () {
+ open2Dialogs();
+ setTimeout(function () {
+ dismissPrevious(function () {
+ console.log('Successfully dismissed previous dialog');
+ }, function (error) {
+ console.error('Failed to dismiss previous dialog: ' + error);
+ });
+ }, 5000);
+ },
+ 'dismiss_previous'
+ );
+
+ createActionButton(
+ 'Dismiss All',
+ function () {
+ open2Dialogs();
+ setTimeout(function () {
+ dismissAll(function () {
+ console.log('Successfully dismissed all open dialogs');
+ }, function (error) {
+ console.error('Failed to dismiss all open dialogs: ' + error);
+ });
+ }, 5000);
+ },
+ 'dismiss_all'
+ );
+ }
};
diff --git a/www/browser/notification.js b/www/browser/notification.js
index efcc376..ce1faa2 100644
--- a/www/browser/notification.js
+++ b/www/browser/notification.js
@@ -110,3 +110,11 @@
}
}
};
+
+module.exports.dismissPrevious = window.navigator.notification.dismissPrevious = function () {
+ console.warn('dismissPrevious() is not available on browser platform');
+};
+
+module.exports.dismissAll = window.navigator.notification.dismissAll = function () {
+ console.warn('dismissAll() is not available on browser platform');
+};
diff --git a/www/notification.js b/www/notification.js
index 1de7b52..a06e2c9 100644
--- a/www/notification.js
+++ b/www/notification.js
@@ -107,6 +107,26 @@
beep: function (count) {
var defaultedCount = count || 1;
exec(null, null, 'Notification', 'beep', [defaultedCount]);
+ },
+
+ /**
+ * Close previously opened dialog
+ *
+ * @param {Function} successCallback The callback that is called when previously opened dialog has been dismissed.
+ * @param {Function} errorCallback The callback that is called on failure to dismiss previously opened dialog.
+ */
+ dismissPrevious: function (successCallback, errorCallback) {
+ exec(successCallback, errorCallback, 'Notification', 'dismissPrevious', []);
+ },
+
+ /**
+ * Close any open dialog.
+ *
+ * @param {Function} successCallback The callback that is called when all previously opened dialogs have been dismissed.
+ * @param {Function} errorCallback The callback that is called on failure to dismiss all previously opened dialogs.
+ */
+ dismissAll: function (successCallback, errorCallback) {
+ exec(successCallback, errorCallback, 'Notification', 'dismissAll', []);
}
};