Selaa lähdekoodia

android: add JitsiMeetActivity

It renders a single JitsiMeetFragment which holds the JitsiMeetView view.
master
Saúl Ibarra Corretgé 6 vuotta sitten
vanhempi
commit
bf3bcd65d6

+ 69
- 104
android/app/src/main/java/org/jitsi/meet/MainActivity.java Näytä tiedosto

@@ -20,34 +20,31 @@ package org.jitsi.meet;
20 20
 import android.content.Intent;
21 21
 import android.net.Uri;
22 22
 import android.os.Build;
23
-import android.os.Bundle;
24 23
 import android.provider.Settings;
25 24
 import android.support.annotation.Nullable;
26
-import android.support.v4.app.FragmentActivity;
25
+import android.util.Log;
27 26
 import android.view.KeyEvent;
28 27
 
29 28
 import org.jitsi.meet.sdk.JitsiMeet;
30
-import org.jitsi.meet.sdk.JitsiMeetActivityInterface;
31
-import org.jitsi.meet.sdk.JitsiMeetActivityDelegate;
32
-import org.jitsi.meet.sdk.JitsiMeetFragment;
29
+import org.jitsi.meet.sdk.JitsiMeetActivity;
33 30
 import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
34 31
 
35 32
 import com.crashlytics.android.Crashlytics;
36
-import com.facebook.react.modules.core.PermissionListener;
37 33
 import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
38 34
 import io.fabric.sdk.android.Fabric;
39 35
 
40 36
 import java.net.MalformedURLException;
41 37
 import java.net.URL;
38
+import java.util.Map;
42 39
 
43 40
 /**
44
- * The one and only {@link FragmentActivity} that the Jitsi Meet app needs. The
41
+ * The one and only Activity that the Jitsi Meet app needs. The
45 42
  * {@code Activity} is launched in {@code singleTask} mode, so it will be
46 43
  * created upon application initialization and there will be a single instance
47 44
  * of it. Further attempts at launching the application once it was already
48
- * launched will result in {@link FragmentActivity#onNewIntent(Intent)} being called.
45
+ * launched will result in {@link MainActivity#onNewIntent(Intent)} being called.
49 46
  */
