[RN] Make all delegate / listener methods run in the main / UI thread
This commit is contained in:
parent
ccbf3efa38
commit
ef7fb1a7b0
|
@ -28,6 +28,7 @@ import org.jitsi.meet.sdk.invite.InviteController;
|
|||
import org.jitsi.meet.sdk.invite.InviteControllerListener;
|
||||
|
||||
import com.calendarevents.CalendarEventsPackage;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -65,6 +66,8 @@ public class MainActivity extends JitsiMeetActivity {
|
|||
if (BuildConfig.DEBUG && view != null) {
|
||||
view.setListener(new JitsiMeetViewListener() {
|
||||
private void on(String name, Map<String, Object> data) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// Log with the tag "ReactNative" in order to have the log
|
||||
// visible in react-native log-android as well.
|
||||
Log.d(
|
||||
|
@ -112,6 +115,8 @@ public class MainActivity extends JitsiMeetActivity {
|
|||
inviteController.setListener(new InviteControllerListener() {
|
||||
public void beginAddPeople(
|
||||
AddPeopleController addPeopleController) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
onInviteControllerBeginAddPeople(
|
||||
inviteController,
|
||||
addPeopleController);
|
||||
|
@ -129,6 +134,8 @@ public class MainActivity extends JitsiMeetActivity {
|
|||
private void onAddPeopleControllerInviteSettled(
|
||||
AddPeopleController addPeopleController,
|
||||
List<Map<String, Object>> failedInvitees) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// XXX Explicitly invoke endAddPeople on addPeopleController; otherwise,
|
||||
// it is going to be memory-leaked in the associated InviteController
|
||||
// and no subsequent InviteButton clicks/taps will be delivered.
|
||||
|
@ -142,6 +149,8 @@ public class MainActivity extends JitsiMeetActivity {
|
|||
AddPeopleController addPeopleController,
|
||||
List<Map<String, Object>> results,
|
||||
String query) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
int size = results.size();
|
||||
|
||||
if (size > 0) {
|
||||
|
@ -182,6 +191,8 @@ public class MainActivity extends JitsiMeetActivity {
|
|||
private void onInviteControllerBeginAddPeople(
|
||||
InviteController inviteController,
|
||||
AddPeopleController addPeopleController) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// Log with the tag "ReactNative" in order to have the log visible in
|
||||
// react-native log-android as well.
|
||||
Log.d(
|
||||
|
|
|
@ -21,9 +21,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -150,43 +148,53 @@ class ExternalAPIModule extends ReactContextBaseJavaModule {
|
|||
* @param scope
|
||||
*/
|
||||
@ReactMethod
|
||||
public void sendEvent(String name, ReadableMap data, String scope) {
|
||||
// The JavaScript App needs to provide uniquely identifying information
|
||||
// to the native ExternalAPI module so that the latter may match the
|
||||
// former to the native JitsiMeetView which hosts it.
|
||||
JitsiMeetView view = JitsiMeetView.findViewByExternalAPIScope(scope);
|
||||
public void sendEvent(final String name,
|
||||
final ReadableMap data,
|
||||
final String scope) {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// The JavaScript App needs to provide uniquely identifying
|
||||
// information to the native ExternalAPI module so that the
|
||||
// latter may match the former to the native JitsiMeetView which
|
||||
// hosts it.
|
||||
JitsiMeetView view
|
||||
= JitsiMeetView.findViewByExternalAPIScope(scope);
|
||||
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeSetViewURL(name, data, view);
|
||||
maybeSetViewURL(name, data, view);
|
||||
|
||||
JitsiMeetViewListener listener = view.getListener();
|
||||
JitsiMeetViewListener listener = view.getListener();
|
||||
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method method = JITSI_MEET_VIEW_LISTENER_METHODS.get(name);
|
||||
Method method = JITSI_MEET_VIEW_LISTENER_METHODS.get(name);
|
||||
|
||||
if (method != null) {
|
||||
try {
|
||||
method.invoke(listener, toHashMap(data));
|
||||
} catch (IllegalAccessException e) {
|
||||
// FIXME There was a multicatch for IllegalAccessException and
|
||||
// InvocationTargetException, but Android Studio complained
|
||||
// with:
|
||||
// "Multi-catch with these reflection exceptions requires
|
||||
// API level 19 (current min is 16) because they get compiled to
|
||||
// the common but new super type ReflectiveOperationException.
|
||||
// As a workaround either create individual catch statements, or
|
||||
// catch Exception."
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
if (method != null) {
|
||||
try {
|
||||
method.invoke(listener, toHashMap(data));
|
||||
} catch (IllegalAccessException e) {
|
||||
// FIXME There was a multicatch for
|
||||
// IllegalAccessException and InvocationTargetException,
|
||||
// but Android Studio complained with: "Multi-catch with
|
||||
// these reflection exceptions requires API level 19
|
||||
// (current min is 16) because they get compiled to the
|
||||
// common but new super type
|
||||
// ReflectiveOperationException. As a workaround either
|
||||
// create individual catch statements, or
|
||||
// catch Exception."
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
|||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
|
||||
|
@ -42,13 +43,18 @@ public class InviteModule extends ReactContextBaseJavaModule {
|
|||
* {@code JitsiMeetView} whose {@code InviteButton} was clicked/tapped.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void beginAddPeople(String externalAPIScope) {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
public void beginAddPeople(final String externalAPIScope) {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
|
||||
if (inviteController != null) {
|
||||
inviteController.beginAddPeople(getReactApplicationContext());
|
||||
}
|
||||
if (inviteController != null) {
|
||||
inviteController.beginAddPeople(getReactApplicationContext());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private InviteController findInviteControllerByExternalAPIScope(
|
||||
|
@ -72,21 +78,26 @@ public class InviteModule extends ReactContextBaseJavaModule {
|
|||
*/
|
||||
@ReactMethod
|
||||
public void inviteSettled(
|
||||
String externalAPIScope,
|
||||
String addPeopleControllerScope,
|
||||
ReadableArray failedInvitees) {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
final String externalAPIScope,
|
||||
final String addPeopleControllerScope,
|
||||
final ReadableArray failedInvitees) {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
|
||||
if (inviteController == null) {
|
||||
Log.w(
|
||||
"InviteModule",
|
||||
"Invite settled, but failed to find active controller to notify");
|
||||
} else {
|
||||
inviteController.inviteSettled(
|
||||
addPeopleControllerScope,
|
||||
failedInvitees);
|
||||
}
|
||||
if (inviteController == null) {
|
||||
Log.w(
|
||||
"InviteModule",
|
||||
"Invite settled, but failed to find active controller to notify");
|
||||
} else {
|
||||
inviteController.inviteSettled(
|
||||
addPeopleControllerScope,
|
||||
failedInvitees);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,22 +109,27 @@ public class InviteModule extends ReactContextBaseJavaModule {
|
|||
*/
|
||||
@ReactMethod
|
||||
public void receivedResults(
|
||||
String externalAPIScope,
|
||||
String addPeopleControllerScope,
|
||||
String query,
|
||||
ReadableArray results) {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
final String externalAPIScope,
|
||||
final String addPeopleControllerScope,
|
||||
final String query,
|
||||
final ReadableArray results) {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
InviteController inviteController
|
||||
= findInviteControllerByExternalAPIScope(externalAPIScope);
|
||||
|
||||
if (inviteController == null) {
|
||||
Log.w(
|
||||
"InviteModule",
|
||||
"Received results, but failed to find active controller to send results back");
|
||||
} else {
|
||||
inviteController.receivedResultsForQuery(
|
||||
addPeopleControllerScope,
|
||||
query,
|
||||
results);
|
||||
}
|
||||
if (inviteController == null) {
|
||||
Log.w(
|
||||
"InviteModule",
|
||||
"Received results, but failed to find active controller to send results back");
|
||||
} else {
|
||||
inviteController.receivedResultsForQuery(
|
||||
addPeopleControllerScope,
|
||||
query,
|
||||
results);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <assert.h>
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
/**
|
||||
|
@ -64,6 +66,9 @@ void _onJitsiMeetViewDelegateEvent(NSString *name, NSDictionary *data) {
|
|||
NSLog(
|
||||
@"[%s:%d] JitsiMeetViewDelegate %@ %@",
|
||||
__FILE__, __LINE__, name, data);
|
||||
|
||||
assert([NSThread isMainThread]
|
||||
&& "Delegate method called in a non-main thread");
|
||||
}
|
||||
|
||||
- (void)conferenceFailed:(NSDictionary *)data {
|
||||
|
@ -97,6 +102,9 @@ void _onJitsiMeetViewDelegateEvent(NSString *name, NSDictionary *data) {
|
|||
@"[%s:%d] JMInviteControllerDelegate %s",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
assert([NSThread isMainThread]
|
||||
&& "Delegate method called in a non-main thread");
|
||||
|
||||
NSString *query = ADD_PEOPLE_CONTROLLER_QUERY;
|
||||
JitsiMeetView *view = (JitsiMeetView *) self.view;
|
||||
JMInviteController *inviteController = view.inviteController;
|
||||
|
@ -119,6 +127,9 @@ void _onJitsiMeetViewDelegateEvent(NSString *name, NSDictionary *data) {
|
|||
- (void)addPeopleController:(JMAddPeopleController * _Nonnull)controller
|
||||
didReceiveResults:(NSArray<NSDictionary *> * _Nonnull)results
|
||||
forQuery:(NSString * _Nonnull)query {
|
||||
assert([NSThread isMainThread]
|
||||
&& "Delegate method called in a non-main thread");
|
||||
|
||||
NSUInteger count = results.count;
|
||||
|
||||
if (count) {
|
||||
|
@ -151,6 +162,9 @@ void _onJitsiMeetViewDelegateEvent(NSString *name, NSDictionary *data) {
|
|||
|
||||
- (void) inviteSettled:(NSArray<NSDictionary *> * _Nonnull)failedInvitees
|
||||
fromSearchController:(JMAddPeopleController * _Nonnull)addPeopleController {
|
||||
assert([NSThread isMainThread]
|
||||
&& "Delegate method called in a non-main thread");
|
||||
|
||||
// XXX Explicitly invoke endAddPeople on addPeopleController; otherwise, it
|
||||
// is going to be memory-leaked in the associated JMInviteController and no
|
||||
// subsequent InviteButton clicks/taps will be delivered. Technically,
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
/**
|
||||
* Make sure all methods in this module are called in the main (i.e. UI) thread.
|
||||
*/
|
||||
- (dispatch_queue_t)methodQueue {
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event that occurred on JavaScript to the view's delegate.
|
||||
*
|
||||
|
|
|
@ -40,6 +40,13 @@ RCT_EXPORT_MODULE();
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure all methods in this module are called in the main (i.e. UI) thread.
|
||||
*/
|
||||
- (dispatch_queue_t)methodQueue {
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the process to add people. This involves calling a delegate method
|
||||
* in the JMInviteControllerDelegate so the native host application can start
|
||||
|
|
Loading…
Reference in New Issue