feat(mobile) adds ability to send and receive text messages (#8425)

This commit is contained in:
tmoldovan8x8 2021-01-20 14:06:45 +02:00 committed by GitHub
parent df21ec6f04
commit 61037b982b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 131 additions and 18 deletions

View File

@ -60,7 +60,8 @@ public class BroadcastAction {
enum Type {
SET_AUDIO_MUTED("org.jitsi.meet.SET_AUDIO_MUTED"),
HANG_UP("org.jitsi.meet.HANG_UP");
HANG_UP("org.jitsi.meet.HANG_UP"),
SEND_ENDPOINT_TEXT_MESSAGE("org.jitsi.meet.SEND_ENDPOINT_TEXT_MESSAGE");
private final String action;

View File

@ -80,7 +80,8 @@ public class BroadcastEvent {
CONFERENCE_WILL_JOIN("org.jitsi.meet.CONFERENCE_WILL_JOIN"),
AUDIO_MUTED_CHANGED("org.jitsi.meet.AUDIO_MUTED_CHANGED"),
PARTICIPANT_JOINED("org.jitsi.meet.PARTICIPANT_JOINED"),
PARTICIPANT_LEFT("org.jitsi.meet.PARTICIPANT_LEFT");
PARTICIPANT_LEFT("org.jitsi.meet.PARTICIPANT_LEFT"),
ENDPOINT_TEXT_MESSAGE_RECEIVED("org.jitsi.meet.ENDPOINT_TEXT_MESSAGE_RECEIVED");
private static final String CONFERENCE_WILL_JOIN_NAME = "CONFERENCE_WILL_JOIN";
private static final String CONFERENCE_JOINED_NAME = "CONFERENCE_JOINED";
@ -88,6 +89,7 @@ public class BroadcastEvent {
private static final String AUDIO_MUTED_CHANGED_NAME = "AUDIO_MUTED_CHANGED";
private static final String PARTICIPANT_JOINED_NAME = "PARTICIPANT_JOINED";
private static final String PARTICIPANT_LEFT_NAME = "PARTICIPANT_LEFT";
private static final String ENDPOINT_TEXT_MESSAGE_RECEIVED_NAME = "ENDPOINT_TEXT_MESSAGE_RECEIVED";
private final String action;
@ -122,6 +124,8 @@ public class BroadcastEvent {
return PARTICIPANT_JOINED;
case PARTICIPANT_LEFT_NAME:
return PARTICIPANT_LEFT;
case ENDPOINT_TEXT_MESSAGE_RECEIVED_NAME:
return ENDPOINT_TEXT_MESSAGE_RECEIVED;
}
return null;

View File

@ -12,4 +12,11 @@ public class BroadcastIntentHelper {
public static Intent buildHangUpIntent() {
return new Intent(BroadcastAction.Type.HANG_UP.getAction());
}
public static Intent buildSendEndpointTextMessageIntent(String to, String message) {
Intent intent = new Intent(BroadcastAction.Type.SEND_ENDPOINT_TEXT_MESSAGE.getAction());
intent.putExtra("to", to);
intent.putExtra("message", message);
return intent;
}
}

View File

@ -18,6 +18,7 @@ public class BroadcastReceiver extends android.content.BroadcastReceiver {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BroadcastAction.Type.SET_AUDIO_MUTED.getAction());
intentFilter.addAction(BroadcastAction.Type.HANG_UP.getAction());
intentFilter.addAction(BroadcastAction.Type.SEND_ENDPOINT_TEXT_MESSAGE.getAction());
localBroadcastManager.registerReceiver(this, intentFilter);
}

View File

@ -77,6 +77,7 @@ class ExternalAPIModule
constants.put("SET_AUDIO_MUTED", BroadcastAction.Type.SET_AUDIO_MUTED.getAction());
constants.put("HANG_UP", BroadcastAction.Type.HANG_UP.getAction());
constants.put("SEND_ENDPOINT_TEXT_MESSAGE", BroadcastAction.Type.SEND_ENDPOINT_TEXT_MESSAGE.getAction());
return constants;
}

View File

@ -271,6 +271,7 @@ public class JitsiMeetActivity extends FragmentActivity
intentFilter.addAction(BroadcastEvent.Type.CONFERENCE_TERMINATED.getAction());
intentFilter.addAction(BroadcastEvent.Type.PARTICIPANT_JOINED.getAction());
intentFilter.addAction(BroadcastEvent.Type.PARTICIPANT_LEFT.getAction());
intentFilter.addAction(BroadcastEvent.Type.ENDPOINT_TEXT_MESSAGE_RECEIVED.getAction());
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter);
}

View File

@ -115,6 +115,10 @@
NSLog(@"%@%@", @"Audio muted changed: ", data[@"muted"]);
}
- (void)endpointTextMessageReceived:(NSDictionary *)data; {
NSLog(@"%@%@", @"Endpoint text message received: ", data);
}
#pragma mark - Helpers
- (void)terminate {

View File

@ -20,5 +20,6 @@
- (void)sendHangUp;
- (void)sendSetAudioMuted: (BOOL)muted;
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message;
@end

View File

@ -18,8 +18,9 @@
#import "JitsiMeetView+Private.h"
// Events
static NSString * const hangUpEvent = @"org.jitsi.meet.HANG_UP";
static NSString * const setAudioMutedEvent = @"org.jitsi.meet.SET_AUDIO_MUTED";
static NSString * const hangUpAction = @"org.jitsi.meet.HANG_UP";
static NSString * const setAudioMutedAction = @"org.jitsi.meet.SET_AUDIO_MUTED";
static NSString * const sendEndpointTextMessageAction = @"org.jitsi.meet.SEND_ENDPOINT_TEXT_MESSAGE";
@implementation ExternalAPI
@ -27,8 +28,9 @@ RCT_EXPORT_MODULE();
- (NSDictionary *)constantsToExport {
return @{
@"HANG_UP": hangUpEvent,
@"SET_AUDIO_MUTED" : setAudioMutedEvent
@"HANG_UP": hangUpAction,
@"SET_AUDIO_MUTED" : setAudioMutedAction,
@"SEND_ENDPOINT_TEXT_MESSAGE": sendEndpointTextMessageAction
};
};
@ -44,7 +46,7 @@ RCT_EXPORT_MODULE();
}
- (NSArray<NSString *> *)supportedEvents {
return @[ hangUpEvent, setAudioMutedEvent ];
return @[ hangUpAction, setAudioMutedAction, sendEndpointTextMessageAction ];
}
/**
@ -103,13 +105,22 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
}
- (void)sendHangUp {
[self sendEventWithName:hangUpEvent body:nil];
[self sendEventWithName:hangUpAction body:nil];
}
- (void)sendSetAudioMuted:(BOOL)muted {
NSDictionary *data = @{ @"muted": [NSNumber numberWithBool:muted]};
[self sendEventWithName:setAudioMutedEvent body:data];
[self sendEventWithName:setAudioMutedAction body:data];
}
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message {
NSDictionary *data = @{
@"to": to,
@"message": message
};
[self sendEventWithName:sendEndpointTextMessageAction body:data];
}
@end

View File

@ -16,11 +16,13 @@
#import <React/RCTBridge.h>
#import "ExternalAPI.h"
#import "JitsiMeet.h"
@interface JitsiMeet ()
- (NSDictionary *)getDefaultProps;
- (RCTBridge *)getReactBridge;
- (ExternalAPI *)getExternalAPI;
@end

View File

@ -213,4 +213,8 @@
return _bridgeWrapper.bridge;
}
- (ExternalAPI *)getExternalAPI {
return [_bridgeWrapper.bridge moduleForClass:ExternalAPI.class];
}
@end

View File

@ -41,4 +41,6 @@
- (void)setAudioMuted:(BOOL)muted;
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message;
@end

View File

@ -116,13 +116,18 @@ static void initializeViewsMap() {
}
- (void)hangUp {
RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
[[bridge moduleForClass:ExternalAPI.class] sendHangUp];
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI sendHangUp];
}
- (void)setAudioMuted:(BOOL)muted {
RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
[[bridge moduleForClass:ExternalAPI.class] sendSetAudioMuted:muted];
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI sendSetAudioMuted:muted];
}
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message {
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI sendEndpointTextMessage:to :message];
}
#pragma mark Private methods

View File

@ -75,4 +75,12 @@
* The `data` dictionary contains a `muted` key with state of the audioMuted for the localParticipant.
*/
- (void)audioMutedChanged:(NSDictionary *)data;
/**
* Called when an endpoint text message is received.
*
* The `data` dictionary contains a `senderId` key with the participantId of the sender and a 'message' key with the content.
*/
- (void)endpointTextMessageReceived:(NSDictionary *)data;
@end