50
-public class MainActivity extends FragmentActivity implements JitsiMeetActivityInterface {
47
+public class MainActivity extends JitsiMeetActivity {
51 48
     /**
52 49
      * The request code identifying requests for the permission to draw on top
53 50
      * of other apps. The value must be 16-bit and is arbitrarily chosen here.
@@ -55,19 +52,49 @@ public class MainActivity extends FragmentActivity implements JitsiMeetActivityI
55 52
     private static final int OVERLAY_PERMISSION_REQUEST_CODE
56 53
         = (int) (Math.random() * Short.MAX_VALUE);
57 54
 
58
-    private JitsiMeetFragment getFragment() {
59
-        return (JitsiMeetFragment) getSupportFragmentManager().findFragmentById(R.id.jitsiFragment);
60
-    }
55
+    // JitsiMeetActivity overrides
56
+    //
61 57
 
62
-    private @Nullable URL buildURL(String urlStr) {
63
-        try {
64
-            return new URL(urlStr);
65
-        } catch (MalformedURLException e) {
66
-            return null;
58
+    @Override
59
+    protected boolean extraInitialize() {
60
+        // Setup Crashlytics and Firebase Dynamic Links
61
+        if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
62
+            Fabric.with(this, new Crashlytics());
63
+
64
+            FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
65
+                .addOnSuccessListener(this, pendingDynamicLinkData -> {
66
+                    Uri dynamicLink = null;
67
+
68
+                    if (pendingDynamicLinkData != null) {
69
+                        dynamicLink = pendingDynamicLinkData.getLink();
70
+                    }
71
+
72
+                    if (dynamicLink != null) {
73
+                        join(dynamicLink.toString());
74
+                    }
75
+                });
76
+        }
77
+
78
+        // In Debug builds React needs permission to write over other apps in
79
+        // order to display the warning and error overlays.
80
+        if (BuildConfig.DEBUG) {
81
+            if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
82
+                Intent intent
83
+                    = new Intent(
84
+                    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
85
+                    Uri.parse("package:" + getPackageName()));
86
+
87
+                startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
88
+
89
+                return true;
90
+            }
67 91
         }
92
+
93
+        return false;
68 94
     }
69 95
 
70
-    private void initialize() {
96
+    @Override
97
+    protected void initialize() {
71 98
         // Set default options
72 99
         JitsiMeetConferenceOptions defaultOptions
73 100
             = new JitsiMeetConferenceOptions.Builder()
@@ -76,36 +103,27 @@ public class MainActivity extends FragmentActivity implements JitsiMeetActivityI
76 103
                 .build();
77 104
         JitsiMeet.setDefaultConferenceOptions(defaultOptions);
78 105
 
79
-        // Join the room specified by the URL the app was launched with.
80
-        // Joining without the room option displays the welcome page.
81
-        join(getIntentUrl(getIntent()));
106
+        super.initialize();
82 107
     }
83 108
 
84
-    private void join(@Nullable String url) {
85
-        JitsiMeetConferenceOptions options
86
-            = new JitsiMeetConferenceOptions.Builder()
87
-                .setRoom(url)
88
-                .build();
89
-        getFragment().getJitsiView().join(options);
109
+    @Override
110
+    public void onConferenceFailed(Map<String, Object> data) {
111
+        Log.d(TAG, "Conference failed: " + data);
90 112
     }
91 113
 
92
-    private @Nullable String getIntentUrl(Intent intent) {
93
-        Uri uri;
94
-
95
-        if (Intent.ACTION_VIEW.equals(intent.getAction())
96
-                && (uri = intent.getData()) != null) {
97
-            return uri.toString();
98
-        }
99
-
100
-        return null;
114
+    @Override
115
+    public void onConferenceLeft(Map<String, Object> data) {
116
+        Log.d(TAG, "Conference left: " + data);
101 117
     }
102 118
 
103
-    private boolean canRequestOverlayPermission() {
104
-        return
105
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
106
-                && getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
119
+    @Override
120
+    public void onLoadConfigError(Map<String, Object> data) {
121
+        Log.d(TAG, "Error loading config: " + data);
107 122
     }
108 123
 
124
+    // Activity lifecycle method overrides
125
+    //
126
+
109 127
     @Override
110 128
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
111 129
         if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
@@ -120,11 +138,6 @@ public class MainActivity extends FragmentActivity implements JitsiMeetActivityI
120 138
         super.onActivityResult(requestCode, resultCode, data);
121 139
     }
122 140
 
123
-    @Override
124
-    public void onBackPressed() {
125
-        JitsiMeetActivityDelegate.onBackPressed();
126
-    }
127
-
128 141
     // ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
129 142
     @Override
130 143
     public boolean onKeyUp(int keyCode, KeyEvent event) {
@@ -136,68 +149,20 @@ public class MainActivity extends FragmentActivity implements JitsiMeetActivityI
136 149
         return super.onKeyUp(keyCode, event);
137 150
     }
138 151
 
139
-    @Override
140
-    public void onNewIntent(Intent intent) {
141
-        String url;
142
-
143
-        if ((url = getIntentUrl(intent)) != null) {
144
-            join(url);
145
-            return;
146
-        }
147
-
148
-        JitsiMeetActivityDelegate.onNewIntent(intent);
149
-    }
150
-
151
-    @Override
152
-    protected void onUserLeaveHint() {
153
-        getFragment().getJitsiView().enterPictureInPicture();
154
-    }
155
-
156
-    @Override
157
-    protected void onCreate(Bundle savedInstanceState) {
158
-        super.onCreate(savedInstanceState);
159
-
160
-        // Set the Activity's content view.
161
-        setContentView(R.layout.main_layout);
162
-
163
-        // Setup Crashlytics and Firebase Dynamic Links
164
-        if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
165
-            Fabric.with(this, new Crashlytics());
166
-
167
-            FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
168
-                .addOnSuccessListener(this, pendingDynamicLinkData -> {
169
-                    Uri dynamicLink = null;
170
-
171
-                    if (pendingDynamicLinkData != null) {
172
-                        dynamicLink = pendingDynamicLinkData.getLink();
173
-                    }
174
-
175
-                    if (dynamicLink != null) {
176
-                        join(dynamicLink.toString());
177
-                    }
178
-                });
179
-        }
152
+    // Helper methods
153
+    //
180 154
 
181
-        // In Debug builds React needs permission to write over other apps in
182
-        // order to display the warning and error overlays.
183
-        if (BuildConfig.DEBUG) {
184
-            if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
185
-                Intent intent
186
-                    = new Intent(
187
-                        Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
188
-                        Uri.parse("package:" + getPackageName()));
189
-
190
-                startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
191
-                return;
192
-            }
155
+    private @Nullable URL buildURL(String urlStr) {
156
+        try {
157
+            return new URL(urlStr);
158
+        } catch (MalformedURLException e) {
159
+            return null;
193 160
         }
194
-
195
-        initialize();
196 161
     }
197 162
 
198
-    @Override
199
-    public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) {
200
-        JitsiMeetActivityDelegate.requestPermissions(this, permissions, requestCode, listener);
163
+    private boolean canRequestOverlayPermission() {
164
+        return
165
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
166
+                && getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
201 167
     }
202
-
203 168
 }

+ 39
- 34
android/sdk/src/main/AndroidManifest.xml Näytä tiedosto

@@ -1,37 +1,42 @@
1
-<manifest
2
-    xmlns:android="http://schemas.android.com/apk/res/android"
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 3
     package="org.jitsi.meet.sdk">
4
-  <!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
5
-  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6
-  <uses-permission android:name="android.permission.BLUETOOTH" />
7
-  <uses-permission android:name="android.permission.CAMERA" />
8
-  <uses-permission android:name="android.permission.INTERNET" />
9
-  <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
10
-  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
11
-  <uses-permission android:name="android.permission.RECORD_AUDIO" />
12
-  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
13
-  <uses-permission android:name="android.permission.WAKE_LOCK" />
14
-  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
4
+    <!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
5
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6
+    <uses-permission android:name="android.permission.BLUETOOTH" />
7
+    <uses-permission android:name="android.permission.CAMERA" />
8
+    <uses-permission android:name="android.permission.INTERNET" />
9
+    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
10
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
11
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
12
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
13
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
14
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
15 15
 
16
-  <uses-feature android:glEsVersion="0x00020000" android:required="true" />
17
-  <uses-feature
18
-      android:name="android.hardware.camera"
19
-      android:required="false" />
20
-  <uses-feature
21
-      android:name="android.hardware.camera.autofocus"
22
-      android:required="false" />
16
+    <uses-feature
17
+        android:glEsVersion="0x00020000"
18
+        android:required="true" />
19
+    <uses-feature
20
+        android:name="android.hardware.camera"
21
+        android:required="false" />
22
+    <uses-feature
23
+        android:name="android.hardware.camera.autofocus"
24
+        android:required="false" />
23 25
 
24
-  <application
25
-      android:allowBackup="true"
26
-      android:label="@string/app_name"
27
-      android:supportsRtl="true">
28
-    <activity
29
-        android:name="com.facebook.react.devsupport.DevSettingsActivity" />
30
-    <service android:name="org.jitsi.meet.sdk.ConnectionService"
31
-        android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
32
-      <intent-filter>
33
-        <action android:name="android.telecom.ConnectionService" />
34
-      </intent-filter>
35
-    </service>
36
-  </application>
37
-</manifest>
26
+    <application
27
+        android:allowBackup="true"
28
+        android:label="@string/app_name"
29
+        android:supportsRtl="true">
30
+        <activity android:name=".JitsiMeetActivity"></activity>
31
+        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
32
+
33
+        <service
34
+            android:name=".ConnectionService"
35
+            android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
36
+            <intent-filter>
37
+                <action android:name="android.telecom.ConnectionService" />
38
+            </intent-filter>
39
+        </service>
40
+    </application>
41
+
42
+</manifest>

+ 189
- 0
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java Näytä tiedosto

@@ -0,0 +1,189 @@
1
+/*
2
+ * Copyright @ 2019-present 8x8, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+package org.jitsi.meet.sdk;
18
+
19
+import android.content.Intent;
20
+import android.net.Uri;
21
+import android.os.Bundle;
22
+import android.support.annotation.Nullable;
23
+import android.support.v4.app.FragmentActivity;
24
+import android.util.Log;
25
+
26
+import com.facebook.react.modules.core.PermissionListener;
27
+
28
+import java.util.Map;
29
+
30
+
31
+/**
32
+ * A base activity for SDK users to embed. It uses {@link JitsiMeetFragment} to do the heavy
33
+ * lifting and wires the remaining Activity lifecycle methods so it works out of the box.
34
+ */
35
+public class JitsiMeetActivity extends FragmentActivity
36
+        implements JitsiMeetActivityInterface, JitsiMeetViewListener {
37
+
38
+    protected static final String TAG = JitsiMeetActivity.class.getSimpleName();
39
+
40
+    // Overrides
41
+    //
42
+
43
+    @Override
44
+    protected void onCreate(Bundle savedInstanceState) {
45
+        super.onCreate(savedInstanceState);
46
+
47
+        setContentView(R.layout.activity_jitsi_meet);
48
+
49
+        if (!extraInitialize()) {
50
+            initialize();
51
+        }
52
+    }
53
+
54
+    @Override
55
+    public void finish() {
56
+        getJitsiView().leave();
57
+
58
+        super.finish();
59
+    }
60
+
61
+    // Helper methods
62
+    //
63
+
64
+    protected JitsiMeetView getJitsiView() {
65
+        JitsiMeetFragment fragment
66
+            = (JitsiMeetFragment) getSupportFragmentManager().findFragmentById(R.id.jitsiFragment);
67
+        return fragment.getJitsiView();
68
+    }
69
+
70
+    protected void join(@Nullable String url) {
71
+        JitsiMeetConferenceOptions options
72
+            = new JitsiMeetConferenceOptions.Builder()
73
+                .setRoom(url)
74
+                .build();
75
+        join(options);
76
+    }
77
+
78
+    protected void join(JitsiMeetConferenceOptions options) {
79
+        getJitsiView().join(options);
80
+    }
81
+
82
+    private @Nullable JitsiMeetConferenceOptions getConferenceOptions(Intent intent) {
83
+        Uri uri;
84
+
85
+        if (Intent.ACTION_VIEW.equals(intent.getAction())
86
+                && (uri = intent.getData()) != null) {
87
+            JitsiMeetConferenceOptions options
88
+                = new JitsiMeetConferenceOptions.Builder()
89
+                    .setRoom(uri.toString())
90
+                    .build();
91
+            return options;
92
+        }
93
+
94
+        // TODO: accept JitsiMeetConferenceOptions directly.
95
+
96
+        return null;
97
+    }
98
+
99
+    /**
100
+     * Helper function called during activity initialization. If {@code true} is returned, the
101
+     * initialization is delayed and the {@link JitsiMeetActivity#initialize()} method is not
102
+     * called. In this case, it's up to the subclass to call the initialize method when ready.
103
+     *
104
+     * This is mainly required so we do some extra initialization in the Jitsi Meet app.
105
+     *
106
+     * @return {@code true} if the initialization will be delayed, {@code false} otherwise.
107
+     */
108
+    protected boolean extraInitialize() {
109
+        return false;
110
+    }
111
+
112
+    protected void initialize() {
113
+        // Listen for conference events.
114
+        getJitsiView().setListener(this);
115
+
116
+        // Join the room specified by the URL the app was launched with.
117
+        // Joining without the room option displays the welcome page.
118
+        join(getConferenceOptions(getIntent()));
119
+    }
120
+
121
+    // Activity lifecycle methods
122
+    //
123
+
124
+    @Override
125
+    public void onBackPressed() {
126
+        JitsiMeetActivityDelegate.onBackPressed();
127
+    }
128
+
129
+    @Override
130
+    public void onNewIntent(Intent intent) {
131
+        JitsiMeetConferenceOptions options;
132
+
133
+        if ((options = getConferenceOptions(intent)) != null) {
134
+            join(options);
135
+            return;
136
+        }
137
+
138
+        JitsiMeetActivityDelegate.onNewIntent(intent);
139
+    }
140
+
141
+    @Override
142
+    protected void onUserLeaveHint() {
143
+        getJitsiView().enterPictureInPicture();
144
+    }
145
+
146
+    // JitsiMeetActivityInterface
147
+    //
148
+
149
+    @Override
150
+    public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) {
151
+        JitsiMeetActivityDelegate.requestPermissions(this, permissions, requestCode, listener);
152
+    }
153
+
154
+    // JitsiMeetViewListener
155
+    //
156
+
157
+    @Override
158
+    public void onConferenceFailed(Map<String, Object> data) {
159
+        Log.d(TAG, "Conference failed: " + data);
160
+        finish();
161
+    }
162
+
163
+    @Override
164
+    public void onConferenceJoined(Map<String, Object> data) {
165
+        Log.d(TAG, "Conference joined: " + data);
166
+    }
167
+
168
+    @Override
169
+    public void onConferenceLeft(Map<String, Object> data) {
170
+        Log.d(TAG, "Conference left: " + data);
171
+        finish();
172
+    }
173
+
174
+    @Override
175
+    public void onConferenceWillJoin(Map<String, Object> data) {
176
+        Log.d(TAG, "Conference will join: " + data);
177
+    }
178
+
179
+    @Override
180
+    public void onConferenceWillLeave(Map<String, Object> data) {
181
+        Log.d(TAG, "Conference will leave: " + data);
182
+    }
183
+
184
+    @Override
185
+    public void onLoadConfigError(Map<String, Object> data) {
186
+        Log.d(TAG, "Error loading config: " + data);
187
+        finish();
188
+    }
189
+}

android/app/src/main/res/layout/main_layout.xml → android/sdk/src/main/res/layout/activity_jitsi_meet.xml Näytä tiedosto

@@ -1,10 +1,12 @@
1 1
 <?xml version="1.0" encoding="utf-8"?>
2 2
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:tools="http://schemas.android.com/tools"
3 4
     android:layout_width="match_parent"
4
-    android:layout_height="match_parent">
5
+    android:layout_height="match_parent"
6
+    tools:context=".JitsiMeetActivity">
5 7
     <fragment
6 8
         android:layout_width="match_parent"
7 9
         android:layout_height="match_parent"
8 10
         android:name="org.jitsi.meet.sdk.JitsiMeetFragment"
9 11
         android:id="@+id/jitsiFragment"/>
10
-</FrameLayout>
12
+</FrameLayout>

Loading…
Peruuta
Tallenna