[RN] Consistency in Jitsi Meet SDK for Android
This commit is contained in:
parent
84463d8cf0
commit
90466183d6
|
@ -1,24 +1,38 @@
|
||||||
# Jitsi Meet for Android
|
# Jitsi Meet SDK for Android
|
||||||
|
|
||||||
This directory contains the source code for Jitsi Meet for Android (the
|
This directory contains the source code of the Jitsi Meet app and the Jitsi Meet
|
||||||
application) and the Jitsi Meet SDK for Android.
|
SDK for Android.
|
||||||
|
|
||||||
## Jitsi Meet SDK
|
## Jitsi Meet SDK
|
||||||
|
|
||||||
Jitsi Meet SDK is an Android library which embodies the Jitsi Meet experience,
|
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
|
||||||
gift-wrapped so other applications can use it. Example use:
|
experience and makes it reusable by third-party apps.
|
||||||
|
|
||||||
|
To get started, extends your `android.app.Activity` from
|
||||||
|
`org.jitsi.meet.sdk.JitsiMeetActivity`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package org.jitsi.example;
|
||||||
|
|
||||||
|
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||||
|
|
||||||
|
public class MainActivity extends JitsiMeetActivity {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use the `org.jitsi.meet.sdk.JitsiMeetView` class which
|
||||||
|
extends `android.view.View`:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
package org.jitsi.example;
|
package org.jitsi.example;
|
||||||
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.jitsi.meet.sdk.*;
|
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
public class CustomActivity extends AppCompatActivity {
|
private JitsiMeetView view;
|
||||||
private JitsiMeetView jitsiMeetView;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
|
@ -32,10 +46,17 @@ public class CustomActivity extends AppCompatActivity {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
jitsiMeetView = new JitsiMeetView(this);
|
view = new JitsiMeetView(this);
|
||||||
jitsiMeetView.loadURL(null);
|
view.loadURL(null);
|
||||||
|
|
||||||
setContentView(jitsiMeetView);
|
setContentView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
JitsiMeetView.onHostDestroy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,45 +64,26 @@ public class CustomActivity extends AppCompatActivity {
|
||||||
JitsiMeetView.onNewIntent(intent);
|
JitsiMeetView.onNewIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
JitsiMeetView.onHostDestroy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
JitsiMeetView.onHostPause(this);
|
JitsiMeetView.onHostPause(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
JitsiMeetView.onHostResume(this);
|
JitsiMeetView.onHostResume(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can use the `JitsiMeetBaseActivity` class, which already has
|
### JitsiMeetActivity
|
||||||
all activity lifecycle methods hooked up:
|
|
||||||
|
|
||||||
```java
|
This class encapsulates a high level API in the form of an Android `Activity`
|
||||||
package org.jitsi.example;
|
which displays a single `JitsiMeetView`.
|
||||||
|
|
||||||
import org.jitsi.meet.sdk.*;
|
|
||||||
|
|
||||||
|
|
||||||
public class MainActivity extends JitsiMeetBaseActivity {
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### JitsiMeetBaseActivity
|
|
||||||
|
|
||||||
This class encapsulates a high level API in the form of an Android activity
|
|
||||||
which displays a single `JitsiMeetView` views.
|
|
||||||
|
|
||||||
#### loadURL(url)
|
#### loadURL(url)
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ See JitsiMeetView.loadURL.
|
||||||
### JitsiMeetView
|
### JitsiMeetView
|
||||||
|
|
||||||
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
|
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
|
||||||
display a Jitsi Meet conference view (or a welcome page).
|
display a Jitsi Meet conference (or a welcome page).
|
||||||
|
|
||||||
#### getListener()
|
#### getListener()
|
||||||
|
|
||||||
|
@ -99,8 +101,8 @@ Returns the `JitsiMeetView.Listener` instance attached to the view.
|
||||||
|
|
||||||
#### loadURL(url)
|
#### loadURL(url)
|
||||||
|
|
||||||
Loads the given URL and joins the conference which is being pointed to. If null,
|
Loads the given URL and joins the room. If `null` is specified, the welcome page
|
||||||
it will load the welcome page.
|
is displayed instead.
|
||||||
|
|
||||||
#### setListener(listener)
|
#### setListener(listener)
|
||||||
|
|
||||||
|
@ -110,8 +112,8 @@ interface) on the view.
|
||||||
#### onBackPressed()
|
#### onBackPressed()
|
||||||
|
|
||||||
Helper method which should be called from the activity's `onBackPressed` method.
|
Helper method which should be called from the activity's `onBackPressed` method.
|
||||||
If this function returns `true` it means the action was handled and thus no
|
If this function returns `true`, it means the action was handled and thus no
|
||||||
extra processing is required, otherwise the application should call the parent's
|
extra processing is required; otherwise the app should call the parent's
|
||||||
`onBackPressed` method.
|
`onBackPressed` method.
|
||||||
|
|
||||||
This is a static method.
|
This is a static method.
|
||||||
|
@ -136,16 +138,16 @@ This is a static method.
|
||||||
|
|
||||||
#### onNewIntent(intent)
|
#### onNewIntent(intent)
|
||||||
|
|
||||||
Helper method for integrating the *deep linking* functionality. If your
|
Helper method for integrating the *deep linking* functionality. If your app's
|
||||||
application's activity is launched in "singleTask" mode this method should
|
activity is launched in "singleTask" mode this method should be called from the
|
||||||
be called from the activity's `onNewIntent` method.
|
activity's `onNewIntent` method.
|
||||||
|
|
||||||
This is a static method.
|
This is a static method.
|
||||||
|
|
||||||
#### Listener
|
#### Listener
|
||||||
|
|
||||||
JitsiMeetView.Listener provides an interface applications can implement in order
|
JitsiMeetView.Listener provides an interface apps can implement in order to get
|
||||||
to get notified about the state of the Jitsi Meet conference.
|
notified about the state of the Jitsi Meet conference.
|
||||||
|
|
||||||
##### onConferenceFailed
|
##### onConferenceFailed
|
||||||
|
|
||||||
|
@ -178,4 +180,3 @@ The `data` HashMap contains a "url" key with the conference URL.
|
||||||
Called before a conference is left.
|
Called before a conference is left.
|
||||||
|
|
||||||
The `data` HashMap contains a "url" key with the conference URL.
|
The `data` HashMap contains a "url" key with the conference URL.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||||
|
|
|
@ -16,18 +16,19 @@
|
||||||
|
|
||||||
package org.jitsi.meet;
|
package org.jitsi.meet;
|
||||||
|
|
||||||
import org.jitsi.meet.sdk.JitsiMeetBaseActivity;
|
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The one and only Activity that Jitsi Meet (the app) needs. The activity is launched in
|
* The one and only {@link Activity} that the Jitsi Meet app needs. The
|
||||||
* "singleTask" mode, so it will be created upon application initialization and there will be
|
* {@code Activity} is launched in {@code singleTask} mode, so it will be
|
||||||
* a single instance of it. Further attempts at launching the application once it was already
|
* created upon application initialization and there will be a single instance
|
||||||
* launched will result in <tt>onNewIntent</tt> being called.
|
* of it. Further attempts at launching the application once it was already
|
||||||
|
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
|
||||||
*
|
*
|
||||||
* This Activity inherits from JitsiMeetBaseActivity without adding anything to it. It merely exists to
|
* This {@code Activity} extends {@link JitsiMeetActivity} without adding
|
||||||
* keep the React Native CLI working, since it always tries to launch an activity called
|
* anything to it. It exists to merely keep the React Native CLI working, since
|
||||||
* "MainActivity" when doing "react-native run-android".
|
* the latter always tries to launch an {@code Activity} named
|
||||||
|
* {@code MainActivity} when doing {@code react-native run-android}.
|
||||||
*/
|
*/
|
||||||
public class MainActivity extends JitsiMeetBaseActivity {
|
public class MainActivity extends JitsiMeetActivity {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all
|
||||||
|
// sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -8,7 +9,7 @@ buildscript {
|
||||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +18,8 @@ allprojects {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven {
|
maven {
|
||||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
// All of React Native (JS, Obj-C sources, Android binaries) is
|
||||||
|
// installed from npm.
|
||||||
url "$rootDir/../node_modules/react-native/android"
|
url "$rootDir/../node_modules/react-native/android"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ gradle.projectsEvaluated {
|
||||||
def buildNameCapitalized = "${buildType.name.capitalize()}"
|
def buildNameCapitalized = "${buildType.name.capitalize()}"
|
||||||
def bundlePath = "${buildDir}/intermediates/bundles/${buildType.name}"
|
def bundlePath = "${buildDir}/intermediates/bundles/${buildType.name}"
|
||||||
|
|
||||||
// Bundle fonts in react-native-vector-icons
|
// Bundle fonts in react-native-vector-icons.
|
||||||
//
|
//
|
||||||
|
|
||||||
def currentFontTask = tasks.create(name: "${buildType.name}CopyFonts", type: Copy) {
|
def currentFontTask = tasks.create(name: "${buildType.name}CopyFonts", type: Copy) {
|
||||||
|
@ -63,35 +63,43 @@ gradle.projectsEvaluated {
|
||||||
runBefore("processUniversal${buildNameCapitalized}Resources", currentFontTask)
|
runBefore("processUniversal${buildNameCapitalized}Resources", currentFontTask)
|
||||||
runBefore("process${buildNameCapitalized}Resources", currentFontTask)
|
runBefore("process${buildNameCapitalized}Resources", currentFontTask)
|
||||||
|
|
||||||
// Bundle JavaScript and React resources
|
// Bundle JavaScript and React resources.
|
||||||
// (adapted from react-native/react.gradle)
|
// (adapted from react-native/react.gradle)
|
||||||
//
|
//
|
||||||
|
|
||||||
// React js bundle directories
|
// React JS bundle directories
|
||||||
def jsBundleDir = file("${bundlePath}/assets")
|
def jsBundleDir = file("${bundlePath}/assets")
|
||||||
def resourcesDir = file("${bundlePath}/res/merged")
|
def resourcesDir = file("${bundlePath}/res/merged")
|
||||||
def jsBundleFile = file("${jsBundleDir}/index.android.bundle")
|
def jsBundleFile = file("${jsBundleDir}/index.android.bundle")
|
||||||
|
|
||||||
// Bundle task name for variant
|
// Bundle task name for variant.
|
||||||
def bundleJsAndAssetsTaskName = "bundle${buildNameCapitalized}JsAndAssets"
|
def bundleJsAndAssetsTaskName = "bundle${buildNameCapitalized}JsAndAssets"
|
||||||
|
|
||||||
def currentBundleTask = tasks.create(
|
def currentBundleTask = tasks.create(
|
||||||
name: bundleJsAndAssetsTaskName,
|
name: bundleJsAndAssetsTaskName,
|
||||||
type: Exec) {
|
type: Exec) {
|
||||||
|
|
||||||
// Set up inputs and outputs so gradle can cache the result
|
// Set up inputs and outputs so gradle can cache the result.
|
||||||
def reactRoot = file("${projectDir}/../../")
|
def reactRoot = file("${projectDir}/../../")
|
||||||
inputs.files fileTree(dir: reactRoot, excludes: ["android/**", "ios/**"])
|
inputs.files fileTree(dir: reactRoot, excludes: ["android/**", "ios/**"])
|
||||||
outputs.dir jsBundleDir
|
outputs.dir jsBundleDir
|
||||||
outputs.dir resourcesDir
|
outputs.dir resourcesDir
|
||||||
|
|
||||||
// Set up the call to the react-native cli
|
// Set up the call to the react-native cli.
|
||||||
workingDir reactRoot
|
workingDir reactRoot
|
||||||
|
|
||||||
// Create JS bundle
|
// Create JS bundle
|
||||||
def devEnabled = !buildNameCapitalized.toLowerCase().contains("release")
|
def devEnabled = !buildNameCapitalized.toLowerCase().contains("release")
|
||||||
commandLine("node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
|
commandLine(
|
||||||
"--reset-cache", "--entry-file", "index.android.js", "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir)
|
"node",
|
||||||
|
"node_modules/react-native/local-cli/cli.js",
|
||||||
|
"bundle",
|
||||||
|
"--assets-dest", resourcesDir,
|
||||||
|
"--bundle-output", jsBundleFile,
|
||||||
|
"--dev", "${devEnabled}",
|
||||||
|
"--entry-file", "index.android.js",
|
||||||
|
"--platform", "android",
|
||||||
|
"--reset-cache")
|
||||||
|
|
||||||
// TODO: disable task in Debug mode?
|
// TODO: disable task in Debug mode?
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,53 +26,57 @@ import android.os.Bundle;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Activity for applications integrating Jitsi Meet at a higher level. It contains all the
|
* Base Activity for applications integrating Jitsi Meet at a higher level. It
|
||||||
* required wiring between the <tt>JKConferenceView</tt> and the Activity lifecycle methods already
|
* contains all the required wiring between the <tt>JKConferenceView</tt> and
|
||||||
* implemented.
|
* the Activity lifecycle methods already implemented.
|
||||||
*
|
*
|
||||||
* In this activity we use a single <tt>JKConferenceView</tt> instance. This instance gives us
|
* In this activity we use a single <tt>JKConferenceView</tt> instance. This
|
||||||
* access to a view which displays the welcome page and the conference itself. All lifetime methods
|
* instance gives us access to a view which displays the welcome page and the
|
||||||
* associated with this Activity are hooked to the React Native subsystem via proxy calls through
|
* conference itself. All lifetime methods associated with this Activity are
|
||||||
* the <tt>JKConferenceView</tt> static methods.
|
* hooked to the React Native subsystem via proxy calls through the
|
||||||
|
* <tt>JKConferenceView</tt> static methods.
|
||||||
*/
|
*/
|
||||||
public class JitsiMeetBaseActivity extends AppCompatActivity {
|
public class JitsiMeetActivity extends AppCompatActivity {
|
||||||
/**
|
/**
|
||||||
* Instance of the {@JitsiMeetView} which this activity will display.
|
* Code for identifying the permission to draw on top of other apps. The
|
||||||
*/
|
* number is chosen arbitrarily and used to correlate the intent with its
|
||||||
private JitsiMeetView jitsiMeetView;
|
* result.
|
||||||
|
|
||||||
/**
|
|
||||||
* Code for identifying the permission to draw on top of other apps. The number is chosen
|
|
||||||
* arbitrarily and used to correlate the intent with its result.
|
|
||||||
*/
|
*/
|
||||||
public static final int OVERLAY_PERMISSION_REQ_CODE = 4242;
|
public static final int OVERLAY_PERMISSION_REQ_CODE = 4242;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the given URL and displays the conference. If the specified URL is null, the welcome
|
* Instance of the {@JitsiMeetView} which this activity will display.
|
||||||
* page is displayed instead.
|
*/
|
||||||
|
private JitsiMeetView view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given URL and displays the conference. If the specified URL is
|
||||||
|
* null, the welcome page is displayed instead.
|
||||||
*
|
*
|
||||||
* @param url - The conference URL.
|
* @param url - The conference URL.
|
||||||
*/
|
*/
|
||||||
public void loadURL(@Nullable URL url) {
|
public void loadURL(@Nullable URL url) {
|
||||||
jitsiMeetView.loadURL(url);
|
view.loadURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(
|
||||||
|
int requestCode,
|
||||||
|
int resultCode,
|
||||||
|
Intent data) {
|
||||||
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
|
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (!Settings.canDrawOverlays(this)) {
|
if (!Settings.canDrawOverlays(this)) {
|
||||||
// Permission not granted...
|
// Permission not granted.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(jitsiMeetView);
|
setContentView(view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,24 +98,34 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
jitsiMeetView = new JitsiMeetView(this);
|
view = new JitsiMeetView(this);
|
||||||
jitsiMeetView.loadURL(null);
|
view.loadURL(null);
|
||||||
|
|
||||||
/**
|
|
||||||
* In debug mode React needs permission to write over other apps in order to display the
|
|
||||||
* warning and error overlays.
|
|
||||||
*/
|
|
||||||
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
|
||||||
!Settings.canDrawOverlays(this)) {
|
|
||||||
|
|
||||||
|
// In debug mode React needs permission to write over other apps in
|
||||||
|
// order to display the warning and error overlays.
|
||||||
|
if (BuildConfig.DEBUG
|
||||||
|
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
&& !Settings.canDrawOverlays(this)) {
|
||||||
Intent intent
|
Intent intent
|
||||||
= new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
= new Intent(
|
||||||
Uri.parse("package:" + getPackageName()));
|
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||||
|
Uri.parse("package:" + getPackageName()));
|
||||||
|
|
||||||
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
|
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(jitsiMeetView);
|
setContentView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
JitsiMeetView.onHostDestroy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,21 +136,13 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
|
||||||
JitsiMeetView.onNewIntent(intent);
|
JitsiMeetView.onNewIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
JitsiMeetView.onHostDestroy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
JitsiMeetView.onHostPause(this);
|
JitsiMeetView.onHostPause(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +152,7 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
JitsiMeetView.onHostResume(this);
|
JitsiMeetView.onHostResume(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -32,56 +32,58 @@ import com.facebook.react.common.LifecycleState;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
public class JitsiMeetView extends FrameLayout {
|
public class JitsiMeetView extends FrameLayout {
|
||||||
/**
|
/**
|
||||||
* Background color used by this view and the React Native root view.
|
* Background color used by {@code JitsiMeetView} and the React Native root
|
||||||
|
* view.
|
||||||
*/
|
*/
|
||||||
private static final int BACKGROUND_COLOR = 0xFF111111;
|
private static final int BACKGROUND_COLOR = 0xFF111111;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@JitsiMeetView.Listener} instance for reporting events occurring in Jitsi Meet.
|
* Reference to the single instance of this class we currently allow. It's
|
||||||
|
* currently used for fetching the instance from the listener's callbacks.
|
||||||
|
*
|
||||||
|
* TODO: lift this limitation.
|
||||||
|
*/
|
||||||
|
private static JitsiMeetView instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React Native bridge. The instance manager allows embedding applications
|
||||||
|
* to create multiple root views off the same JavaScript bundle.
|
||||||
|
*/
|
||||||
|
private static ReactInstanceManager reactInstanceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@JitsiMeetView.Listener} instance for reporting events occurring in
|
||||||
|
* Jitsi Meet.
|
||||||
*/
|
*/
|
||||||
private JitsiMeetView.Listener listener;
|
private JitsiMeetView.Listener listener;
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the single instance of this class we currently allow. It's currently used for
|
|
||||||
* fetching the instance from the listener's callbacks.
|
|
||||||
*
|
|
||||||
* TODO: lift this limitation.
|
|
||||||
*/
|
|
||||||
private static JitsiMeetView mInstance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* React Native bridge. The instance manager allows embedding applications to create multiple
|
|
||||||
* root views off the same JavaScript bundle.
|
|
||||||
*/
|
|
||||||
private static ReactInstanceManager mReactInstanceManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React Native root view.
|
* React Native root view.
|
||||||
*/
|
*/
|
||||||
private ReactRootView mReactRootView;
|
private ReactRootView reactRootView;
|
||||||
|
|
||||||
public JitsiMeetView(@NonNull Context context) {
|
public JitsiMeetView(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
if (mInstance != null) {
|
if (instance != null) {
|
||||||
throw new RuntimeException("Only a single instance is currently allowed");
|
throw new RuntimeException(
|
||||||
|
"Only a single instance is currently allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Only allow a single instance for now. All React Native modules are
|
* TODO: Only allow a single instance for now. All React Native modules
|
||||||
* kinda singletons so global state would be broken since we have a single
|
* are kinda singletons so global state would be broken since we have a
|
||||||
* bridge. Once we have that sorted out multiple instances of JitsiMeetView
|
* single bridge. Once we have that sorted out multiple instances of
|
||||||
* will be allowed.
|
* JitsiMeetView will be allowed.
|
||||||
*/
|
*/
|
||||||
mInstance = this;
|
instance = this;
|
||||||
|
|
||||||
setBackgroundColor(BACKGROUND_COLOR);
|
setBackgroundColor(BACKGROUND_COLOR);
|
||||||
|
|
||||||
if (mReactInstanceManager == null) {
|
if (reactInstanceManager == null) {
|
||||||
initReactInstanceManager(((Activity)context).getApplication());
|
initReactInstanceManager(((Activity) context).getApplication());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
* @returns The {@JitsiMeetView} instance.
|
* @returns The {@JitsiMeetView} instance.
|
||||||
*/
|
*/
|
||||||
public static JitsiMeetView getInstance() {
|
public static JitsiMeetView getInstance() {
|
||||||
return mInstance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,14 +106,15 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to initialize the React Native instance manager. We create a single instance
|
* Internal method to initialize the React Native instance manager. We
|
||||||
* in order to load the JavaScript bundle a single time. All <tt>ReactRootView</tt> instances
|
* create a single instance in order to load the JavaScript bundle a single
|
||||||
* will be tied to the one and only <tt>ReactInstanceManager</tt>.
|
* time. All <tt>ReactRootView</tt> instances will be tied to the one and
|
||||||
|
* only <tt>ReactInstanceManager</tt>.
|
||||||
*
|
*
|
||||||
* @param application - <tt>Application</tt> instance which is running.
|
* @param application - <tt>Application</tt> instance which is running.
|
||||||
*/
|
*/
|
||||||
private static void initReactInstanceManager(Application application) {
|
private static void initReactInstanceManager(Application application) {
|
||||||
mReactInstanceManager = ReactInstanceManager.builder()
|
reactInstanceManager = ReactInstanceManager.builder()
|
||||||
.setApplication(application)
|
.setApplication(application)
|
||||||
.setBundleAssetName("index.android.bundle")
|
.setBundleAssetName("index.android.bundle")
|
||||||
.setJSMainModuleName("index.android")
|
.setJSMainModuleName("index.android")
|
||||||
|
@ -130,8 +133,8 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the given URL and displays the conference. If the specified URL is null, the welcome
|
* Loads the given URL and displays the conference. If the specified URL is
|
||||||
* page is displayed instead.
|
* null, the welcome page is displayed instead.
|
||||||
*
|
*
|
||||||
* @param url - The conference URL.
|
* @param url - The conference URL.
|
||||||
*/
|
*/
|
||||||
|
@ -142,17 +145,18 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
props.putString("url", url.toString());
|
props.putString("url", url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ReactRootView#setAppProperties is only available on React Native 0.45, so destroy
|
// TODO: ReactRootView#setAppProperties is only available on React
|
||||||
// the current root view and create a new one.
|
// Native 0.45, so destroy the current root view and create a new one.
|
||||||
if (mReactRootView != null) {
|
if (reactRootView != null) {
|
||||||
removeView(mReactRootView);
|
removeView(reactRootView);
|
||||||
mReactRootView = null;
|
reactRootView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mReactRootView = new ReactRootView(getContext());
|
reactRootView = new ReactRootView(getContext());
|
||||||
mReactRootView.startReactApplication(mReactInstanceManager, "App", props);
|
reactRootView
|
||||||
mReactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
.startReactApplication(reactInstanceManager, "App", props);
|
||||||
addView(mReactRootView);
|
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
||||||
|
addView(reactRootView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,15 +169,17 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity lifecycle method which should be called from <tt>Activity.onBackPressed</tt> so
|
* Activity lifecycle method which should be called from
|
||||||
* we can do the required internal processing.
|
* <tt>Activity.onBackPressed</tt> so we can do the required internal
|
||||||
|
* processing.
|
||||||
*
|
*
|
||||||
* @return - true if the back-press was processed, false otherwise. In case false is returned
|
* @return - true if the back-press was processed, false otherwise. In case
|
||||||
* the application should call the parent's implementation.
|
* false is returned the application should call the parent's
|
||||||
|
* implementation.
|
||||||
*/
|
*/
|
||||||
public static boolean onBackPressed() {
|
public static boolean onBackPressed() {
|
||||||
if (mReactInstanceManager != null) {
|
if (reactInstanceManager != null) {
|
||||||
mReactInstanceManager.onBackPressed();
|
reactInstanceManager.onBackPressed();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -181,52 +187,54 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity lifecycle method which should be called from <tt>Activity.onDestroy</tt> so
|
* Activity lifecycle method which should be called from
|
||||||
* we can do the required internal processing.
|
* <tt>Activity.onDestroy</tt> so we can do the required internal
|
||||||
|
* processing.
|
||||||
*
|
*
|
||||||
* @param activity - <tt>Activity</tt> being destroyed.
|
* @param activity - <tt>Activity</tt> being destroyed.
|
||||||
*/
|
*/
|
||||||
public static void onHostDestroy(Activity activity) {
|
public static void onHostDestroy(Activity activity) {
|
||||||
if (mReactInstanceManager != null) {
|
if (reactInstanceManager != null) {
|
||||||
mReactInstanceManager.onHostDestroy(activity);
|
reactInstanceManager.onHostDestroy(activity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity lifecycle method which should be called from <tt>Activity.onPause</tt> so
|
* Activity lifecycle method which should be called from
|
||||||
* we can do the required internal processing.
|
* <tt>Activity.onPause</tt> so we can do the required internal processing.
|
||||||
*
|
*
|
||||||
* @param activity - <tt>Activity</tt> being paused.
|
* @param activity - <tt>Activity</tt> being paused.
|
||||||
*/
|
*/
|
||||||
public static void onHostPause(Activity activity) {
|
public static void onHostPause(Activity activity) {
|
||||||
if (mReactInstanceManager != null) {
|
if (reactInstanceManager != null) {
|
||||||
mReactInstanceManager.onHostPause(activity);
|
reactInstanceManager.onHostPause(activity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity lifecycle method which should be called from <tt>Activity.onResume</tt> so
|
* Activity lifecycle method which should be called from
|
||||||
* we can do the required internal processing.
|
* <tt>Activity.onResume</tt> so we can do the required internal processing.
|
||||||
*
|
*
|
||||||
* @param activity - <tt>Activity</tt> being resumed.
|
* @param activity - <tt>Activity</tt> being resumed.
|
||||||
*/
|
*/
|
||||||
public static void onHostResume(Activity activity) {
|
public static void onHostResume(Activity activity) {
|
||||||
if (mReactInstanceManager != null) {
|
if (reactInstanceManager != null) {
|
||||||
mReactInstanceManager.onHostResume(activity, null);
|
reactInstanceManager.onHostResume(activity, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity lifecycle method which should be called from <tt>Activity.onNewIntent</tt> so
|
* Activity lifecycle method which should be called from
|
||||||
* we can do the required internal processing. Note that this is only needed if the activity's
|
* <tt>Activity.onNewIntent</tt> so we can do the required internal
|
||||||
* "launchMode" was set to "singleTask". This is required for deep linking to work once the
|
* processing. Note that this is only needed if the activity's "launchMode"
|
||||||
* application is already running.
|
* was set to "singleTask". This is required for deep linking to work once
|
||||||
|
* the application is already running.
|
||||||
*
|
*
|
||||||
* @param intent - <tt>Intent</tt> instance which was received.
|
* @param intent - <tt>Intent</tt> instance which was received.
|
||||||
*/
|
*/
|
||||||
public static void onNewIntent(Intent intent) {
|
public static void onNewIntent(Intent intent) {
|
||||||
if (mReactInstanceManager != null) {
|
if (reactInstanceManager != null) {
|
||||||
mReactInstanceManager.onNewIntent(intent);
|
reactInstanceManager.onNewIntent(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,33 +243,38 @@ public class JitsiMeetView extends FrameLayout {
|
||||||
*/
|
*/
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
/**
|
/**
|
||||||
* Called when joining a conference fails or an ongoing conference is interrupted due to a
|
* Called when joining a conference fails or an ongoing conference is
|
||||||
* failure.
|
* interrupted due to a failure.
|
||||||
* @param data - HashMap with an "error" key describing the problem, and a "url" key with
|
*
|
||||||
* the conference URL.
|
* @param data - HashMap with an "error" key describing the problem, and
|
||||||
|
* a "url" key with the conference URL.
|
||||||
*/
|
*/
|
||||||
void onConferenceFailed(HashMap<String, Object> data);
|
void onConferenceFailed(HashMap<String, Object> data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a conference was joined.
|
* Called when a conference was joined.
|
||||||
|
*
|
||||||
* @param data - HashMap with a "url" key with the conference URL.
|
* @param data - HashMap with a "url" key with the conference URL.
|
||||||
*/
|
*/
|
||||||
void onConferenceJoined(HashMap<String, Object> data);
|
void onConferenceJoined(HashMap<String, Object> data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the conference was left, typically after hanging up.
|
* Called when the conference was left, typically after hanging up.
|
||||||
|
*
|
||||||
* @param data - HashMap with a "url" key with the conference URL.
|
* @param data - HashMap with a "url" key with the conference URL.
|
||||||
*/
|
*/
|
||||||
void onConferenceLeft(HashMap<String, Object> data);
|
void onConferenceLeft(HashMap<String, Object> data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before the conference is joined.
|
* Called before the conference is joined.
|
||||||
|
*
|
||||||
* @param data - HashMap with a "url" key with the conference URL.
|
* @param data - HashMap with a "url" key with the conference URL.
|
||||||
*/
|
*/
|
||||||
void onConferenceWillJoin(HashMap<String, Object> data);
|
void onConferenceWillJoin(HashMap<String, Object> data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before the conference is left.
|
* Called before the conference is left.
|
||||||
|
*
|
||||||
* @param data - HashMap with a "url" key with the conference URL.
|
* @param data - HashMap with a "url" key with the conference URL.
|
||||||
*/
|
*/
|
||||||
void onConferenceWillLeave(HashMap<String, Object> data);
|
void onConferenceWillLeave(HashMap<String, Object> data);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.jitsi.meet.sdk.JitsiMeetView;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module implementing a simple API to enable a proximity sensor-controlled
|
* Module implementing a simple API to enable a proximity sensor-controlled
|
||||||
* wake lock. When the lock is held, if the proximity sensor detects a nearby
|
* wake lock. When the lock is held, if the proximity sensor detects a nearby
|
||||||
|
@ -61,20 +60,22 @@ public class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an event that occurred on JavaScript to the view's listener.
|
* Dispatches an event that occurred on JavaScript to the view's listener.
|
||||||
|
*
|
||||||
* @param name - Event name.
|
* @param name - Event name.
|
||||||
* @param data - Ancillary data for the event.
|
* @param data - Ancillary data for the event.
|
||||||
*/
|
*/
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void sendEvent(final String name, ReadableMap data) {
|
public void sendEvent(final String name, ReadableMap data) {
|
||||||
JitsiMeetView view = JitsiMeetView.getInstance();
|
JitsiMeetView view = JitsiMeetView.getInstance();
|
||||||
JitsiMeetView.Listener listener = view != null ? view.getListener() : null;
|
JitsiMeetView.Listener listener
|
||||||
|
= view != null ? view.getListener() : null;
|
||||||
|
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Sigh, converting a ReadableMap to a HashMap is not supported until React Native
|
// TODO: Sigh, converting a ReadableMap to a HashMap is not supported
|
||||||
// 0.46.
|
// until React Native 0.46.
|
||||||
final HashMap<String, Object> dataMap = new HashMap<>();
|
final HashMap<String, Object> dataMap = new HashMap<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class ExternalAPIPackage implements ReactPackage {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<NativeModule> createNativeModules(
|
public List<NativeModule> createNativeModules(
|
||||||
ReactApplicationContext reactContext) {
|
ReactApplicationContext reactContext) {
|
||||||
List<NativeModule> modules = new ArrayList<>();
|
List<NativeModule> modules = new ArrayList<>();
|
||||||
|
|
||||||
modules.add(new ExternalAPIModule(reactContext));
|
modules.add(new ExternalAPIModule(reactContext));
|
||||||
|
@ -58,7 +58,7 @@ public class ExternalAPIPackage implements ReactPackage {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<ViewManager> createViewManagers(
|
public List<ViewManager> createViewManagers(
|
||||||
ReactApplicationContext reactContext) {
|
ReactApplicationContext reactContext) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,4 +108,3 @@ The `data` dictionary contains a "url" key with the conference URL.
|
||||||
Called before a conference is left.
|
Called before a conference is left.
|
||||||
|
|
||||||
The `data` dictionary contains a "url" key with the conference URL.
|
The `data` dictionary contains a "url" key with the conference URL.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#import "JitsiMeetView.h"
|
#import "JitsiMeetView.h"
|
||||||
|
|
||||||
|
|
||||||
@interface ExternalAPI : NSObject<RCTBridgeModule>
|
@interface ExternalAPI : NSObject<RCTBridgeModule>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -40,25 +39,20 @@ RCT_EXPORT_METHOD(sendEvent:(NSString*)name data:(NSDictionary *) data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([name isEqualToString:@"CONFERENCE_FAILED"] &&
|
if ([name isEqualToString:@"CONFERENCE_FAILED"]
|
||||||
[delegate respondsToSelector:@selector(conferenceFailed:)]) {
|
&& [delegate respondsToSelector:@selector(conferenceFailed:)]) {
|
||||||
|
|
||||||
[delegate conferenceFailed:data];
|
[delegate conferenceFailed:data];
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_JOINED"] &&
|
} else if ([name isEqualToString:@"CONFERENCE_JOINED"]
|
||||||
[delegate respondsToSelector:@selector(conferenceJoined:)]) {
|
&& [delegate respondsToSelector:@selector(conferenceJoined:)]) {
|
||||||
|
|
||||||
[delegate conferenceJoined:data];
|
[delegate conferenceJoined:data];
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_LEFT"] &&
|
} else if ([name isEqualToString:@"CONFERENCE_LEFT"]
|
||||||
[delegate respondsToSelector:@selector(conferenceLeft:)]) {
|
&& [delegate respondsToSelector:@selector(conferenceLeft:)]) {
|
||||||
|
|
||||||
[delegate conferenceLeft:data];
|
[delegate conferenceLeft:data];
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_WILL_JOIN"] &&
|
} else if ([name isEqualToString:@"CONFERENCE_WILL_JOIN"]
|
||||||
[delegate respondsToSelector:@selector(conferenceWillJoin:)]) {
|
&& [delegate respondsToSelector:@selector(conferenceWillJoin:)]) {
|
||||||
|
|
||||||
[delegate conferenceWillJoin:data];
|
[delegate conferenceWillJoin:data];
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_WILL_LEAVE"] &&
|
} else if ([name isEqualToString:@"CONFERENCE_WILL_LEAVE"]
|
||||||
[delegate respondsToSelector:@selector(conferenceWillLeave:)]) {
|
&& [delegate respondsToSelector:@selector(conferenceWillLeave:)]) {
|
||||||
|
|
||||||
[delegate conferenceWillLeave:data];
|
[delegate conferenceWillLeave:data];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
sourceApplication:(NSString *)sourceApplication
|
sourceApplication:(NSString *)sourceApplication
|
||||||
annotation:(id)annotation;
|
annotation:(id)annotation;
|
||||||
|
|
||||||
+ (instancetype) getInstance;
|
+ (instancetype)getInstance;
|
||||||
|
|
||||||
- (void)loadURL:(nullable NSURL *)url;
|
- (void)loadURL:(nullable NSURL *)url;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue