[RN] Alert the user when they need to manually grant a permission
This commit is contained in:
parent
9bca0e3b3d
commit
26f0f7f89c
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Adapted from
|
||||
* {@link https://github.com/Aleksandern/react-native-android-settings-library}.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
class AndroidSettingsModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* React Native module name.
|
||||
*/
|
||||
private static final String MODULE_NAME = "AndroidSettings";
|
||||
|
||||
public AndroidSettingsModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void open() {
|
||||
Context context = getReactApplicationContext();
|
||||
Intent intent = new Intent();
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(
|
||||
Uri.fromParts("package", context.getPackageName(), null));
|
||||
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ public class JitsiMeetView extends FrameLayout {
|
|||
private static List<NativeModule> createNativeModules(
|
||||
ReactApplicationContext reactContext) {
|
||||
return Arrays.<NativeModule>asList(
|
||||
new AndroidSettingsModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new ExternalAPIModule(reactContext),
|
||||
new ProximityModule(reactContext)
|
||||
|
|
|
@ -8,6 +8,7 @@ import '../../mobile/audio-mode';
|
|||
import '../../mobile/background';
|
||||
import '../../mobile/external-api';
|
||||
import '../../mobile/full-screen';
|
||||
import '../../mobile/permissions';
|
||||
import '../../mobile/proximity';
|
||||
import '../../mobile/wake-lock';
|
||||
|
||||
|
|
|
@ -9,6 +9,17 @@
|
|||
*/
|
||||
export const TRACK_ADDED = Symbol('TRACK_ADDED');
|
||||
|
||||
/**
|
||||
* Action for when a track cannot be created because permissions have not been
|
||||
* granted.
|
||||
*
|
||||
* {
|
||||
* type: TRACK_PERMISSION_ERROR,
|
||||
* trackType: string
|
||||
* }
|
||||
*/
|
||||
export const TRACK_PERMISSION_ERROR = Symbol('TRACK_PERMISSION_ERROR');
|
||||
|
||||
/**
|
||||
* Action for when a track has been removed from the conference,
|
||||
* local or remote.
|
||||
|
|
|
@ -7,7 +7,12 @@ import {
|
|||
} from '../media';
|
||||
import { getLocalParticipant } from '../participants';
|
||||
|
||||
import { TRACK_ADDED, TRACK_REMOVED, TRACK_UPDATED } from './actionTypes';
|
||||
import {
|
||||
TRACK_ADDED,
|
||||
TRACK_PERMISSION_ERROR,
|
||||
TRACK_REMOVED,
|
||||
TRACK_UPDATED
|
||||
} from './actionTypes';
|
||||
import { createLocalTracksF } from './functions';
|
||||
|
||||
/**
|
||||
|
@ -78,14 +83,19 @@ export function createLocalTracksA(options = {}) {
|
|||
},
|
||||
/* firePermissionPromptIsShownEvent */ false,
|
||||
store)
|
||||
.then(localTracks => dispatch(_updateLocalTracks(localTracks)));
|
||||
|
||||
// TODO The function createLocalTracksF logs the rejection reason of
|
||||
// JitsiMeetJS.createLocalTracks so there is no real benefit to
|
||||
// logging it here as well. Technically though,
|
||||
// _updateLocalTracks may cause a rejection so it may be nice to log
|
||||
// it. It's not too big of a concern at the time of this writing
|
||||
// because React Native warns on unhandled Promise rejections.
|
||||
.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
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import './middleware';
|
|
@ -0,0 +1,25 @@
|
|||
/* @flow */
|
||||
|
||||
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.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(() => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case TRACK_PERMISSION_ERROR:
|
||||
alertPermissionErrorWithSettings(action.trackType);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
Loading…
Reference in New Issue