From 6a1067733a38cef34514ecd071bd4727969007b5 Mon Sep 17 00:00:00 2001 From: tmoldovan8x8 <62697631+tmoldovan8x8@users.noreply.github.com> Date: Thu, 31 Mar 2022 17:47:40 +0300 Subject: [PATCH] feat(android) use JitsiMeetView instead of JitsiMeetFragment --- .../org/jitsi/meet/sdk/BaseReactView.java | 32 +++++++--- .../org/jitsi/meet/sdk/JitsiMeetActivity.java | 58 +++++++++++++------ .../org/jitsi/meet/sdk/JitsiMeetFragment.java | 4 +- .../org/jitsi/meet/sdk/JitsiMeetView.java | 28 ++++++--- .../main/res/layout/activity_jitsi_meet.xml | 9 +-- 5 files changed, 92 insertions(+), 39 deletions(-) diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java index a66c1bf7a..20000e262 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java @@ -20,6 +20,7 @@ package org.jitsi.meet.sdk; import android.app.Activity; import android.content.Context; import android.os.Bundle; +import android.util.AttributeSet; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -93,7 +94,7 @@ public abstract class BaseReactView * inspired by postis which we use on Web for the similar purposes of the * iframe-based external API. */ - protected final String externalAPIScope; + protected String externalAPIScope; /** * The listener (e.g. {@link JitsiMeetViewListener}) instance for reporting @@ -109,16 +110,17 @@ public abstract class BaseReactView public BaseReactView(@NonNull Context context) { super(context); + initialize((Activity)context); + } - setBackgroundColor(BACKGROUND_COLOR); + public BaseReactView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize((Activity)context); + } - ReactInstanceManagerHolder.initReactInstanceManager((Activity)context); - - // Hook this BaseReactView into ExternalAPI. - externalAPIScope = UUID.randomUUID().toString(); - synchronized (views) { - views.add(this); - } + public BaseReactView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize((Activity)context); } /** @@ -223,4 +225,16 @@ public abstract class BaseReactView public void setListener(ListenerT listener) { this.listener = listener; } + + private void initialize(Activity activity) { + setBackgroundColor(BACKGROUND_COLOR); + + ReactInstanceManagerHolder.initReactInstanceManager(activity); + + // Hook this BaseReactView into ExternalAPI. + externalAPIScope = UUID.randomUUID().toString(); + synchronized (views) { + views.add(this); + } + } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java index e76a2d48e..5df38317a 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java @@ -16,6 +16,7 @@ package org.jitsi.meet.sdk; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -32,11 +33,16 @@ import com.facebook.react.modules.core.PermissionListener; import org.jitsi.meet.sdk.log.JitsiMeetLogger; import java.util.HashMap; -import android.app.Activity; /** - * A base activity for SDK users to embed. It uses {@link JitsiMeetFragment} to do the heavy - * lifting and wires the remaining Activity lifecycle methods so it works out of the box. + * A base activity for SDK users to embed. It contains all the required wiring + * between the {@code JitsiMeetView} and the Activity lifecycle methods. + * + * In this activity we use a single {@code JitsiMeetView} instance. This + * instance gives us access to a view which displays the welcome page and the + * conference itself. All lifecycle methods associated with this Activity are + * hooked to the React Native subsystem via proxy calls through the + * {@code JitsiMeetActivityDelegate} static methods. */ public class JitsiMeetActivity extends AppCompatActivity implements JitsiMeetActivityInterface { @@ -52,6 +58,12 @@ public class JitsiMeetActivity extends AppCompatActivity onBroadcastReceived(intent); } }; + + /** + * Instance of the {@link JitsiMeetView} which this activity will display. + */ + private JitsiMeetView jitsiView; + // Helpers for starting the activity // @@ -79,6 +91,7 @@ public class JitsiMeetActivity extends AppCompatActivity super.onCreate(savedInstanceState); setContentView(R.layout.activity_jitsi_meet); + this.jitsiView = findViewById(R.id.jitsiView); registerForBroadcastMessages(); @@ -87,6 +100,18 @@ public class JitsiMeetActivity extends AppCompatActivity } } + @Override + public void onResume() { + super.onResume(); + JitsiMeetActivityDelegate.onHostResume(this); + } + + @Override + public void onStop() { + JitsiMeetActivityDelegate.onHostPause(this); + super.onStop(); + } + @Override public void onDestroy() { // Here we are trying to handle the following corner case: an application using the SDK @@ -97,6 +122,9 @@ public class JitsiMeetActivity extends AppCompatActivity // be operational so the external API won't be able to notify the native side that the // conference terminated. Thus, try our best to clean up. leave(); + + this.jitsiView = null; + if (AudioModeModule.useConnectionService()) { ConnectionService.abortConnections(); } @@ -104,6 +132,8 @@ public class JitsiMeetActivity extends AppCompatActivity LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver); + JitsiMeetActivityDelegate.onHostDestroy(this); + super.onDestroy(); } @@ -118,9 +148,7 @@ public class JitsiMeetActivity extends AppCompatActivity // protected JitsiMeetView getJitsiView() { - JitsiMeetFragment fragment - = (JitsiMeetFragment) getSupportFragmentManager().findFragmentById(R.id.jitsiFragment); - return fragment != null ? fragment.getJitsiView() : null; + return jitsiView; } public void join(@Nullable String url) { @@ -132,20 +160,16 @@ public class JitsiMeetActivity extends AppCompatActivity } public void join(JitsiMeetConferenceOptions options) { - JitsiMeetView view = getJitsiView(); - - if (view != null) { - view.join(options); + if (this.jitsiView != null) { + this.jitsiView .join(options); } else { JitsiMeetLogger.w("Cannot join, view is null"); } } public void leave() { - JitsiMeetView view = getJitsiView(); - - if (view != null) { - view.leave(); + if (this.jitsiView != null) { + this.jitsiView .leave(); } else { JitsiMeetLogger.w("Cannot leave, view is null"); } @@ -252,10 +276,8 @@ public class JitsiMeetActivity extends AppCompatActivity @Override protected void onUserLeaveHint() { - JitsiMeetView view = getJitsiView(); - - if (view != null) { - view.enterPictureInPicture(); + if (this.jitsiView != null) { + this.jitsiView .enterPictureInPicture(); } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetFragment.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetFragment.java index a8afdff86..c6dff7f72 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetFragment.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetFragment.java @@ -17,7 +17,6 @@ package org.jitsi.meet.sdk; -import android.content.Intent; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -37,7 +36,10 @@ import android.view.ViewGroup; * conference itself. All lifecycle methods associated with this Fragment are * hooked to the React Native subsystem via proxy calls through the * {@code JitsiMeetActivityDelegate} static methods. + * + * @deprecated use {@link JitsiMeetActivity} or directly {@link JitsiMeetView} */ +@Deprecated public class JitsiMeetFragment extends Fragment { /** diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java index c8b70d097..36a2fa0b1 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java @@ -18,6 +18,8 @@ package org.jitsi.meet.sdk; import android.content.Context; import android.os.Bundle; +import android.util.AttributeSet; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,7 +30,6 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger; import java.lang.reflect.Method; import java.util.Map; - public class JitsiMeetView extends BaseReactView implements OngoingConferenceTracker.OngoingConferenceListener { @@ -95,14 +96,17 @@ public class JitsiMeetView extends BaseReactView public JitsiMeetView(@NonNull Context context) { super(context); + initialize(context); + } - // Check if the parent Activity implements JitsiMeetActivityInterface, - // otherwise things may go wrong. - if (!(context instanceof JitsiMeetActivityInterface)) { - throw new RuntimeException("Enclosing Activity must implement JitsiMeetActivityInterface"); - } + public JitsiMeetView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } - OngoingConferenceTracker.getInstance().addListener(this); + public JitsiMeetView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(context); } @Override @@ -207,4 +211,14 @@ public class JitsiMeetView extends BaseReactView dispose(); super.onDetachedFromWindow(); } + + private void initialize(@NonNull Context context) { + // Check if the parent Activity implements JitsiMeetActivityInterface, + // otherwise things may go wrong. + if (!(context instanceof JitsiMeetActivityInterface)) { + throw new RuntimeException("Enclosing Activity must implement JitsiMeetActivityInterface"); + } + + OngoingConferenceTracker.getInstance().addListener(this); + } } diff --git a/android/sdk/src/main/res/layout/activity_jitsi_meet.xml b/android/sdk/src/main/res/layout/activity_jitsi_meet.xml index 46cf5d520..e2213b000 100644 --- a/android/sdk/src/main/res/layout/activity_jitsi_meet.xml +++ b/android/sdk/src/main/res/layout/activity_jitsi_meet.xml @@ -1,12 +1,13 @@ - + android:layout_height="match_parent" /> \ No newline at end of file