feat(android) set target SDK to 34 (#14129)

* feat(android) set target SDK to 34 and fixed mediaProjection service type
pull/14260/head jitsi-meet_9213
Saúl Ibarra Corretgé 1 year ago committed by GitHub
parent e00b6be06c
commit f8cef330f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 9
      android/app/build.gradle
  2. 1
      android/app/src/main/AndroidManifest.xml
  3. 6
      android/build.gradle
  4. 1
      android/sdk/build.gradle
  5. 11
      android/sdk/src/main/AndroidManifest.xml
  6. 42
      android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetMediaProjectionModule.java
  7. 100
      android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetMediaProjectionService.java
  8. 8
      android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java
  9. 8
      android/sdk/src/main/java/org/jitsi/meet/sdk/OngoingNotification.java
  10. 1
      android/sdk/src/main/java/org/jitsi/meet/sdk/ReactInstanceManagerHolder.java
  11. 1
      android/sdk/src/main/res/values/strings.xml
  12. 66
      package-lock.json
  13. 2
      package.json
  14. 9
      react/features/base/tracks/actions.native.ts
  15. 4
      react/features/shared-video/components/native/VideoManager.tsx

@ -15,11 +15,13 @@ def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
packagingOptions {
exclude 'lib/*/libhermes*.so'
jniLibs {
excludes += ['lib/*/libhermes*.so']
}
}
defaultConfig {
applicationId 'org.jitsi.meet'
versionCode vcode
@ -72,12 +74,13 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'org.jitsi.meet'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.13'
if (!rootProject.ext.libreBuild) {
// Sync with react-native-google-signin

@ -1,6 +1,5 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.meet"
android:installLocation="auto">
<application
android:allowBackup="true"

@ -10,7 +10,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
}
@ -19,9 +19,9 @@ buildscript {
ext {
kotlinVersion = "1.7.0"
buildToolsVersion = "33.0.2"
compileSdkVersion = 33
compileSdkVersion = 34
minSdkVersion = 24
targetSdkVersion = 33
targetSdkVersion = 34
supportLibVersion = "28.0.0"
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.

@ -30,6 +30,7 @@ android {
}
}
}
namespace 'org.jitsi.meet.sdk'
}
dependencies {

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.jitsi.meet.sdk">
xmlns:tools="http://schemas.android.com/tools">
<!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
@ -13,6 +12,8 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-feature
android:glEsVersion="0x00020000"
@ -48,6 +49,10 @@
<service
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
android:foregroundServiceType="mediaPlayback" />
<service
android:name="org.jitsi.meet.sdk.JitsiMeetMediaProjectionService"
android:foregroundServiceType="mediaProjection" />
<provider
@ -66,4 +71,4 @@
</application>
</manifest>
</manifest>

@ -0,0 +1,42 @@
package org.jitsi.meet.sdk;
import android.content.Context;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
@ReactModule(name = JitsiMeetMediaProjectionModule.NAME)
class JitsiMeetMediaProjectionModule
extends ReactContextBaseJavaModule {
public static final String NAME = "JitsiMeetMediaProjectionModule";
public JitsiMeetMediaProjectionModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
public void launch() {
Context context = getReactApplicationContext();
JitsiMeetMediaProjectionService.launch(context);
}
@ReactMethod
public void abort() {
Context context = getReactApplicationContext();
JitsiMeetMediaProjectionService.abort(context);
}
@NonNull
@Override
public String getName() {
return NAME;
}
}

@ -0,0 +1,100 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import android.app.Notification;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* This class implements an Android {@link Service}, a foreground one specifically, and it's
* responsible for presenting an ongoing notification when a conference is in progress.
* The service will help keep the app running while in the background.
*
* See: https://developer.android.com/guide/components/services
*/
public class JitsiMeetMediaProjectionService extends Service {
private static final String TAG = JitsiMeetMediaProjectionService.class.getSimpleName();
public static void launch(Context context) {
OngoingNotification.createOngoingConferenceNotificationChannel();
Intent intent = new Intent(context, JitsiMeetMediaProjectionService.class);
ComponentName componentName;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
componentName = context.startForegroundService(intent);
} else {
componentName = context.startService(intent);
}
} catch (RuntimeException e) {
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
JitsiMeetLogger.w(TAG + " Ongoing conference service not started", e);
return;
}
if (componentName == null) {
JitsiMeetLogger.w(TAG + " Ongoing conference service not started");
}
}
public static void abort(Context context) {
Intent intent = new Intent(context, JitsiMeetMediaProjectionService.class);
context.stopService(intent);
}
@Override
public void onCreate() {
super.onCreate();
Notification notification = OngoingNotification.buildOngoingConferenceNotification(null);
if (notification == null) {
stopSelf();
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(OngoingNotification.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
} else {
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
}

@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@ -94,8 +95,11 @@ public class JitsiMeetOngoingConferenceService extends Service
stopSelf();
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
} else {
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " Service started");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(OngoingNotification.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
} else {
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
}
}
OngoingConferenceTracker.getInstance().addListener(this);

@ -73,7 +73,7 @@ class OngoingNotification {
notificationManager.createNotificationChannel(channel);
}
static Notification buildOngoingConferenceNotification(boolean isMuted) {
static Notification buildOngoingConferenceNotification(Boolean isMuted) {
Context context = ReactInstanceManagerHolder.getCurrentActivity();
if (context == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
@ -92,7 +92,7 @@ class OngoingNotification {
builder
.setCategory(NotificationCompat.CATEGORY_CALL)
.setContentTitle(context.getString(R.string.ongoing_notification_title))
.setContentText(context.getString(R.string.ongoing_notification_text))
.setContentText(isMuted != null ? context.getString(R.string.ongoing_notification_text) : context.getString(R.string.ongoing_notification_action_screenshare))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setOngoing(true)
@ -103,6 +103,10 @@ class OngoingNotification {
.setOnlyAlertOnce(true)
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
if (isMuted == null) {
return builder.build();
}
NotificationCompat.Action hangupAction = createAction(context, JitsiMeetOngoingConferenceService.Action.HANGUP, R.string.ongoing_notification_action_hang_up);
JitsiMeetOngoingConferenceService.Action toggleAudioAction = isMuted

@ -67,6 +67,7 @@ class ReactInstanceManagerHolder {
new DropboxModule(reactContext),
new ExternalAPIModule(reactContext),
new JavaScriptSandboxModule(reactContext),
new JitsiMeetMediaProjectionModule(reactContext),
new LocaleDetector(reactContext),
new LogBridgeModule(reactContext),
new SplashScreenModule(reactContext),

@ -5,6 +5,7 @@
<string name="ongoing_notification_text">You are currently in a meeting. Tap to return to it.</string>
<string name="ongoing_notification_action_hang_up">Hang up</string>
<string name="ongoing_notification_action_mute">Mute</string>
<string name="ongoing_notification_action_screenshare">You are currently screen-sharing. Tap to return to the meeting.</string>
<string name="ongoing_notification_action_unmute">Unmute</string>
<string name="ongoing_notification_channel_name">Ongoing Conference Notifications</string>
</resources>

66
package-lock.json generated

@ -97,7 +97,7 @@
"react-native-svg-transformer": "1.1.0",
"react-native-tab-view": "3.5.2",
"react-native-url-polyfill": "2.0.0",
"react-native-video": "6.0.0-alpha.7",
"react-native-video": "6.0.0-alpha.11",
"react-native-watch-connectivity": "1.1.0",
"react-native-webrtc": "118.0.0",
"react-native-webview": "13.5.1",
@ -5574,11 +5574,6 @@
}
}
},
"node_modules/@react-native/normalize-color": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
},
"node_modules/@react-native/normalize-colors": {
"version": "0.72.0",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
@ -9335,16 +9330,6 @@
"node": ">= 0.6"
}
},
"node_modules/deprecated-react-native-prop-types": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
"integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
"dependencies": {
"@react-native/normalize-color": "*",
"invariant": "*",
"prop-types": "*"
}
},
"node_modules/destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@ -12872,11 +12857,6 @@
"rollup": ">= 1.0.0"
}
},
"node_modules/keymirror": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
"integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@ -16953,13 +16933,12 @@
}
},
"node_modules/react-native-video": {
"version": "6.0.0-alpha.7",
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.7.tgz",
"integrity": "sha512-X/siSaJf0V//IbnozjDm1jAjNaXlFy6Hbr6X8GNFl/ztLvN+Z8R/Quq9Q8o22XVwlPacPQ9VS/G0Stdktn0FEw==",
"dependencies": {
"deprecated-react-native-prop-types": "^2.2.0",
"keymirror": "^0.1.1",
"prop-types": "^15.7.2"
"version": "6.0.0-alpha.11",
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.11.tgz",
"integrity": "sha512-Z1FqIkNBqQWdBVKoh5WlmM01LIVhxlOsddKVV9IzMJ3EDl8PAU4ln7hdo85RHCHhgWSHzathPDo0UK7gPB48MA==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-watch-connectivity": {
@ -23970,11 +23949,6 @@
}
}
},
"@react-native/normalize-color": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
},
"@react-native/normalize-colors": {
"version": "0.72.0",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
@ -26841,16 +26815,6 @@
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"deprecated-react-native-prop-types": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
"integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
"requires": {
"@react-native/normalize-color": "*",
"invariant": "*",
"prop-types": "*"
}
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@ -29474,11 +29438,6 @@
"debounce": "^1.2.0"
}
},
"keymirror": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
"integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@ -32442,14 +32401,9 @@
}
},
"react-native-video": {
"version": "6.0.0-alpha.7",
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.7.tgz",
"integrity": "sha512-X/siSaJf0V//IbnozjDm1jAjNaXlFy6Hbr6X8GNFl/ztLvN+Z8R/Quq9Q8o22XVwlPacPQ9VS/G0Stdktn0FEw==",
"requires": {
"deprecated-react-native-prop-types": "^2.2.0",
"keymirror": "^0.1.1",
"prop-types": "^15.7.2"
}
"version": "6.0.0-alpha.11",
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.11.tgz",
"integrity": "sha512-Z1FqIkNBqQWdBVKoh5WlmM01LIVhxlOsddKVV9IzMJ3EDl8PAU4ln7hdo85RHCHhgWSHzathPDo0UK7gPB48MA=="
},
"react-native-watch-connectivity": {
"version": "1.1.0",

@ -103,7 +103,7 @@
"react-native-svg-transformer": "1.1.0",
"react-native-tab-view": "3.5.2",
"react-native-url-polyfill": "2.0.0",
"react-native-video": "6.0.0-alpha.7",
"react-native-video": "6.0.0-alpha.11",
"react-native-watch-connectivity": "1.1.0",
"react-native-webrtc": "118.0.0",
"react-native-webview": "13.5.1",

@ -1,3 +1,5 @@
import { NativeModules, Platform } from 'react-native';
import { IReduxState, IStore } from '../../app/types';
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
import { showNotification } from '../../notifications/actions';
@ -12,6 +14,8 @@ import { VIDEO_MUTISM_AUTHORITY } from '../media/constants';
import { addLocalTrack, replaceLocalTrack } from './actions.any';
import { getLocalDesktopTrack, getTrackState, isLocalVideoTrackDesktop } from './functions.native';
const { JitsiMeetMediaProjectionModule } = NativeModules;
export * from './actions.any';
/**
@ -31,7 +35,10 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
if (!isSharing) {
_startScreenSharing(dispatch, state);
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.launch();
}
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.abort();
} else {
dispatch(setScreenshareMuted(true));
dispatch(setVideoMuted(false, VIDEO_MUTISM_AUTHORITY.SCREEN_SHARE));
@ -77,7 +84,7 @@ async function _startScreenSharing(dispatch: IStore['dispatch'], state: IReduxSt
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}
} catch (error: any) {
console.log('ERROR creating ScreeSharing stream ', error);
console.log('ERROR creating screen-sharing stream ', error);
setPictureInPictureEnabled(true);
}

@ -19,7 +19,7 @@ interface IState {
* Manager of shared video.
*/
class VideoManager extends AbstractVideoManager<IState> {
playerRef: RefObject<Video>;
playerRef: RefObject<typeof Video>;
/**
* Initializes a new VideoManager instance.
@ -83,6 +83,8 @@ class VideoManager extends AbstractVideoManager<IState> {
*/
seek(time: number) {
if (this.player) {
// @ts-ignore
this.player.seek(time);
}
}

Loading…
Cancel
Save