[RN] Alert the user when they need to manually grant a permission

This commit is contained in:
Saúl Ibarra Corretgé 2017-08-18 12:54:05 +02:00 committed by Lyubo Marinov
parent 9bca0e3b3d
commit 26f0f7f89c
8 changed files with 149 additions and 9 deletions

View File

@ -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);
}
}

View File

@ -59,6 +59,7 @@ public class JitsiMeetView extends FrameLayout {
private static List<NativeModule> createNativeModules( private static List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) { ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList( return Arrays.<NativeModule>asList(
new AndroidSettingsModule(reactContext),
new AudioModeModule(reactContext), new AudioModeModule(reactContext),
new ExternalAPIModule(reactContext), new ExternalAPIModule(reactContext),
new ProximityModule(reactContext) new ProximityModule(reactContext)

View File

@ -8,6 +8,7 @@ import '../../mobile/audio-mode';
import '../../mobile/background'; import '../../mobile/background';
import '../../mobile/external-api'; import '../../mobile/external-api';
import '../../mobile/full-screen'; import '../../mobile/full-screen';
import '../../mobile/permissions';
import '../../mobile/proximity'; import '../../mobile/proximity';
import '../../mobile/wake-lock'; import '../../mobile/wake-lock';

View File

@ -9,6 +9,17 @@
*/ */
export const TRACK_ADDED = Symbol('TRACK_ADDED'); 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, * Action for when a track has been removed from the conference,
* local or remote. * local or remote.

View File

@ -7,7 +7,12 @@ import {
} from '../media'; } from '../media';
import { getLocalParticipant } from '../participants'; 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'; import { createLocalTracksF } from './functions';
/** /**
@ -78,14 +83,19 @@ export function createLocalTracksA(options = {}) {
}, },
/* firePermissionPromptIsShownEvent */ false, /* firePermissionPromptIsShownEvent */ false,
store) store)
.then(localTracks => dispatch(_updateLocalTracks(localTracks))); .then(localTracks => dispatch(_updateLocalTracks(localTracks)))
.catch(({ gum }) => {
// TODO The function createLocalTracksF logs the rejection reason of // If permissions are not allowed, alert the user.
// JitsiMeetJS.createLocalTracks so there is no real benefit to if (gum
// logging it here as well. Technically though, && gum.error
// _updateLocalTracks may cause a rejection so it may be nice to log && gum.error.name === 'DOMException'
// it. It's not too big of a concern at the time of this writing && gum.error.message === 'NotAllowedError') {
// because React Native warns on unhandled Promise rejections. dispatch({
type: TRACK_PERMISSION_ERROR,
trackType: device
});
}
});
} }
}; };
} }

View File

@ -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;
}
}

View File

@ -0,0 +1 @@
import './middleware';

View File

@ -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;
});