diff --git a/react/features/base/tracks/actions.js b/react/features/base/tracks/actions.js
index 4b123ed84..cc2c04556 100644
--- a/react/features/base/tracks/actions.js
+++ b/react/features/base/tracks/actions.js
@@ -83,19 +83,10 @@ export function createLocalTracksA(options = {}) {
},
/* firePermissionPromptIsShownEvent */ false,
store)
- .then(localTracks => dispatch(_updateLocalTracks(localTracks)))
- .catch(({ gum }) => {
- // If permissions are not allowed, alert the user.
- if (gum
- && gum.error
- && gum.error.name === 'DOMException'
- && gum.error.message === 'NotAllowedError') {
- dispatch({
- type: TRACK_PERMISSION_ERROR,
- trackType: device
- });
- }
- });
+ .then(
+ localTracks => dispatch(_updateLocalTracks(localTracks)),
+ reason =>
+ dispatch(_onCreateLocalTracksRejected(reason, device)));
}
};
}
@@ -390,6 +381,52 @@ function _getLocalTracksToChange(currentTracks, newTracks) {
};
}
+/**
+ * Implements the Promise rejection handler of
+ * createLocalTracksA and createLocalTracksF.
+ *
+ * @param {Object} reason - The Promise rejection reason.
+ * @param {string} device - The device/MEDIA_TYPE associated with the
+ * rejection.
+ * @private
+ * @returns {Function}
+ */
+function _onCreateLocalTracksRejected({ gum }, device) {
+ return dispatch => {
+ // If permissions are not allowed, alert the user.
+ if (gum) {
+ const { error } = gum;
+
+ if (error) {
+ // FIXME For whatever reason (which is probably an
+ // implementation fault), react-native-webrtc will give the
+ // error in one of the following formats depending on whether it
+ // is attached to a remote debugger or not. (The remote debugger
+ // scenario suggests that react-native-webrtc is at fault
+ // because the remote debugger is Google Chrome and then its
+ // JavaScript engine will define DOMException. I suspect I wrote
+ // react-native-webrtc to return the error in the alternative
+ // format if DOMException is not defined.)
+ let trackPermissionError;
+
+ switch (error.name) {
+ case 'DOMException':
+ trackPermissionError = error.message === 'NotAllowedError';
+ break;
+
+ case 'NotAllowedError':
+ trackPermissionError = error instanceof DOMException;
+ break;
+ }
+ trackPermissionError && dispatch({
+ type: TRACK_PERMISSION_ERROR,
+ trackType: device
+ });
+ }
+ }
+ };
+}
+
/**
* Returns true if the provided JitsiTrack should be rendered as a mirror.
*
diff --git a/react/features/mobile/permissions/functions.js b/react/features/mobile/permissions/functions.js
deleted file mode 100644
index e9fa54693..000000000
--- a/react/features/mobile/permissions/functions.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Alert, Linking, NativeModules } from 'react-native';
-
-import { Platform } from '../../base/react';
-
-/**
- * Shows an alert panel which tells the user they have to manually grant some
- * permissions by opening Settings. A button which opens Settings is provided.
- *
- * FIXME: translate.
- *
- * @param {string} trackType - Type of track that failed with a permission
- * error.
- * @returns {void}
- */
-export function alertPermissionErrorWithSettings(trackType) {
- const type = trackType === 'video' ? 'Camera' : 'Microphone';
-
- Alert.alert(
- 'Permissions Error',
- `${type} permission is required, please enable it in Settings.`,
- [
- { text: 'Cancel' },
- {
- onPress: _openSettings,
- text: 'Settings'
- }
- ],
- { cancelable: false });
-}
-
-/**
- * Opens the settings panel for the current platform.
- *
- * @private
- * @returns {void}
- */
-function _openSettings() {
- switch (Platform.OS) {
- case 'android':
- NativeModules.AndroidSettings.open();
- break;
-
- case 'ios':
- Linking.openURL('app-settings:');
- break;
- }
-}
diff --git a/react/features/mobile/permissions/middleware.js b/react/features/mobile/permissions/middleware.js
index c9dfcd528..02674d9f4 100644
--- a/react/features/mobile/permissions/middleware.js
+++ b/react/features/mobile/permissions/middleware.js
@@ -1,10 +1,12 @@
/* @flow */
+import { Alert, Linking, NativeModules } from 'react-native';
+
+import { isRoomValid } from '../../base/conference';
+import { Platform } from '../../base/react';
import { MiddlewareRegistry } from '../../base/redux';
import { TRACK_PERMISSION_ERROR } from '../../base/tracks';
-import { alertPermissionErrorWithSettings } from './functions';
-
/**
* Middleware that captures track permission errors and alerts the user so they
* can enable the permission themselves.
@@ -12,14 +14,68 @@ import { alertPermissionErrorWithSettings } from './functions';
* @param {Store} store - The redux store.
* @returns {Function}
*/
-MiddlewareRegistry.register(() => next => action => {
+MiddlewareRegistry.register(store => next => action => {
const result = next(action);
switch (action.type) {
case TRACK_PERMISSION_ERROR:
- alertPermissionErrorWithSettings(action.trackType);
+ // XXX We do not currently have user interface outside of a conference
+ // which the user may tap and cause a permission-related error. If we
+ // alert whenever we (intend to) ask for a permission, the scenario of
+ // entering the WelcomePage, being asked for the camera permission, me
+ // denying it, and being alerted that there is an error is overwhelming
+ // me.
+ if (isRoomValid(store.getState()['features/base/conference'].room)) {
+ _alertPermissionErrorWithSettings(action.trackType);
+ }
break;
}
return result;
});
+
+/**
+ * Shows an alert panel which tells the user they have to manually grant some
+ * permissions by opening Settings. A button which opens Settings is provided.
+ *
+ * @param {string} trackType - Type of track that failed with a permission
+ * error.
+ * @private
+ * @returns {void}
+ */
+function _alertPermissionErrorWithSettings(trackType) {
+ // TODO i18n
+ const deviceType = trackType === 'video' ? 'Camera' : 'Microphone';
+
+ Alert.alert(
+ 'Permission required',
+ `${deviceType
+ } permission is required to participate in conferences with ${
+ trackType}. Please grant it in Settings.`,
+ [
+ { text: 'Cancel' },
+ {
+ onPress: _openSettings,
+ text: 'Settings'
+ }
+ ],
+ { cancelable: false });
+}
+
+/**
+ * Opens the settings panel for the current platform.
+ *
+ * @private
+ * @returns {void}
+ */
+function _openSettings() {
+ switch (Platform.OS) {
+ case 'android':
+ NativeModules.AndroidSettings.open();
+ break;
+
+ case 'ios':
+ Linking.openURL('app-settings:');
+ break;
+ }
+}