View File

@ -0,0 +1,5 @@
// @flow
import { getLogger } from '../../base/logging/functions';
export default getLogger('features/mobile/external-api');

View File

@ -2,6 +2,7 @@
import { NativeEventEmitter, NativeModules } from 'react-native';
import { ENDPOINT_TEXT_MESSAGE_NAME } from '../../../../modules/API/constants';
import { appNavigate } from '../../app/actions';
import { APP_WILL_MOUNT } from '../../base/app/actionTypes';
import {
@ -12,6 +13,7 @@ import {
JITSI_CONFERENCE_URL_KEY,
SET_ROOM,
forEachConference,
getCurrentConference,
isRoomValid
} from '../../base/conference';
import { LOAD_CONFIG_ERROR } from '../../base/config';
@ -22,6 +24,7 @@ import {
JITSI_CONNECTION_URL_KEY,
getURLWithoutParams
} from '../../base/connection';
import { JitsiConferenceEvents } from '../../base/lib-jitsi-meet';
import { SET_AUDIO_MUTED } from '../../base/media/actionTypes';
import { PARTICIPANT_JOINED, PARTICIPANT_LEFT } from '../../base/participants';
import { MiddlewareRegistry } from '../../base/redux';
@ -29,6 +32,7 @@ import { muteLocal } from '../../remote-video-menu/actions';
import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';
import { sendEvent } from './functions';
import logger from './logger';
/**
* Event which will be emitted on the native side to indicate the conference
@ -36,6 +40,12 @@ import { sendEvent } from './functions';
*/
const CONFERENCE_TERMINATED = 'CONFERENCE_TERMINATED';
/**
* Event which will be emitted on the native side to indicate a message was received
* through the channel.
*/
const ENDPOINT_TEXT_MESSAGE_RECEIVED = 'ENDPOINT_TEXT_MESSAGE_RECEIVED';
const { ExternalAPI } = NativeModules;
const eventEmitter = new NativeEventEmitter(ExternalAPI);
@ -52,7 +62,7 @@ MiddlewareRegistry.register(store => next => action => {
switch (type) {
case APP_WILL_MOUNT:
_registerForNativeEvents(store.dispatch);
_registerForNativeEvents(store);
break;
case CONFERENCE_FAILED: {
const { error, ...data } = action;
@ -75,12 +85,16 @@ MiddlewareRegistry.register(store => next => action => {
break;
}
case CONFERENCE_JOINED:
case CONFERENCE_LEFT:
case CONFERENCE_WILL_JOIN:
_sendConferenceEvent(store, action);
break;
case CONFERENCE_JOINED:
_sendConferenceEvent(store, action);
_registerForEndpointTextMessages(store);
break;
case CONNECTION_DISCONNECTED: {
// FIXME: This is a hack. See the description in the JITSI_CONNECTION_CONFERENCE_KEY constant definition.
// Check if this connection was attached to any conference. If it wasn't, fake a CONFERENCE_TERMINATED event.
@ -160,11 +174,11 @@ MiddlewareRegistry.register(store => next => action => {
/**
* Registers for events sent from the native side via NativeEventEmitter.
*
* @param {Dispatch} dispatch - The Redux dispatch function.
* @param {Store} store - The redux store.
* @private
* @returns {void}
*/
function _registerForNativeEvents(dispatch) {
function _registerForNativeEvents({ getState, dispatch }) {
eventEmitter.addListener(ExternalAPI.HANG_UP, () => {
dispatch(appNavigate(undefined));
});
@ -172,6 +186,48 @@ function _registerForNativeEvents(dispatch) {
eventEmitter.addListener(ExternalAPI.SET_AUDIO_MUTED, ({ muted }) => {
dispatch(muteLocal(muted === 'true'));
});
eventEmitter.addListener(ExternalAPI.SEND_ENDPOINT_TEXT_MESSAGE, ({ to, message }) => {
const conference = getCurrentConference(getState());
try {
conference && conference.sendEndpointMessage(to, {
name: ENDPOINT_TEXT_MESSAGE_NAME,
text: message
});
} catch (error) {
logger.warn('Cannot send endpointMessage', error);
}
});
}
/**
* Registers for endpoint messages sent on conference data channel.
*
* @param {Store} store - The redux store.
* @private
* @returns {void}
*/
function _registerForEndpointTextMessages(store) {
const conference = getCurrentConference(store.getState());
conference && conference.on(
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
(...args) => {
if (args && args.length >= 2) {
const [ sender, eventData ] = args;
if (eventData.name === ENDPOINT_TEXT_MESSAGE_NAME) {
sendEvent(
store,
ENDPOINT_TEXT_MESSAGE_RECEIVED,
/* data */ {
message: eventData.text,
senderId: sender._id
});
}
}
});
}
/**