Compare commits

...

974 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
fbdd1d2f38 settings: fix loading disableCallIntegration 2019-11-08 12:22:41 +01:00
Saúl Ibarra Corretgé
53ebab33b3 android: fix selecting the Bluetooth route
Samsung devices (of course) seem to stick with the earpiece if we first select
Bluetooth but then set speaker to false. Reverse the order to make everyone
happy.

This only applies to the generic and legacy handlers.
2019-11-08 12:22:41 +01:00
Saúl Ibarra Corretgé
a36965e908 android: fix initializing audio device handler modules too early
When ConnectionService is used (the default) we were attaching the handlers too
early, and since attaching them requires that the RNConnectionService module is
loaded, it silently failed. Instead, use the initialize() method, which gets
called after all the Catalyst (aka native) modules have been loaded.
2019-11-08 12:22:41 +01:00
Saúl Ibarra Corretgé
9bf859ee50 android: log a warning if listeners could not be attached 2019-11-08 12:22:41 +01:00
Saúl Ibarra Corretgé
24ff6f58a5 android: make code a bit more readable 2019-11-08 12:22:41 +01:00
Saúl Ibarra Corretgé
6338624095 android,hack: send custom UA to fool spartan nginx config on meet.jit.si 2019-11-07 15:28:04 +01:00
Saúl Ibarra Corretgé
9634d58d4e Merge branch 'master' into mobile-19.4 2019-11-07 08:40:06 +01:00
Saúl Ibarra Corretgé
ad0064993d ios: enable Swift mobule stability for the SDK target
Supersedes: https://github.com/jitsi/jitsi-meet/pull/4818
Fixes: https://github.com/jitsi/jitsi-meet/issues/4812
2019-11-06 18:30:26 +01:00
Saúl Ibarra Corretgé
458d4acd22 ios: use the "new" Xcode build system
It was introduced in Xcode 9 and made the default in Xcode 10. We were forcing
the use of the legacy version, which doesn't support some new features that we
wish to enable, such as building the SDK for distribution.
2019-11-06 18:30:26 +01:00
Saúl Ibarra Corretgé
8ebc99175c ios: set deployment target on Pods to 10.0
Matches the app / SDK deployment target and avoids compilation warnings.
2019-11-06 18:30:26 +01:00
Vlad Piersec
9889cb2b69 Add conference name as fallback for subject 2019-11-06 17:23:18 +01:00
Saúl Ibarra Corretgé
95a6f1355f uri: avoid using String.prototype.normalize
It crashes on Android. Well, on the JSC version React Native uses on Android.

While we could use this fallback only on Android, we have decided to use it
on all mobile platforms for consistency.
2019-11-06 15:37:52 +01:00
Saúl Ibarra Corretgé
191e530071 uri: avoid using String.prototype.normalize
It crashes on Android. Well, on the JSC version React Native uses on Android.

While we could use this fallback only on Android, we have decided to use it
on all mobile platforms for consistency.
2019-11-06 15:37:14 +01:00
Mihai Uscat
ae30d39b4d feat(PromotionalFooter): Implement 2019-11-06 03:29:49 -08:00
Leonard Kim
c354e46846 chore(deps): update lib so newer FF does not need click for gum 2019-11-06 07:47:14 +00:00
Hristo Terezov
5da4e43e50 fix(settings): respect configWhitelist 2019-11-05 02:13:54 -08:00
Hristo Terezov
eae6f7760f fix(configWhitelist): add startWithAudioMuted. 2019-11-05 02:13:54 -08:00
Mihai Uscat
00161212c8 feat(welcome): Add responsive text to go button 2019-11-04 05:48:55 -08:00
Mark Anthony Sison
8976b92842 doc(install): adds cd command to jitsi-meet installation 2019-11-03 19:46:34 +00:00
Vlad Piersec
c3a6a8fb17 Add participants count 2019-10-31 09:08:59 -07:00
Saúl Ibarra Corretgé
fd3fb7ef55 Merge branch 'master' into mobile-19.4 2019-10-31 16:45:37 +01:00
Saúl Ibarra Corretgé
391e5ca483 deps: react-native@0.61.3 2019-10-31 16:44:31 +01:00
Saúl Ibarra Corretgé
36654cb808 rn: disable H.264 on select devices even when not in P2P
iOS 10 crashes, so don't use it there, in any case.
2019-10-31 16:41:08 +01:00
Saúl Ibarra Corretgé
6d16e087d9 rn: add a new advanced settings section
Currently only 2 options are implemented, mainly aimed at helping troubleshoot
audio related problems:

- Disable native call integration (it disables CallKit / ConnectionService)
- Disable P2P
2019-10-31 16:41:08 +01:00
Saúl Ibarra Corretgé
fe90e5aa8f rn,settings: remove top margin 2019-10-31 16:41:08 +01:00
Saúl Ibarra Corretgé
3c22cd8ef4 rn,android: refactor audio device handling module
Separate each implementation (3 as of this writing) into each own "handler"
class.

This should make the code easier to understand, maintain and extend.
2019-10-31 16:41:08 +01:00
Bettenbuk Zoltan
5429b8568e feat: feature flag for invite functionalities 2019-10-29 11:27:25 +01:00
George Politis
0eccaf9a21 bumps ljm@5521a40aa85cb6f128f8a6dad9b72a5646132484 (#4791) 2019-10-24 14:52:38 +02:00
Aaron van Meerten
be0950c1ec multidomain mapper functionality and examples (#4773)
* first pass at mod_muc_domain open source plus example

* doc - prosody config and config.js examples for mapper
2019-10-24 12:42:11 +01:00
drimovecz
6ecd150f75 Add context user on speaker stats 2019-10-23 09:24:43 +01:00
Mihai Uscat
02fb37189b fix(welcome): Add extra variables 2019-10-22 13:24:44 -07:00
Jaya Allamsetty
8fe2536996 Update LJM for taking the changes for capScreenshareBitrate 2019-10-22 13:28:14 -05:00
Paweł Domas
4b9e156c5d Generic iOS .ipa build script (#4775) 2019-10-22 12:45:28 -05:00
Bettenbuk Zoltan
9265e1ffec ui: web chat facelift 2019-10-22 13:16:00 +02:00
Bettenbuk Zoltan
d11735b04c feat: make the hangup button first 2019-10-21 19:00:12 +02:00
Saúl Ibarra Corretgé
d33b700477 rn,blank-page: refactor BlankPage
- Remove network-activity "feature"
    - It wasn't in use
    - It relied on internal React Native components, bound to break anytime
- Show an infinite loading indicator
- Style it just like the LoadConfigOverlay
    - Since it kinda represents the opposite, an "unload" then SDK is done
2019-10-21 11:17:56 +02:00
Saúl Ibarra Corretgé
6909c6a0f4 android: fix SDK release script for new dependency syntax
Skip the first character, since it's now like ^123456.0.0
2019-10-21 11:13:13 +02:00
Saúl Ibarra Corretgé
97d75c2cb9 android: fix SDK release script for new dependency syntax
Skip the first character, since it's now like ^123456.0.0
2019-10-21 11:12:26 +02:00
Saúl Ibarra Corretgé
287115f4c3 deps: react-native-webrtc@latest
Fixes a crash on iOS when disposing streams.
2019-10-18 14:05:18 +02:00
Saúl Ibarra Corretgé
63a221212b ios: add ability to manually toggle WebRTC logging 2019-10-18 14:05:18 +02:00
Bettenbuk Zoltan
6a916fd0e1 fix: fix filmstrip-only toolbar 2019-10-18 13:16:15 +02:00
yanas
220691d61d Merge pull request #4762 from jitsi/fix-etherpad-follow-me
Fixes showing etherpad in follow-me mode.
2019-10-17 13:44:10 +01:00
damencho
5cafc4bcbd Fixes showing etherpad in follow-me mode. 2019-10-17 13:39:01 +01:00
yanas
b3a78dc2e6 Merge pull request #4761 from zbettenbuk/aot-icons
fix: fix and refactor AoT css
2019-10-17 12:34:13 +01:00
Bettenbuk Zoltan
bebc6eabe5 fix: fix and refactor AoT css 2019-10-17 12:15:29 +02:00
paweldomas
26dc6a4ac2 update logger and LJM to support log timestamps 2019-10-16 15:59:58 -05:00
Hristo Terezov
ff2626723a fix(HelpButton): Improvements. 2019-10-16 13:34:43 -07:00
Mihai Uscat
72bb897269 feat(DownloadOverflowButton): Implement. 2019-10-16 11:30:06 -07:00
damencho
f46387a226 Adds room name validation logic for web. 2019-10-16 17:52:24 +01:00
damencho
a4cbbccb2a Fixes loading recent lists on wrong meeting name stored.
decodeURIComponent is not needed any more and after adding a validation such meeting name should not happen to be stored.
2019-10-16 17:52:24 +01:00
damencho
3e1a008399 Adds copy icon next to the meeting url in info dialog. 2019-10-16 17:52:24 +01:00
Bettenbuk Zoltan
7e70a8c1de feat: make mobile chat messages selectable 2019-10-16 16:05:10 +02:00
Hristo Terezov
8efee04a10 feat(package.json): Node 12 support. 2019-10-16 06:34:44 -07:00
Bettenbuk Zoltan
a35099f949 feat: add chat color scheming 2019-10-16 10:38:28 +02:00
Mihai Uscat
8be02f9ca1 Implement review changes 2019-10-15 06:54:54 -07:00
Mihai Uscat
3c25a4c08c Naming conventions; Add variables 2019-10-15 06:54:54 -07:00
Mihai Uscat
5ade0cad8b feat(welcome): add posibility to extend settings toolbar 2019-10-15 06:54:54 -07:00
Saúl Ibarra Corretgé
0fa6ffc439 deps: react-native-google-signin@3.0.1 2019-10-14 19:12:45 +02:00
Saúl Ibarra Corretgé
c2ed296178 android: make check more resilient
If action is null (observed on some old devices) we'll get an exception.
Reversing the check fixes it since Actions.XXX is statically defined.
2019-10-14 17:45:43 +02:00
Saúl Ibarra Corretgé
febd12b871 ci: use Xcode 11.1 on Travis 2019-10-14 16:47:07 +02:00
Hristo Terezov
0a06e256b7 feat(HelpButton): Mobile support. 2019-10-14 07:35:39 -07:00
Hristo Terezov
f295f60bea feat(HelpOverflowButton): Implement. 2019-10-14 07:35:39 -07:00
Saúl Ibarra Corretgé
4a8f787519 rn: evaluate config.js in a sandboxed environment
We are downloading code off the Internet and executing it on the user's device,
so run it sandboxed to avoid potential bad actors.

Since it's impossible to eval() safely in JS and React Native doesn't offer
something akin to Node's vm module, here we are rolling our own.

On Android it uses the Duktape JavaScript engine and on iOS the builtin
JavaScriptCore engine. The extra JS engine is *only* used for evaluating the
downloaded code and returning a JSON string which is then passed back to RN.
2019-10-14 12:20:58 +02:00
Saúl Ibarra Corretgé
d85b869934 rn: skip loading configured scriptUrls
None of them work on mobile.
2019-10-14 12:20:58 +02:00
Saúl Ibarra Corretgé
35130f0736 rn: refactor loadScript
- use AbortController for setting the fetch timeout
- use async / await syntax for clarify
- set the default timeout to 5s (previously non-existent, aka 0)
- add ability to load but not evaluate a script
2019-10-14 12:20:58 +02:00
Saúl Ibarra Corretgé
1feff9709c config: drop configLocation and getroomnode options
They never worked on mobile and pose an impediment for makinf config.js more
future proof. Specially if we want to move to a non-executable form of
configuration.
2019-10-14 12:20:58 +02:00
Leonard Kim
1010f53a84 fix(config): add whitelisting for interface config
For now all keys are whitelisted.
2019-10-11 09:38:56 -07:00
Saúl Ibarra Corretgé
f7a526f488 rn: fix rendering unnecessary stuff when in PiP mode 2019-10-11 17:17:53 +02:00
Bettenbuk Zoltan
245eb89b85 fix BottomSheet shaking 2019-10-11 15:14:51 +02:00
Hristo Terezov
99de9d0bfa fix(remoteVideo): Attaching video stream. 2019-10-11 04:58:01 -07:00
Saúl Ibarra Corretgé
98698ba89a etherpad: refactor to share code with mobile
- simplify initialization procedure
- set user display name as the Etherpad name\
- use SharedDocumentButton
2019-10-10 11:19:38 +02:00
Saúl Ibarra Corretgé
19d1e3829d rn: add shared document support using Etherpad 2019-10-10 11:19:38 +02:00
Saúl Ibarra Corretgé
612586ed1f deps: react-native-webview@7.4.1 2019-10-10 11:19:38 +02:00
Saúl Ibarra Corretgé
2609e43f29 ios: misc Xcode changes due to an update 2019-10-10 11:19:38 +02:00
Saúl Ibarra Corretgé
c5cd4f534c dial-in-summary: center the loading indicator 2019-10-10 11:19:38 +02:00
Bettenbuk Zoltan
6e10ca5dd2 fix: chat error message 2019-10-09 18:35:09 +02:00
Bettenbuk Zoltan
0fff1c3534 ref: serve makefile libs locally 2019-10-09 11:56:06 +02:00
Bettenbuk Zoltan
42271b1b89 feat: private messages 2019-10-08 18:22:45 +02:00
Bettenbuk Zoltan
f270b50972 fix: remove unnecessary escaping 2019-10-08 18:22:45 +02:00
Saúl Ibarra Corretgé
ab4b6be9d7 rn: throw exception if default conference options set the room
See: https://github.com/jitsi/jitsi-meet/issues/4720
2019-10-08 14:31:13 +02:00
Saúl Ibarra Corretgé
c45ee0230f android: add getters to JitsiMeetConferenceOptions 2019-10-08 14:31:13 +02:00
George Politis
d210f2f2e7 Adds a noAutoPlayVideo configuration option (used in testing). (#4714)
This adds an option to disable video autoplay that will be used mostly with maleus (our selenium-based load testing tool for testing the new bridge). Disabling video rendering lowers the resource utilisation of the selenium nodes.
2019-10-08 11:34:25 +02:00
Bettenbuk Zoltan
13d78d6b49 fix: utf-8 room name case sensitivity 2019-10-08 10:35:19 +02:00
damencho
34a71042c6 Enables Hungarian translation. 2019-10-05 00:11:25 +01:00
damencho
47ecf7d035 Commit from translate.jitsi.org by user damencho.: 601 of 601 strings translated (0 fuzzy). 2019-10-04 23:15:36 +00:00
damencho
bbe8c52778 Commit from translate.jitsi.org by user damencho.: 600 of 601 strings translated (1 fuzzy). 2019-10-04 23:15:24 +00:00
damencho
2011421e9d Commit from translate.jitsi.org by user damencho.: 582 of 601 strings translated (3 fuzzy). 2019-10-04 23:15:08 +00:00
damencho
ce55952ca9 Commit from translate.jitsi.org by user damencho.: 524 of 601 strings translated (5 fuzzy). 2019-10-04 23:14:58 +00:00
damencho
f93482e815 Commit from translate.jitsi.org by user damencho.: 582 of 601 strings translated (0 fuzzy). 2019-10-04 23:14:45 +00:00
Andrei Gavrilescu
761ac6a730 feat: integrate rnnoise based service for voice activity (VAD) detection 2019-10-04 12:55:18 +02:00
Djorkaeff Alexandre
11d3a343e5 ios: use iPhone 8 simulator when archiving JitsiMeet framework
It's available on both Xcode 10 and 11.
2019-10-04 11:00:31 +02:00
Saúl Ibarra Corretgé
9666bf836e ios: update CocoaPods to version 1.8 2019-10-04 11:00:31 +02:00
Saúl Ibarra Corretgé
a6d3b09796 ios: support building with Xcode 11 2019-10-04 11:00:31 +02:00
Дамян Минков
bb0036fdab Adds notifications for who stop/start recording/live streaming. (#4708)
* Adds notifications for who stop/start recording/live streaming.

* Updates to latest lib-jitsi-meet.
2019-10-03 20:35:21 +01:00
paweldomas
8dc0f30a49 ref(NAT64AddrInfoModule): use 'ipv4only.arpa' well known host
defined in RFC7050 instead of 'nat64.jitsi.net' as suggested by
Jonathan Lennox.
2019-10-02 10:49:39 -05:00
Saúl Ibarra Corretgé
1aed08f460 deps: react-native-webrtc@latest
Fixes iOS crashes when restarting the AudioUnit in case of interruption.
2019-10-02 14:44:15 +02:00
Saúl Ibarra Corretgé
afccf6f06d rn: disable H.264 on iOS 10 devices
It crashes like hell. See:
https://bugs.chromium.org/p/webrtc/issues/detail?id=11002
2019-10-02 14:10:37 +02:00
damencho
5cd351a46f Updates rayo filter to add user token info to dial messages.
Adds option to limit number of outgoing calls per user.
2019-09-30 16:53:38 +01:00
damencho
51f257e894 chore(deps): update LJM to 3f7613748d7669cd3fd031bbdf9069e4309f6f56 2019-09-30 11:53:30 +01:00
Saúl Ibarra Corretgé
ac06892bb4 android,ios: now working on versions 19.4 / 2.4 2019-09-26 17:33:52 +02:00
Saúl Ibarra Corretgé
fd8473cb52 deps: react-native-webrtc@latest
Avoid Android crashes.
2019-09-26 17:33:52 +02:00
damencho
3f40257f89 chore(deps): update LJM to a61941fc9a1927daedc1c9446e4036702964b38a
Uses sendBeacon to send xmpp presence unavailable on unloading the window(leaving the conference).
2019-09-26 16:20:57 +01:00
paweldomas
14509adff2 chore(deps): update LJM to dda16f607ed190a0664d643d511cc87f9bfceaf1
It was referencing LJM from a PR branch instead of the master.
2019-09-25 16:57:06 -05:00
Bettenbuk Zoltan
c472537ecf update RN to 61 2019-09-25 17:31:52 +02:00
Jaya Allamsetty
d40fce741a Fix the WebGL memory leak for Blur effect in Chrome 77 and up (#4652) 2019-09-24 06:50:10 -07:00
Saúl Ibarra Corretgé
944e8f8353 android: fix NPE when handling onHostPause
If the Activity is put into the background before the ReactContext is created we
get an NPE here. While the window might be short, it's thechnically possible to
hit this, as our Crashlytics reports show.
2019-09-24 09:49:52 +02:00
Saúl Ibarra Corretgé
7d972a50f2 ios: set logger subsystem and category
The subsystem is set to the bundle ID and the category to "JitsiMeetSDK".
2019-09-24 09:49:33 +02:00
Leonard Kim
92e7be34e3 fix(icons): scope white svgs to Icon components 2019-09-20 07:50:41 -07:00
Bettenbuk Zoltan
f5dba929a5 fix: add support for functional component type icons 2019-09-20 16:35:56 +02:00
Saúl Ibarra Corretgé
64d2885233 android: raise SDK version 2019-09-20 10:25:42 +02:00
Saúl Ibarra Corretgé
4ce65ae7a7 android: make reportConnectedOutgoingCall return a Promise
The call-integration middleware relies on it returning it, as iOS does.
2019-09-20 10:25:42 +02:00
Saúl Ibarra Corretgé
07bf95f838 doc: add info on reporting security issues 2019-09-19 13:49:46 +02:00
Saúl Ibarra Corretgé
3469d5dc4f doc: move development sections to standalone file 2019-09-19 13:49:46 +02:00
Leonard Kim
8c0f942ae1 add more logging around attaching videos to thumbnails 2019-09-19 10:46:36 +02:00
Leonard Kim
b8aa74f212 fix(large-video): bring back workaround for selecting on conference join
Bring back the workaround introduced in afd2aea7
but removed in 21dcc41d. On conference join,
several other actions have already been fired
that try to set the large video participant
and select the participant on the bridge.
The problem is there is no conference during
these actions so the select participant
never fires. Then subsequent actions do not
fire select participant because the large
video participant has not changed.
2019-09-18 15:00:13 -07:00
George Politis
2a7c6681ad ref: Changes how isVideoPlayable is computed.
This commit changes how the SmallVideo.isVideoPlayable method works.

1st we remove the check on the video stream muted field (materialized with the
!this.videoStream.isMuted() guard). This check is redundant as it is
already materialized in the !this.isVideoMuted check (the isVideoMuted
field is updated with the return value of the videoStream.isMuted()
method).

2nd we return false if we're in audio only mode, because it's
(obviously) undesirable to have a playable video when in audio only
mode.
2019-09-17 18:18:44 +02:00
George Politis
324a9eba91 minor change in debug log wording 2019-09-17 18:18:44 +02:00
George Politis
fb1ed22c6c ref: Tweak logging logic for thumbnail display mode and tile view. 2019-09-17 18:18:44 +02:00
Saúl Ibarra Corretgé
00c8409e31 ios,android: update SDK version to 2.3.0 2019-09-17 13:42:08 +02:00
Leonard Kim
1b43c22940 fix(chat): update thumbs emoji strings
react-emoji-renderer 1.0.0 removed the
thumbsup and thumbsdown aliases.
2019-09-16 09:55:36 -07:00
Saúl Ibarra Corretgé
efddb36164 thumbnail: fix accessing props 2019-09-16 13:27:10 +02:00
Saúl Ibarra Corretgé
385e1c1047 media: fix creating video track when toggling the welcome page switch 2019-09-13 19:07:26 +02:00
Saúl Ibarra Corretgé
3cc181a2e5 rn,config: create a fake config if we cannot load one on the welcome page
We try to load the configuration with every room change, even when there is no
room. There is a bad (corner) case: when we have no config cached (first boot or
wiped app data). In such case the user is trapped in an infinite loop because we
require the config to show the welcome page, oh well.

Pretend we have a configuration by creating the most minimal one to at least get
to the welcome page.
2019-09-13 19:07:26 +02:00
Saúl Ibarra Corretgé
bcc1be675f thumbnail: use a functional component
Simplifies the code a bit, and we use no lifecycle methods.
2019-09-13 17:37:23 +02:00
Saúl Ibarra Corretgé
d1be5742ba thumbnail: remove dead code
Audio streams are automatically played by WebRTC and this won't change, probably
ever. There is no point in having checks and an Audio component which does
nothing.
2019-09-13 17:37:23 +02:00
Saúl Ibarra Corretgé
1b27e331da thumbnail: use a more explicit prop 2019-09-13 17:37:23 +02:00
Saúl Ibarra Corretgé
c1f7bf75c1 thumbnail: don't render dominant speaker indicator on 1-1 calls 2019-09-13 17:37:23 +02:00
Bettenbuk Zoltan
382ec011eb ref: reduce device popup bundle size 2019-09-13 17:25:32 +02:00
Bettenbuk Zoltan
8a3ddd8596 feat: SVG icons 2019-09-13 14:07:53 +02:00
Saúl Ibarra Corretgé
738a199b4c welcome: tame the linter 2019-09-13 12:28:53 +02:00
Saúl Ibarra Corretgé
40a1af5302 dev: use alpha as the default proxy target 2019-09-13 11:51:22 +02:00
Maximilian Ruta
be5dba7eea welcome: add room validation pattern
Fixes: #312
2019-09-13 11:18:58 +02:00
Saúl Ibarra Corretgé
eb15f73e59 android: don't use proguard on debug builds
It's not necessary and makes the build faster.
2019-09-12 19:43:05 +02:00
Saúl Ibarra Corretgé
2f7b485b8f android: remove unneded code 2019-09-12 19:43:05 +02:00
Saúl Ibarra Corretgé
3a885c893a android: fix running on Android 5
For some reason ART complains about these methods being overrides of package
private ones from Timber.
2019-09-12 19:43:05 +02:00
Saúl Ibarra Corretgé
6c4901a826 ios,callkit: delay updating the muted state until conference starts
In iOS 13 if the call is not unmuted when we report it to the system as started,
an action to unmute it is dispatched automagically. Thanks, Apple.

So, delay synchronizing the muted state until the conference is started (after
the join action). This creates a small window for de-synchronization, but it's
very short and it seems unavoidable.

This change is only applied to operating systems built by the fruit company in
Cupertino.
2019-09-12 12:55:02 +02:00
Saúl Ibarra Corretgé
91c1c91950 android: fix log formatting issues 2019-09-11 14:29:37 +02:00
Saúl Ibarra Corretgé
1091ac7e7d log: fix log formatting 2019-09-10 10:34:52 +02:00
damencho
0c0bd001e5 Removes disableSuspendVideo option. Updates @jitsi/lib-jitsi-meet. 2019-09-10 08:58:55 +02:00
Bettenbuk Zoltan
256994e1f8 fix: webpack proxy fix 2019-09-09 18:27:30 +02:00
Saúl Ibarra Corretgé
f6fb859531 build: exit with an error if bundle sizes increase too much
The currently selected values are a bit above the actual sizes, so if a PR
increases the bundle size enough to trigger the failure, it should bump it.
It better have a good reason for it though!
2019-09-06 17:46:25 +02:00
Saúl Ibarra Corretgé
7deb2006c3 build: add integration with webpack-bundle-analyzer
Build as follows to build (production) bundle size stats:

npx webpack -p --progress --analyze-bundle

Then open the report:

npx webpack-bundle-analyzer build/stats.json build/
2019-09-06 17:46:25 +02:00
Saúl Ibarra Corretgé
2aea24ffad dial-in-info: fix bundle bloat
The direct import sidesteps many chained-effect imports, halving the bundle
size.
2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
b5aae0b58d build: style 2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
d436825a45 flacworker: don't use the Grand Unified Logger
There are just a couple of logs in this feature, and it's a standalone bundle,
which would bloat it due to cascaded dependencis.
2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
5276cb6bc8 alwaysontop: don't use the Grand Unified Logger
There are just a couple of logs in this feature, and it's a standalone bundle,
which would bloat it due to cascaded dependencis.
2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
f863733dd3 base/util: don't use the Grand Unified Logger
There are just a couple of logs in this feature, and it's included in bundles
like external_api, which would bloat it due to cascaded dependencis.
2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
2ccd4968a4 external_api: don't use the Jitsi Meet logger
This is for other applications to use, and it's currently only used for logging
1 line, so use console.error.
2019-09-06 16:29:23 +02:00
Saúl Ibarra Corretgé
c233433243 deps: react-native-webrtc@latest 2019-09-05 16:37:51 +02:00
Saúl Ibarra Corretgé
6861f463b3 android: update SDK release script to publish JSC artifacts
In
b53a034aaf (diff-0339cf92cc68bc5981fe6df601316c1c)
I removed this, because RN has updated the builtin JSC version. On the next
release, however, RN introduced a new JS interpreter (Hermes) so JSC is now a RN
dependency. Thus, add the magic spells to publish the AARs to Maven.
2019-09-05 16:32:53 +02:00
Hristo Terezov
ac065f0225 chore(package.json): Update LJM 2019-09-05 04:33:02 -07:00
Saúl Ibarra Corretgé
b4b33c94dd ios: update Podfile.lock 2019-09-05 12:53:26 +02:00
Saúl Ibarra Corretgé
c8753230a4 deps: react-native-webrtc@latest 2019-09-04 20:27:33 +02:00
paweldomas
dbf569e29e chore(deps): update LJM to 00920c0f655a74c757c7fef2cdbd053ae4d1f485 2019-09-04 10:46:18 -05:00
Saúl Ibarra Corretgé
27205e3119 ios: divert RN logs to our logger 2019-09-04 17:45:18 +02:00
Saúl Ibarra Corretgé
f2fdef8361 ios: log fatal errors, don't swallow exceptions 2019-09-04 17:45:18 +02:00
George Politis
d4dd5ab46a deps: lib-jitsi-meet@latest 2019-09-04 17:29:28 +02:00
Saúl Ibarra Corretgé
902da8cc4f rn: add native loggers
These provide the ability to integrate the SDK with some other application
loggers.

At the time this was written we use Timber on Android and CocoaLumberjack on iOS.

In addition to the integration capabilities, a LogBridge React Native module
provides log transports for JavaScript code, thus centralizing all logs on the
native loggers.
2019-09-04 10:50:30 +02:00
Saúl Ibarra Corretgé
c0a5e4f203 rn: fix crash when serializing calendar entries on iOS
Original PR: https://github.com/wmcmahan/react-native-calendar-events/pull/253
2019-09-03 12:37:31 +02:00
virtuacoplenny
55ff9dbe80 feat(api): expose method for playing touch tones (#4584) 2019-08-30 14:17:22 -07:00
Hristo Terezov
bd99108e8e feat(analytics):Add white/black list functionality 2019-08-30 10:26:22 -07:00
damencho
0c042b4078 Adds config to auto turn on captions when recording is started. 2019-08-30 15:46:29 +01:00
damencho
743bbcb846 Commit from translate.jitsi.org by user damencho.: 548 of 596 strings translated (3 fuzzy). 2019-08-30 14:47:00 +00:00
damencho
4ef2f0211a Commit from translate.jitsi.org by user damencho.: 436 of 596 strings translated (18 fuzzy). 2019-08-30 14:46:52 +00:00
damencho
86f765a01f Commit from translate.jitsi.org by user damencho.: 596 of 596 strings translated (0 fuzzy). 2019-08-30 14:46:23 +00:00
damencho
9e8b8313e0 Commit from translate.jitsi.org by user damencho.: 438 of 586 strings translated (16 fuzzy). 2019-08-30 14:46:11 +00:00
damencho
f4a8115b00 Commit from translate.jitsi.org by user damencho.: 552 of 586 strings translated (3 fuzzy). 2019-08-30 14:46:01 +00:00
Bettenbuk Zoltan
a93bd422d3 feat: new invite layout 2019-08-28 13:57:33 +02:00
Bettenbuk Zoltan
c1598b7376 feat: make display name prompt platform independent 2019-08-26 22:20:22 +02:00
Leonard Kim
bc403adb46 feat(api): allow for explicit screenshare state toggling 2019-08-26 06:53:28 -07:00
Bettenbuk Zoltan
1941275f93 feat: mobile chat emojis 2019-08-26 15:37:58 +02:00
paweldomas
6ae9bbe0c5 feat: report analytics for the network connection
Will emit new 'network.info' action with the online/offline status and
extra details for native like the network type and
'isConnectionExpensive' flag.
2019-08-23 13:36:33 -05:00
Jip-Hop
2c70388a9e Get participant specific video element
* Get participant specific video element

We now have the ability to select the video element for specific participants. I'm tweaking the jitsi-meet-electron app for my use case. I need to open Always On Top windows for specific participants, so the current _getLargeVideo() wont suffice.

I made a post about this in the Developers section on the Jitsi Community Forum, but it got blocked by Akismet.

* Add dots at end of sentence.

* Fixed ESlint errors and add additional check for iframe.

* Use _myUserID instead of string.

* Return the local video by default if participantId is undefined.

* Fixed mistake in string template.
2019-08-23 08:35:10 -07:00
Saúl Ibarra Corretgé
e0815de2ad rn,welcome: fix accessing local participant
It need not always exist, since it's created asynchronousluy on app
initiualization. Make sure we are ready for it.

I've seen backtraces because of this.
2019-08-23 17:16:22 +02:00
Saúl Ibarra Corretgé
02e058370e logging: disable caller info globally 2019-08-23 17:11:29 +02:00
Saúl Ibarra Corretgé
8a7b795d37 deps: lib-jitsi-meet@latest 2019-08-23 17:11:29 +02:00
Saúl Ibarra Corretgé
d24ca796ad deps: jitsi-meet-logger@latest 2019-08-23 17:11:29 +02:00
Leonard Kim
af2c61fd96 fix(pinning): dynamically check auto-pin setting
Any overrides set on interfaceConfig are not
applied on module load. As such, call to get
the value of the auto pin setting, providing
time for the bootstrapping to set overrides.
Otherwise iframe api users cannot override
the setting.
2019-08-23 07:36:27 -07:00
Saúl Ibarra Corretgé
5a934c071a logging: use individual, names loggers
React Native doesn't define __filename nor __dirname so do it artisanally. In
addition, this helps with centralizing the configuration passed to loggers.
2019-08-23 10:57:38 +02:00
Saúl Ibarra Corretgé
bfe4237430 deps: update jitsi-meet-logger 2019-08-23 10:57:38 +02:00
damencho
84c60a5fdf Removes i18n strings for p2p and turn. 2019-08-22 15:44:13 +01:00
Bettenbuk Zoltan
cfc7210ac8 feat: add send message button 2019-08-22 12:03:39 +02:00
damencho
57ac951192 Commit from translate.jitsi.org by user damencho.: 533 of 597 strings translated (3 fuzzy). 2019-08-21 12:26:23 +00:00
Saúl Ibarra Corretgé
36fee03d5e deps: update lib-jitsi-meet 2019-08-21 12:52:09 +02:00
paweldomas
14b747e0a4 fix(ios/xcode): increase node heap space for the bundle JS step 2019-08-21 11:12:56 +02:00
Saúl Ibarra Corretgé
c113b2e765 ios: update Podfile.lock 2019-08-21 11:12:56 +02:00
Saúl Ibarra Corretgé
560e65da37 deps: update lib-jitsi-meet 2019-08-21 11:12:56 +02:00
Saúl Ibarra Corretgé
861cf7d842 deps: react-redux@7.1.0
RN 0.60 loudly complains (loudly) about deprecated methods which react-redux was using.
2019-08-21 11:12:56 +02:00
Saúl Ibarra Corretgé
dd23ed09ad deps: react-native@0.60 2019-08-21 11:12:56 +02:00
Saúl Ibarra Corretgé
64897b9c91 rn,toolbox: simplify logic for showing Toolbox on mobile 2019-08-20 20:04:27 +02:00
Saúl Ibarra Corretgé
0dc8c687f2 rn,filmstrip: ignore the 'visible' parameter on mobile
Mobile uses a different logic for deciding whether to show the filmstrip or not:
if there are more than 1 participants or not, and there is no way to manually
toggle it.
2019-08-20 20:04:27 +02:00
paweldomas
c65d29d1a7 travis: wait 10 seconds after script to catch the error logged
Adds wait time suggested by Travis support in order to see the last
error logged.
2019-08-20 10:20:59 -05:00
Saúl Ibarra Corretgé
6aa895b679 android: attempt to fix assertion errors in ReactInstanceManager
This is the main one:
df4e67fe75/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java (L512)

Why this happens is a mystery wrapped in an enigma.
2019-08-16 17:59:47 +02:00
Saúl Ibarra Corretgé
dae451e6fa android: fix crash when parsing calendar events
Upstream PR: https://github.com/wmcmahan/react-native-calendar-events/pull/268
2019-08-16 17:46:53 +02:00
Hristo Terezov
3c1f056d2a fix(dialog): Don't steal focus 2019-08-16 07:40:47 -07:00
Leonard Kim
663e0a6693 fix(deep-linking): add back description copy 2019-08-16 16:30:16 +03:00
Saúl Ibarra Corretgé
53f98df8f3 deps: react-native@0.59.10 2019-08-16 07:26:54 +02:00
Saúl Ibarra Corretgé
6616f728f6 proximity: enable the proximity sensor when the device is set to earpiece 2019-08-14 18:57:03 +02:00
Saúl Ibarra Corretgé
1c1e8a942b audio-mode: refactor device handling
This commit refactors device selection (more heavily on iOS) to make it
consistent across platforms.

Due to its complexity I couldn't break out each step into separate commits,
apologies to the reviewer.

Changes made to device handling:

- speaker is always the default, regardless of the mode
- "Phone" shows as a selectable option, even in video call mode
- "Phone" is not displayed when wired headphones are present
- Shared device picker between iOS and Android
- Runtime device updates while the picker is open
2019-08-14 18:57:03 +02:00
George Politis
9721d99918 Updates lib-jitsi-meet. 2019-08-14 16:00:46 +02:00
Saúl Ibarra Corretgé
69c21cbb11 avatar: make code a bit clearer
Uses nullish coalescing and optional chaining.
2019-08-14 15:36:40 +02:00
Saúl Ibarra Corretgé
abefc56750 deps: add babel plugins for optional chaining and nullish coalescing
They are in Stage 3 and are already dependencies or the React Native preset.

References:
https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator
2019-08-14 15:36:40 +02:00
damencho
a4a1685224 chore(lib-jitsi-meet): Update. 2019-08-13 10:16:20 -07:00
damencho
21fb225726 Adds a retry logic when fetching conference numbers and pin. 2019-08-13 19:00:18 +03:00
damencho
75ab890707 Uses the wrapped fetch from base/util. 2019-08-13 19:00:18 +03:00
damencho
2ded8363ad Leaves room only when it is already joined.
In case of hitting errors like max participant limit reached and when clicking hangup, the attempt to leave room second time results error and reload screen.
2019-08-13 16:04:43 +03:00
Leonard Kim
c0a8a386a5 fix(pinning): debounce autopin subscriber
The store's remote tracks get cleared
and re-added when switching in and out
of p2p, which can cause pinning thrashing.
Avoid that with a debounce.
2019-08-12 17:31:53 -07:00
Leonard Kim
7af081ea99 fix(avatars): re-render avatar on any resize 2019-08-12 12:41:57 -07:00
Дамян Минков
8800cb4580 Adds live streaming sound notification. (#4532)
* Adds live streaming sound notification.

* Adds ios resources for the new files.
2019-08-12 18:34:38 +03:00
Karthik Muralidharan
b658f20a30 feat(API): add dominant speaker changed event
Fixes: https://github.com/jitsi/jitsi-meet/issues/4049
2019-08-09 10:09:33 +02:00
Hristo Terezov
c3e52f32f9 feat: Add logging for thumbnail display mode and tile view. 2019-08-09 01:08:19 -07:00
George Politis
ab73d808fe Updates lib-jitsi-meet. 2019-08-08 18:05:50 +02:00
dependabot[bot]
e110460793 Bump jquery from 3.3.1 to 3.4.0
Bumps [jquery](https://github.com/jquery/jquery) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.3.1...3.4.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-08 14:37:18 +02:00
dependabot[bot]
c0ee451ca1 Bump lodash from 4.17.11 to 4.17.13
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.13.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.13)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-08 10:34:51 +02:00
Saúl Ibarra Corretgé
67dca97d1d rn,participants: don't render thumbnnail for screen-shares 2019-08-07 20:16:13 +02:00
Saúl Ibarra Corretgé
fd0ca76255 web,avatar: fix setting avatar size
Use the width of its container as the size, so the font icons can be rendered at
a good size.
2019-08-07 20:16:13 +02:00
Saúl Ibarra Corretgé
149e53af76 avatar: render a special avatar if the user is sharing their screen 2019-08-07 20:16:13 +02:00
Saúl Ibarra Corretgé
f3e7952e51 audio-only: implement initial "low bandwidth mode"
It's an evolution of audio-only mode, where we also allow for receiving a remote
screen-share.

Diving deeper: this basically sets last N to 1 or 0 depending on the
availability of a screen-share.
2019-08-07 20:16:13 +02:00
Saúl Ibarra Corretgé
0f77cf9e0c android: use adaptive icons 2019-08-07 14:40:20 +02:00
damencho
66eb09fb63 Revert raisedHand thumb tooltip i18n string. 2019-08-07 14:59:24 +03:00
Hristo Terezov
b7f2c7d487 chore(lib-jitsi-meet): Update. 2019-08-06 01:59:01 -07:00
Bettenbuk Zoltan
bed3f62536 feat: make links in chat clickable 2019-08-06 08:48:37 +02:00
Leonard Kim
e8eb7e1e1f fix(suboptimal-browser): remove inserting of app name in notification
This prevents inserting any user overridden APP_NAME
values into html. A new translation key is being used
to immediately stop non-english languages from using the
problematic string.

Also tweaked the copy to remove the "eer" and fix
some grammar.
2019-08-05 06:47:44 -07:00
Leonard Kim
1409d6fb5e fix(deep-linking): do not accept native app name as raw html
There is no need to display the native app name as
raw html.
2019-08-04 06:45:00 -07:00
Bettenbuk Zoltan
a2cbd9229a fix: render notification description on mobile 2019-08-02 21:14:19 +02:00
Saúl Ibarra Corretgé
bf50a110c7 lastn: simplify computing the effective last N value 2019-08-02 15:54:47 +02:00
Saúl Ibarra Corretgé
467c9d36cf audio-only,lastn: move audio-only and last N handling to standalone features
This refactors all handling of audio-only and last N to 2 features in preparation
for "low bandwidth mode".

The main motivation to do this is that lastN is a "global" setting so it helps
to have all processing for it in a single place.
2019-08-02 15:54:47 +02:00
damencho
6ddd17c769 Removes resolveAppName postprocess we do not need.
i18next.options are initialized before interfaceConfig overwrites are processed which leads to wrong translations.
2019-08-01 12:47:58 +01:00
virtuacoplenny
732f2c1963 ref(feedback): emit api feedback submitted on completion (#4499)
* ref(feedback): emit api feedback submitted on completion

Compared to firing the event on submission because
the submission ajax will not be completed at that
time..

* squash: update package.json
2019-07-31 10:59:22 -07:00
Bettenbuk Zoltan
e7144eb674 Get chat message display name from backend 2019-07-31 10:48:22 +02:00
Saúl Ibarra Corretgé
b5489b7c81 rn,filmstrip: don't unpin participant when hiding filmstrip
The filmstrip is currently only hidden when PiP mode is entered. There is no
real reason not to leave the large view as it was.
2019-07-30 18:51:40 +02:00
Saúl Ibarra Corretgé
4d5332cadf rn,conference: log pin participant analytics events also on mobile 2019-07-30 17:11:43 +02:00
Saúl Ibarra Corretgé
5261f61110 conference: don't pin participants on the JVB
When a participant is pinned in the UI we then proceed to mark it as selected on
the JVB. This will make the participant part of the last N set and will receive
the highest (or configured highest) video quality.

Pinning a participant at the JVB level just makes sure it will be part of the
last N set.

Since only one participant can be pinned in the UI, there is no point in pinning
it at the JVB level, since selecting it already achieved the same result.
2019-07-30 17:11:43 +02:00
paweldomas
8c7d6da5d5 deps: update LJM to get analytics fixes
Bumps LJM to 3c8058743177b6b6963d3bc3df14f4ea650ef310.
2019-07-30 15:45:43 +02:00
Leonard Kim
6d91728a74 fix(proxy): stop screenshare when the connection stops 2019-07-30 06:40:57 -07:00
Hristo Terezov
9b32fc95eb chore(package): update lib-jitsi-meet version. 2019-07-30 01:55:02 -07:00
Leonard Kim
6bc1d87753 feat(shortcuts): add shortcut for opening video quality modal 2019-07-29 11:40:07 -07:00
damencho
a5fc62b920 Updates correct loading and fix checking is dominant speaker. 2019-07-26 11:18:55 +01:00
Saúl Ibarra Corretgé
49f6010905 pagedlist: fix refresh on wrapped components 2019-07-26 10:38:54 +02:00
paweldomas
1c27f567ee feat: send analytics event when conference is rejoined 2019-07-26 08:25:53 +02:00
paweldomas
7684b2bf98 ref: move getCurrentConferenceUrl to base/connection
Moves getCurrentConferenceUrl method to base/connection to allow reuse.
The new location is not ideal, but looks the best based on the imports
required (trying to avoid circular dependencies).
2019-07-26 08:25:53 +02:00
damencho
8886bcdb73 Fixes missing strings. 2019-07-26 07:07:31 +01:00
Saúl Ibarra Corretgé
437bdb92be deps: update react-native-webrtc and lib-jitsi-meet
Support for the MediaStream constructor has been added to react-native-webrtc.
2019-07-25 23:52:54 +02:00
Saúl Ibarra Corretgé
6943659dc9 rn: enable auto-pinning on screenshare on mobile 2019-07-25 14:27:04 +02:00
Saúl Ibarra Corretgé
35f934e197 config: remove old backwards compatibility shim
It was added for
3ea2f00578
over 2 years ago. That's long enough!
2019-07-25 11:45:16 +02:00
damencho
aca0469bd0 Fixes mobile wifi stats timestamp value type. 2019-07-25 10:20:48 +01:00
Дамян Минков
11f2e7291e Talk while muted sound notification (#4473)
* Moves talk while muted as a new feature.

* Adds sound notification for talk while muted.

* Reorder imports and changes the dispatch of the notification.

* Introduces sounds.js for talk while muted.
2019-07-23 21:56:05 +01:00
Bettenbuk Zoltan
7a985dd843 fix: disable reduced UI on welcome page 2019-07-23 17:52:03 +02:00
damencho
e09ea36055 Maps available locales for countries to the doubled languages.
This maps the tow letter languages as enGB to the country file for en.
Copies countries-en.json as countries-enGB.json.
2019-07-23 10:10:03 +01:00
damencho
ad3a087091 Commit from translate.jitsi.org by user damencho.: 532 of 586 strings translated (9 fuzzy). 2019-07-22 23:06:01 +00:00
damencho
d379b4d53b Commit from translate.jitsi.org by user damencho.: 546 of 586 strings translated (0 fuzzy). 2019-07-22 23:05:43 +00:00
damencho
7a99d57274 Commit from translate.jitsi.org by user damencho.: 478 of 586 strings translated (6 fuzzy). 2019-07-22 23:00:06 +00:00
damencho
85bc0ed5fc Commit from translate.jitsi.org by user damencho.: 535 of 586 strings translated (6 fuzzy). 2019-07-22 22:57:36 +00:00
damencho
f4dda6e7ce Commit from translate.jitsi.org by user damencho.: 434 of 586 strings translated (15 fuzzy). 2019-07-22 22:54:29 +00:00
damencho
5c8dfabf7c Commit from translate.jitsi.org by user damencho.: 538 of 586 strings translated (0 fuzzy). 2019-07-22 22:50:47 +00:00
damencho
20d03f3228 Commit from translate.jitsi.org by user damencho.: 343 of 586 strings translated (18 fuzzy). 2019-07-22 22:46:35 +00:00
damencho
268137bb97 Commit from translate.jitsi.org by user damencho.: 342 of 586 strings translated (19 fuzzy). 2019-07-22 22:44:50 +00:00
damencho
f87463780c Commit from translate.jitsi.org by user damencho.: 506 of 586 strings translated (1 fuzzy). 2019-07-22 22:42:16 +00:00
damencho
6b2ced63c7 Commit from translate.jitsi.org by user damencho.: 506 of 586 strings translated (0 fuzzy). 2019-07-22 22:40:00 +00:00
damencho
d6fbe55360 Commit from translate.jitsi.org by user damencho.: 411 of 586 strings translated (9 fuzzy). 2019-07-22 22:38:36 +00:00
damencho
0feeb94fc7 Commit from translate.jitsi.org by user damencho.: 491 of 586 strings translated (5 fuzzy). 2019-07-22 22:36:34 +00:00
damencho
c9c509ec51 Commit from translate.jitsi.org by user damencho.: 539 of 586 strings translated (4 fuzzy). 2019-07-22 22:34:45 +00:00
damencho
f7ff457a3b Commit from translate.jitsi.org by user damencho.: 536 of 586 strings translated (3 fuzzy). 2019-07-22 22:32:29 +00:00
damencho
72127aaa0b Commit from translate.jitsi.org by user damencho.: 505 of 586 strings translated (4 fuzzy). 2019-07-22 22:30:42 +00:00
damencho
b8854a3b45 Commit from translate.jitsi.org by user damencho.: 538 of 586 strings translated (4 fuzzy). 2019-07-22 22:27:01 +00:00
damencho
e6e7001857 Commit from translate.jitsi.org by user damencho.: 535 of 586 strings translated (7 fuzzy). 2019-07-22 22:19:53 +00:00
damencho
6d4601fe66 Updates used languages and fixes loading them. 2019-07-22 17:48:44 +01:00
damencho
8ecb01ec21 Commit from translate.jitsi.org by user damencho.: 545 of 586 strings translated (1 fuzzy). 2019-07-22 14:48:34 +00:00
damencho
14ccb41015 Commit from translate.jitsi.org by user damencho.: 545 of 586 strings translated (1 fuzzy). 2019-07-22 14:29:08 +00:00
damencho
348cde54e7 Commit from translate.jitsi.org by user damencho.: 545 of 586 strings translated (1 fuzzy). 2019-07-22 14:24:36 +00:00
damencho
430bd3f141 Commit from translate.jitsi.org by user damencho.: 535 of 586 strings translated (7 fuzzy). 2019-07-22 13:03:23 +00:00
damencho
b36f419e86 Commit from translate.jitsi.org by user damencho.: 122 of 586 strings translated (28 fuzzy). 2019-07-22 13:03:11 +00:00
damencho
ed1d03db71 Commit from translate.jitsi.org by user damencho.: 524 of 586 strings translated (5 fuzzy). 2019-07-22 13:02:58 +00:00
damencho
5d837571c0 Commit from translate.jitsi.org by user damencho.: 538 of 586 strings translated (5 fuzzy). 2019-07-22 13:02:46 +00:00
damencho
f23532d7f4 Commit from translate.jitsi.org by user damencho.: 78 of 586 strings translated (12 fuzzy). 2019-07-22 13:02:33 +00:00
damencho
0280294a8f Commit from translate.jitsi.org by user damencho.: 80 of 586 strings translated (12 fuzzy). 2019-07-22 13:02:19 +00:00
damencho
fdd1418236 Commit from translate.jitsi.org by user damencho.: 433 of 586 strings translated (16 fuzzy). 2019-07-22 13:02:05 +00:00
damencho
bae47434b1 Commit from translate.jitsi.org by user damencho.: 531 of 586 strings translated (10 fuzzy). 2019-07-22 13:01:52 +00:00
damencho
3c98cfc136 Commit from translate.jitsi.org by user damencho.: 216 of 586 strings translated (36 fuzzy). 2019-07-22 13:01:25 +00:00
damencho
17e5bc7b73 Commit from translate.jitsi.org by user damencho.: 89 of 586 strings translated (5 fuzzy). 2019-07-22 13:01:11 +00:00
damencho
6092655099 Commit from translate.jitsi.org by user damencho.: 503 of 586 strings translated (6 fuzzy). 2019-07-22 13:00:59 +00:00
damencho
721cca669f Commit from translate.jitsi.org by user damencho.: 0 of 586 strings translated (0 fuzzy). 2019-07-22 13:00:49 +00:00
damencho
c62ff0939d Commit from translate.jitsi.org by user damencho.: 505 of 586 strings translated (1 fuzzy). 2019-07-22 12:58:57 +00:00
damencho
ecf050c2d9 Commit from translate.jitsi.org by user damencho.: 344 of 586 strings translated (15 fuzzy). 2019-07-22 12:58:46 +00:00
damencho
069137b02a Commit from translate.jitsi.org by user damencho.: 25 of 586 strings translated (0 fuzzy). 2019-07-22 12:58:34 +00:00
damencho
f053cad66c Commit from translate.jitsi.org by user damencho.: 123 of 586 strings translated (20 fuzzy). 2019-07-22 12:58:22 +00:00
damencho
4be3042cb0 Commit from translate.jitsi.org by user damencho.: 445 of 586 strings translated (25 fuzzy). 2019-07-22 12:58:09 +00:00
damencho
593235d683 Commit from translate.jitsi.org by user damencho.: 490 of 586 strings translated (6 fuzzy). 2019-07-22 12:57:56 +00:00
damencho
7bd8ddbba2 Commit from translate.jitsi.org by user damencho.: 39 of 586 strings translated (2 fuzzy). 2019-07-22 12:57:44 +00:00
damencho
14232b1d93 Commit from translate.jitsi.org by user damencho.: 515 of 586 strings translated (17 fuzzy). 2019-07-22 12:57:25 +00:00
damencho
ff4887a3c8 Commit from translate.jitsi.org by user damencho.: 535 of 586 strings translated (4 fuzzy). 2019-07-22 12:57:12 +00:00
damencho
0289aacd4f Commit from translate.jitsi.org by user damencho.: 505 of 586 strings translated (2 fuzzy). 2019-07-22 12:57:01 +00:00
damencho
99c13eaec0 Commit from translate.jitsi.org by user damencho.: 254 of 586 strings translated (22 fuzzy). 2019-07-22 12:56:48 +00:00
damencho
1a713dfa27 Commit from translate.jitsi.org by user damencho.: 536 of 586 strings translated (4 fuzzy). 2019-07-22 12:56:36 +00:00
damencho
7e84b51ee0 Commit from translate.jitsi.org by user damencho.: 534 of 586 strings translated (4 fuzzy). 2019-07-22 12:56:22 +00:00
damencho
86fa442d0e Commit from translate.jitsi.org by user damencho.: 148 of 586 strings translated (18 fuzzy). 2019-07-22 12:55:58 +00:00
damencho
93b88f1a16 Commit from translate.jitsi.org by user damencho.: 342 of 586 strings translated (19 fuzzy). 2019-07-22 12:55:46 +00:00
damencho
2041d4fffb Commit from translate.jitsi.org by user damencho.: 534 of 586 strings translated (0 fuzzy). 2019-07-22 12:54:35 +00:00
jitsi-pootle
83c3e7c725 New files added from translate.jitsi.org based on templates 2019-07-22 12:53:40 +00:00
damencho
a34331891a Commit from translate.jitsi.org by user damencho.: 477 of 586 strings translated (7 fuzzy). 2019-07-22 12:46:37 +00:00
damencho
56dd83740c Commit from translate.jitsi.org by user damencho.: 533 of 586 strings translated (8 fuzzy). 2019-07-22 12:46:23 +00:00
damencho
debe50c3f4 Commit from translate.jitsi.org by user damencho.: 227 of 586 strings translated (22 fuzzy). 2019-07-22 12:46:08 +00:00
damencho
d9985c786c Commit from translate.jitsi.org by user damencho.: 5 of 586 strings translated (0 fuzzy). 2019-07-22 12:42:06 +00:00
damencho
ed910947d4 Commit from translate.jitsi.org by user damencho.: 268 of 586 strings translated (27 fuzzy). 2019-07-22 12:41:32 +00:00
damencho
c4c5eace25 Commit from translate.jitsi.org by user damencho.: 206 of 586 strings translated (29 fuzzy). 2019-07-22 12:40:07 +00:00
damencho
c6bf646fe8 Commit from translate.jitsi.org by user damencho.: 410 of 586 strings translated (10 fuzzy). 2019-07-22 12:37:36 +00:00
jitsi-pootle
ab2bb7686e New files added from translate.jitsi.org based on templates 2019-07-22 10:14:05 +00:00
jitsi-pootle
12b53c38b9 New files added from translate.jitsi.org based on templates 2019-07-22 10:14:05 +00:00
jitsi-pootle
ca31c8b199 New files added from translate.jitsi.org based on templates 2019-07-22 10:14:05 +00:00
jitsi-pootle
1b331ce090 New files added from translate.jitsi.org based on templates 2019-07-22 10:14:05 +00:00
jitsi-pootle
edd55e7798 New files added from translate.jitsi.org based on templates 2019-07-22 10:14:05 +00:00
Дамян Минков
9f4da84701 I18next update (#4456)
* Removes unused translations.

* Fixes using translated strings.

* Moves using latest i18next versions and stop using compatibility modes.

* Sorts i18next options.

* Fixes defaultNS used by i18next.

This is used when translating html tags with data-i18n keys as attributes, used by jQuery-Impromptu.
2019-07-22 11:10:25 +01:00
Leonard Kim
0097360396 feat(deep-linking): allow disabling through override 2019-07-19 14:48:46 -07:00
Hristo Terezov
b5cef05941 fix(AOT): imports. 2019-07-19 07:17:15 -07:00
George Politis
ddab9224b2 Merge pull request #4460 from jitsi/analytics-event-for-connectivity-issues
deps: update lib-jitsi-meet
2019-07-18 18:26:28 +02:00
George Politis
a5693c6e96 updates package-lock.json 2019-07-18 17:25:46 +02:00
George Politis
8dd345b192 deps: update lib-jitsi-meet
With the update we get a new analytics event that sends connectivity
issues events to the analytics backend.
2019-07-18 17:10:29 +02:00
Leonard Kim
130ab886ee fix(chat): show toolbar on open 2019-07-18 06:08:27 -07:00
Leonard Kim
c0e9f2b95a fix(chat): workaround for chat scroll causing layout misalignment 2019-07-18 06:08:27 -07:00
Leonard Kim
011972872e fix(blur): add beta label to toolbar button 2019-07-16 10:35:31 -07:00
Saúl Ibarra Corretgé
ef5720a3f0 deps: update react-native-webrtc
Fixes: https://github.com/jitsi/jitsi-meet/issues/4436
2019-07-16 17:55:37 +01:00
Bettenbuk Zoltan
ec30af2844 feat: always show labels 2019-07-16 17:32:58 +02:00
Bettenbuk Zoltan
e08aeca28c feat: use css to place the toolbox buttons 2019-07-16 17:01:24 +02:00
Bettenbuk Zoltan
ad7892ebce aot: jigasi participant icon 2019-07-16 13:04:17 +02:00
Saúl Ibarra Corretgé
cbc7e1b6be android: fix crash if UserInfo is not set
Fixes: https://github.com/jitsi/jitsi-meet-sdk-samples/issues/11
2019-07-16 07:29:07 +01:00
Saúl Ibarra Corretgé
da7d959b9a android: raise SDK version 2019-07-16 07:29:07 +01:00
virtuacoplenny
ada57ebcd0 ref(user-interaction): do not store listener, move browser check to lib (#4441)
* ref(user-interaction): remove storing of listener

* ref(user-interaction): move browser requirement check to lib-jitsi-meet

* ref(user-interaction): no inner function for listener, use module scope
2019-07-13 06:59:58 -07:00
Bettenbuk Zoltan
1993ad10eb feat: apply color brand guidelines 2019-07-12 20:48:49 +02:00
Bettenbuk Zoltan
d305caf910 feat: borderless toolbox icons 2019-07-12 20:48:49 +02:00
Bettenbuk Zoltan
a25a504a59 feat: add bottom gradient 2019-07-12 20:48:49 +02:00
damencho
250c61279b Updates react-native callstats dependency, to use siteID on mobile. 2019-07-12 18:24:44 +01:00
Saúl Ibarra Corretgé
1e18af2d1a rn: fix not showing a prompt when permissions have been denied
This only shows up if we cannot prompt again, like when turning permissions off
in the Settings app in iOS.
2019-07-12 17:50:54 +02:00
Дамян Минков
eb1fd4fd88 Merge pull request #4438 from jitsi/cs-siteid
Passes confID when initializing JitsiConference.
2019-07-12 14:25:35 +01:00
Matthias Herzog
e0c8b6b3c0 fix welcome page title fixes #4273 2019-07-12 14:25:26 +01:00
Дамян Минков
9071cd4813 Listens for suspend events from jitsi-power-monitor on postis channel. (#4428)
* Listens for suspend events from jitsi-power-monitor on postis channel.

* Removes duplicated type and actions.

* Moves suspendDetected state from overlay to power-monitor feature.
2019-07-12 14:08:34 +01:00
Saúl Ibarra Corretgé
9bf650c700 android: keep okio classes
Fixes running profile builds.
2019-07-12 14:22:36 +02:00
Saúl Ibarra Corretgé
49e3b03885 android: custom initialization of the WebRTC module
Set our own audio device manager so we can tweak it if need be (enabling /
disabling the HW AEC on specific devices).

Switch to using the software video encoder / decoder. This may feel like a
downgrade, but it has advantages:

- simulcast is now working (on par with iOS)
- certain devices have broken VP8 HW encoders (I'm looking at you Samsung Galaxy
S7) so this fixes that
2019-07-12 14:22:36 +02:00
Saúl Ibarra Corretgé
31e996ac3f android: always run adb reverse when starting the packager
It tends to close, so always open the reverse tunnel.
2019-07-12 14:22:36 +02:00
Saúl Ibarra Corretgé
d1c447e97b deps: update react-native-webrtc
- Fix crash in PeerConnection.close (Android)
- Add ability to customize PeerConnectionFactory (Android)
2019-07-12 14:22:36 +02:00
damencho
8a34c0a80f Updates lib-jitsi-meet. 2019-07-12 11:17:53 +01:00
virtuacoplenny
2f626ea474 ref(api): move participant join and left to middleware (#4365) 2019-07-11 12:44:27 -07:00
Bettenbuk Zoltan
0a76eebca7 feat: central back button registry 2019-07-11 16:14:08 +02:00
damencho
0e9e695251 Passes confID when initializing JitsiConference.
The confID is domain.com/RoomName or domain.com/tenant/RoomName, adds the tenant if any and also keeps the room name case.
2019-07-11 14:58:14 +01:00
Leonard Kim
b86df7a8e3 fix(remote-control): do not assume failed query is missing support
Multiple requests for checkUserRemoteControlSupport can be in
flight simultaneously. Order of promise resolution is not
guaranteed. It is possible for Request A and Request B to be
in flight and then Request B's promise chain resolves first.
Request A could have encountered errors and then resolve. Then
what could happen is checkUserRemoteControlSupport returns true
for remote control support due to Request B and the UI updates.
But then checkUserRemoteControlSupport returns false for
remote control support due to Request A's error and the UI
updates to hide remote control.
2019-07-11 07:25:08 +01:00
Bettenbuk Zoltan
5b25e02e26 feat: use dialog instead of alert when inviting 2019-07-10 20:50:14 +02:00
Bettenbuk Zoltan
0e6f14bb7c fix: avoid false triggering CDU in SlidingView 2019-07-10 20:49:50 +02:00
Leonard Kim
57b9954d9c fix(api): support params with value of undefined 2019-07-10 11:09:11 -07:00
virtuacoplenny
249dd7b8b8 fix(invite): decode the meeting name (#4411)
* fix(invite): decode the meeting name

* squash: try to make mobile join same encoded meeting name as web

* Decodes and generated texts for share and copy meeting info.

Decodes in all cases except when it contains a space, as it will generate wrong links when pasted/shared in external applications.
2019-07-10 10:27:11 -07:00
Bettenbuk Zoltan
b31d7b4451 ref: remove createStyleSheet from dialog styles 2019-07-10 16:42:56 +02:00
Bettenbuk Zoltan
8dea3389ee fix: avoid clicking behind dialogs 2019-07-10 16:42:56 +02:00
virtuacoplenny
e7f9e8e7f7 fix(conference): require user interaction to unmute in iframe (#4429)
* fix(conference): require user interaction to unmute in iframe

* squash: explicitly whitelist react native
2019-07-10 12:02:27 +01:00
Bettenbuk Zoltan
a53a86ee7a feat: add room lock pwd error message 2019-07-10 11:01:49 +02:00
Saúl Ibarra Corretgé
598b6f0598 deps: update react-native-webrtc
WebRTC is now at M75
2019-07-09 17:22:32 +02:00
Saúl Ibarra Corretgé
b245945c4a android: be explicit about starting a foreground service
After calling startService we are supposed to have a bit of time before turning
the service into a foreground service, but certain devices seem to be more
spartan and we've seen the following failure:

Caused by java.lang.IllegalStateException: Not allowed to start service Intent { act=JitsiMeetOngoingConferenceService:START cmp=org.jitsi.meet/.sdk.JitsiMeetOngoingConferenceService }: app is in background uid UidRecord{f6778d5 u0a220 CAC  bg:+1m1s417ms idle change:idle procs:1 proclist:15604, seq(0,0,0)}
       at android.app.ContextImpl.startServiceCommon + 1600(ContextImpl.java:1600)
       at android.app.ContextImpl.startService + 1546(ContextImpl.java:1546)
       at android.content.ContextWrapper.startService + 669(ContextWrapper.java:669)
       at org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService.launch + 50(JitsiMeetOngoingConferenceService.java:50)

Be expliocit and call startForegroundService, on supported platforms.
2019-07-09 16:14:39 +02:00
Bettenbuk Zoltan
301a8e319a fix: reduce avatar font size 2019-07-09 15:45:38 +02:00
Saúl Ibarra Corretgé
820abfd059 ios: sync Podfile.lock 2019-07-09 12:58:07 +02:00
Hristo Terezov
1d42420a36 fix(font): Bring back the missing icons. 2019-07-08 20:03:04 +01:00
Hristo Terezov
1b4bdb5142 fix(blur): on FF 2019-07-08 20:03:04 +01:00
Hristo Terezov
f030a3f1fb fix(blur): when switching video tracks. 2019-07-08 20:03:04 +01:00
Hristo Terezov
8f79779ca7 fix(blur): Disable for SS 2019-07-08 20:03:04 +01:00
Saúl Ibarra Corretgé
c5111bb359 rn: update default color scheme 2019-07-08 20:27:44 +02:00
Bettenbuk Zoltan
42814eac7d feat: add icon based avatar and icon for pstn 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
74d0013acc feat: use participant id for avatar color 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
88e4850c4d fix: remove locally generated avatar ID 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
87f9b1cf92 ref: remove unnecesary functions 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
fe1187d7b7 ref: remove unused libs 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
a35b36d6df feat: dynamic avatar font size 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
a04982fd96 fix: AlwaysOnTop avatar 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
658679f89e fix: undefined participant in avatar call 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
f90fc665f8 ui: bigger padding to default avatar 2019-07-08 16:53:30 +02:00
Bettenbuk Zoltan
0c8130af41 fix: default avatar relative url 2019-07-08 16:53:30 +02:00
paweldomas
e4c5968459 fix: bring back the add meeting URL button
Brings back the button for generating meeting URLs for calendar events.
2019-07-08 09:26:33 -05:00
damencho
a148cd41a4 Fixes loading wifi-stats when used from jitsi-meet electron utils. 2019-07-08 14:30:20 +01:00
Saúl Ibarra Corretgé
f8a049759d android: fix crash if notification is null
I cannot see a path leading to it being null, but Crashlytics demonstrated it's
possible (so far in a small subset of old devices). Be defensive then.
2019-07-05 10:11:00 +02:00
Hristo Terezov
4b4225e14f chore(lib-jitsi-meet): Update. 2019-07-04 06:26:32 -07:00
Hristo Terezov
3b0c5d0b6a fix(blur): many small issues. 2019-07-04 06:26:32 -07:00
Cristian Florin Ghita
3b750ddd5a Add video background blur 2019-07-04 06:26:32 -07:00
Saúl Ibarra Corretgé
6383d000a9 rn: raise version to 19.3 2019-07-03 21:09:15 +02:00
Bettenbuk Zoltan
a48d67bdc7 fix: inconsistent state when quickly closing a sliding view 2019-07-03 13:43:56 +02:00
Saúl Ibarra Corretgé
2f92e72858 android: raise SDK version 2019-07-03 13:28:31 +02:00
Saúl Ibarra Corretgé
d2c85ada1b android: fix deadlock in uncaught exception handler
The app is about to crash at that stage so it was a moot point to try to leave
the conference anyway.

Stopping ConnectionServers is still a good idea though, since a crash may leave
the device in a bad state otherwise.
2019-07-03 13:28:18 +02:00
Saúl Ibarra Corretgé
55b95c52d6 android: fix synchronized access to listeners set
Fixes this issue:

~~~
    java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextNode(HashMap.java:1441)
        at java.util.HashMap$KeyIterator.next(HashMap.java:1465)
        at org.jitsi.meet.sdk.OngoingConferenceTracker.updateListeners(OngoingConferenceTracker.java:89)
        at org.jitsi.meet.sdk.OngoingConferenceTracker.onExternalAPIEvent(OngoingConferenceTracker.java:74)
        at org.jitsi.meet.sdk.ExternalAPIModule.sendEvent(ExternalAPIModule.java:71)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:158)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
        at android.os.Looper.loop(Looper.java:214)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
        at java.lang.Thread.run(Thread.java:764)
~~~
2019-07-03 13:28:18 +02:00
Chris Hansen
52362c4675 Fix spelling mistake on pragma mark
It causes a compiler error in Xcode 11 because it doesn't know how to parse it.
2019-07-02 14:11:01 -07:00
netaskd
8da0552541 microsoftCalendar: add showing calendar events in local timezone. 2019-07-02 21:20:00 +01:00
Hristo Terezov
7ce0def995 fix(mobile): After PR #4396 2019-07-02 10:36:37 -07:00
Hristo Terezov
48285e8a2d fix(conference): Don't use this._room.
this._room should be used only by jitsi-meet-torture and for test purposes. Also this._room is assigned later than room. This may cause some issues, for example conference.getMyUserId() may return undefined while the user id is already available beacuse this._room hasn't been assigned yet.
2019-07-02 07:38:57 -07:00
Hristo Terezov
21dcc41d31 ref(large-video): switch LargeVideo logic to react 2019-07-02 07:38:57 -07:00
Дамян Минков
625d268373 Room lock update (#4394)
* Adds a notification when remote lock happens.

* Updates translations.

Removes unused strings and extracts room password to separate translation, to be able to change it when deployment uses only digits.

* Formats the conference pin when showing it.

* Removes member from translation in favour of participant.

* Updates formatting of the pin.

* Adds a notification when password is remotely removed.
2019-07-02 14:14:58 +01:00
Дамян Минков
681782ed20 Adds back talk while muted notification. (#4392)
* Adds back talk while muted notification.

* Adds unmute button to the notification.
2019-07-02 12:59:25 +01:00
Saúl Ibarra Corretgé
1baa85b649 rn: hide invite button if the functionality is not available 2019-07-02 12:30:50 +02:00
Bettenbuk Zoltan
72137a2811 feat: initial based avatars 2019-07-01 23:59:16 +02:00
Leonard Kim
0734ce7ae3 feat(api): add notifications for kicked participants 2019-07-01 12:53:25 -07:00
Дамян Минков
2dc06c28e3 Adds option to be able to cancel locked rooms and leave. (#4391)
* Adds option to be able to cancel locked rooms and leave.

* Removes not needed operations when canceling password prompt.
2019-07-01 13:02:25 +01:00
paweldomas
5848669552 feat(analytics): time since last success in connection dropped
Update LJM to 9bcc2a26cc94683b8ed302418695a331b450df97 in order to bring
in the analytics update which will add a property indicating how much
time has passed since the last successful XMPP request came through.
2019-06-28 13:30:50 -05:00
Leonard Kim
c0376d238a ref(notifications): do not notify of local participant left
Join notifications are already supressed for the local
participant, so hide the left notification. For now
the notification is not being shown on mobile to keep
the same existing behavior and because a copy change
will be needed, but will be added once batching is
implemented.
2019-06-28 09:18:18 -07:00
Leonard Kim
979b773c3c ref(notifications): move join notification firing to notifications feature 2019-06-27 17:29:02 -07:00
Leonard Kim
3195a449ca ref(conference): web and native exercise same redux flow for kicked out 2019-06-27 09:34:05 -07:00
Bettenbuk Zoltan
d7483f07e3 feat: add possibility to clear invite search field 2019-06-27 18:17:37 +02:00
Дамян Минков
9c1b802997 Device selection now always shows the device that it managed to open. (#4384)
* Device selection now always shows the device that managed to open.

* Simplifies implementation, skips using state.
2019-06-27 17:04:47 +01:00
damencho
bb3a10b0fc Safe guard for removed parent node of the iframe. 2019-06-27 14:23:59 +01:00
paweldomas
97e8b31cee fix: update LJM to fix reload on hangup
Updates LJM to c0af82a215d0893f1999df299cfdfcbc9ce9e72a
2019-06-26 22:11:12 +02:00
Saúl Ibarra Corretgé
55218de779 rn: add a reduced UI mode for the welcome page
The only way to render the welcome page in reduced UI mode currently is to
hangup a call from the Android ongoing notification while in PiP mode.
2019-06-26 21:45:27 +02:00
Saúl Ibarra Corretgé
714e0e045d android: add notification while there is an ongoing meeting
The notification is posted by a foreground service, which also has the nice
side-effect of keeping the app alive for a long time.
2019-06-26 21:45:27 +02:00
Saúl Ibarra Corretgé
0bc369afb4 android: add ability to get the current Activity running RN
This helper method gets the current Activity attached to React Native (via the
ReactContext). This is useful for modules which need access to it, without being
actual React Native modules.
2019-06-26 21:45:27 +02:00
Saúl Ibarra Corretgé
f71ec55170 android: add ability to keep track of the current ongoing conference 2019-06-26 21:45:27 +02:00
yanas
760885437a Merge pull request #4369 from jitsi/quality-text-change
Changes call quality strings to video quality.
2019-06-26 17:24:34 +01:00
damencho
f77976b742 Notify for detecting suspend. 2019-06-26 17:10:34 +01:00
Saúl Ibarra Corretgé
9e95e7cd97 rn: bump SDK version to 2.2.0 2019-06-26 12:04:17 +02:00
Leonard Kim
9d94257e79 ref(api): move conference join notification to middleware 2019-06-26 10:47:18 +02:00
Leonard Kim
13cfd61c83 fix(index): set reload link as attribute, not raw html 2019-06-25 12:48:31 -07:00
Leonard Kim
fa818bc386 feat(screenshare): allow auto-pin remote only 2019-06-25 11:21:23 +01:00
Saúl Ibarra Corretgé
a73a642c64 rn: fix CallKit failure screen flash when kicked
Pretend we have left instead of triggering a call failure. The user was already
told in the dialog.
2019-06-25 10:25:33 +02:00
Leonard Kim
94b3f6410d ref(api): move local participant name change 2019-06-24 13:15:02 -07:00
Leonard Kim
3d30f6e9cd ref(api): move filmstrip display notification 2019-06-24 13:15:02 -07:00
Leonard Kim
40c16f0bac ref(api): move tile view subscriber to api dir 2019-06-24 13:15:02 -07:00
Leonard Kim
a1db63a8c2 ref(api): move feedbackSubmitted notification to api middleware 2019-06-24 13:15:02 -07:00
Leonard Kim
59a9c2d947 fix(notifications): show notifications after reducers update to get name
Otherwise the participant will not have been added yet
to state so the participant name will not display in
the notification.
2019-06-24 10:51:17 -07:00
Yana Stamcheva
fc897b9bac Changes call quality to video quality. 2019-06-24 14:39:22 +01:00
damencho
96f013c549 Fixes few undefined errors on standby. 2019-06-24 12:06:27 +01:00
damencho
742905e05a Removes duplicated text. 2019-06-24 12:06:27 +01:00
damencho
bde44a94e8 Changes display name prompt to non modal, so people can mute/unmute. 2019-06-24 12:06:27 +01:00
Saúl Ibarra Corretgé
1786bfadce android: make some activity attributes private
They are only meant to be used internally. This reduces the risk of SDK users
sending garbage when we expect a specific type.
2019-06-21 21:48:46 +02:00
Saúl Ibarra Corretgé
b2e840636a sounds: lower log severity
When native SDK users end a meeting the view gets disposed and detached from
React, and then the entire app gets destroyed and these errors get printed at
the error level, throwing some people off.
2019-06-21 21:48:46 +02:00
Saúl Ibarra Corretgé
ddaa22048f android: make sure we left the current meeting when the activity is destroyed
If the user swipes the activity from the recents list there is no other chance,
onDestroy gets called directly.
2019-06-21 21:48:46 +02:00
Saúl Ibarra Corretgé
3e77890387 android: fix not calling super in onNewIntent 2019-06-21 21:48:46 +02:00
Leonard Kim
1e39c12963 fix(suboptimal): allow checks for chromium based browsers 2019-06-21 09:55:43 -07:00
Saúl Ibarra Corretgé
243fdba80f android: fix exception when sending events without URL
ENTER_PIP_MODE, for example, does not have it.
2019-06-21 15:42:10 +02:00
Дамян Минков
08c4933c1b Fixes inviting more than one participant (#4352)
* Fixes inviting more than one participant.

* Shows a notification when participants are invited.

* Adds support for both .id and .user_id props for people query results.
2019-06-21 13:17:47 +01:00
Leonard Kim
d5e0dea469 fix(suboptimal): ignore mobile browsers in whitelists/blacklists 2019-06-21 11:01:40 +01:00
paweldomas
033aa0dd6e fix(base/conference/reducer): check if room is defined
This was hit on a corner case when ConnectionService will deny
the request to start the call. I am not sure, but it could have been
that the conference object has been disposed or closed or something
else, but the fact is that 'conference.room' was not defined and things
crashed. It is not safe to access conference's private field 'room'. It
is true JitsiConference doesn't follow the practice of marking this
field as private with the underscore '_', but it is not a public field.
2019-06-20 13:19:04 -05:00
Saúl Ibarra Corretgé
803870ef8f android: add a uncaught exception handler
Its main task is to cleanup conferences (specially the connection services
stuff) to make sure the system is left in a working state even when the
unexpected happens.
2019-06-20 17:03:24 +02:00
virtuacoplenny
bf67a4a675 Configurable (sub)optimal and unsupported browsers (#4351)
* Configurable (sub)optimal and unsupported browsers

* maybe this helps somehow
2019-06-20 14:02:15 +01:00
Bettenbuk Zoltan
ee2036a2a7 feat: show on stage function 2019-06-20 11:05:34 +02:00
Bettenbuk Zoltan
4c3ed190f3 feat: add ability to toggle toolbox from tile view 2019-06-20 11:05:34 +02:00
Hristo Terezov
a91b49c2c1 feat(reload): on offer / answer error. 2019-06-19 05:25:43 -07:00
Saúl Ibarra Corretgé
186ba70cb7 participants: skip local participant join notification
Also, use the helper function to get the display name for a participant.
2019-06-19 13:15:17 +02:00
Leonard Kim
12c18657d5 fix(welcome-page): make Tabs more resilient to bad props
In case wrong props are passed in, such as pointing to
an index that does not contain a value in the tabs
array.
2019-06-18 17:55:21 -07:00
Leonard Kim
9f8e7d4050 chore(deps): bump lib to a89d673 for caps version fixes 2019-06-18 17:24:12 -07:00
Leonard Kim
4cea7018f5 fix(tile-view): back to single click to pin
Undoes the logic added in:
ebcde745ef
2019-06-18 15:14:20 -07:00
Saúl Ibarra Corretgé
54a9b9199e rn: adapt to API changes in google signin 2019-06-18 14:51:44 +02:00
Saúl Ibarra Corretgé
4591b36c3e android: handle onActivityResult Activity lifecycle method
It may be called in the Activity instead of in the Fragment. Handle both.
2019-06-18 14:51:44 +02:00
Saúl Ibarra Corretgé
db862b5b3b misc: add Android debug builds to .gitignore 2019-06-18 14:51:44 +02:00
Saúl Ibarra Corretgé
70b864f00b deps: react-native-google-signin@2.0.0 2019-06-18 14:51:44 +02:00
Saúl Ibarra Corretgé
73b6a7a134 android: fix React packager not working on debug builds on a device 2019-06-18 14:51:44 +02:00
Saúl Ibarra Corretgé
8b5b112c6a android: don't default to making libre builds 2019-06-18 14:51:44 +02:00
Leonard Kim
2f7f9f24c4 fix(display-name): dismiss prompt if name gets set 2019-06-17 15:10:53 +01:00
Leonard Kim
1197c26529 fix(always-on-top): enforce circle avatar 2019-06-17 16:08:39 +02:00
Дамян Минков
6eb66b639e Notify for kick and mute (#4328)
* Updates kick showing who kicked us.

* Notify participants that someone was kicked.

* Shows notification to user who is remotely muted.

* Updates the notification type.

* Muted by notification for mobile.

* Moves code to react and adds the kick notifications to mobile.

* Updates lib-jitsi-meet.
2019-06-17 16:00:09 +02:00
Saúl Ibarra Corretgé
fa88db6897 ios: update CocoaPods to 1.7.1 2019-06-14 13:24:14 +02:00
Дамян Минков
64eb4b5609 Updates start silent, turning on startWithAudioMuted and few UI tweaks. (#4314)
* Updates start silent, turning on startWithAudioMuted and few UI tweaks.

Disabled mic unmute button and removes remote participants volume slider.

* Adds analytics for start silent.

* Removes extra semi colon.

* Updates lib-jitsi-meet and updates meeting info text.
2019-06-14 12:16:08 +01:00
Emil Ivov
ef2455caea Merge pull request #4333 from saghul/display-name-copy
lang: update display name request copy
2019-06-14 11:13:22 +01:00
Saúl Ibarra Corretgé
ca11cbf6cc calendar-sync: fix loading calendar entries
Checking if the calendar support in the reducer is not only useless but wrong,
since we don't have access to the entire store (the calendar support is checked
in the base/config feature). If calendar support is not enabled the actions
being reduced won't be dispatched anyway, so no harm is done by removing the
check.
2019-06-14 11:32:39 +02:00
Saúl Ibarra Corretgé
f15a2aea68 lang: update display name request copy 2019-06-14 11:03:32 +02:00
paweldomas
e6c3d7ded7 chore(deps): bump LJM version to increase frozen video timeout
Update LJM to 25ca5cbd2a93150e74f029075bc7ac734ed97a2f
2019-06-13 12:32:25 -05:00
Hristo Terezov
2861198251 ref(no-data-from-source): logic. 2019-06-13 09:52:10 -07:00
Hristo Terezov
226c0bb084 ref(track-error): Remove NO_DATA_FROM_SOURCE 2019-06-13 09:52:10 -07:00
Saúl Ibarra Corretgé
30c0bfc108 rn: disable vertical scrollbars on bottom sheets 2019-06-13 10:07:55 +02:00
Leonard Kim
df50e7fa69 fix(large-video): make blurred background fit whole screen 2019-06-12 20:27:04 -07:00
Saúl Ibarra Corretgé
f85ac3ef91 rn: fix video unmuting when disabling audio-only
When the video unmute button disabled audio-only, also unmute video. This fixes
a weird case in which the user need to "unmute twice" if they were muted beofre
they enabled audio-only mode. That's ok if the audio-only button was used, but
not if the video-unmute button was used, since the expectation is to have video,
of course.
2019-06-12 18:54:35 +02:00
Saúl Ibarra Corretgé
e33b334307 rn: add SDK API to set user information
At the moment it includes:

- display name
- email
- avatar URL

This information is used *only* if no token was specified.
2019-06-11 17:27:16 +00:00
Bettenbuk Zoltan
ce6f7308ad fix: avoid keyboard with search results list 2019-06-11 19:14:15 +02:00
Bettenbuk Zoltan
f66478fa34 feat: don't auto-stage bot type participants 2019-06-11 17:55:44 +02:00
Bettenbuk Zoltan
bf99051885 fix: invite search result sorting 2019-06-11 17:55:44 +02:00
Bettenbuk Zoltan
7234ca69c8 feat: invite field autofocus 2019-06-11 17:55:44 +02:00
Bettenbuk Zoltan
ae965877f3 fix: invite list needs double tap to select 2019-06-11 17:55:44 +02:00
Leonard Kim
ae3b70eb13 feat(api): notify of password required 2019-06-11 08:12:37 -07:00
Saúl Ibarra Corretgé
97e0303065 feature-flags: add flag for enabling calendar integration 2019-06-11 13:37:50 +00:00
Saúl Ibarra Corretgé
35ffbe1720 feature-flags: add flag for enabling chat 2019-06-11 13:37:50 +00:00
Saúl Ibarra Corretgé
f7b92f65ca ios: add feature flag to enable recording on iOS 2019-06-11 13:37:50 +00:00
Saúl Ibarra Corretgé
cf7b10d53d feature-flags: initial implementation
The welcomePageEnabled and pictureInPictureEnabled props on mobile have been
converted to feature flags.
2019-06-11 13:37:50 +00:00
Saúl Ibarra Corretgé
d798f93614 deps: check-in the diff when npm 6.9.0 is used 2019-06-11 13:08:23 +00:00
Saúl Ibarra Corretgé
4ddfcaf584 toolbox: disable audio-mode when video-unmuting
If audio-only was engaged, use the video (un)mute button to disengage it. This
should simplify the flow for getting back to video.
2019-06-11 13:08:23 +00:00
Saúl Ibarra Corretgé
431a221c63 ios: be resilient to invalid UUIDs 2019-06-11 10:04:15 +00:00
Mihai Damian
477826089c ios: Added property for setting PiP initial position 2019-06-11 09:25:23 +00:00
Hristo Terezov
a46369cf22 chore(package.json): Update lib-jitsi-meet 2019-06-10 06:53:36 -07:00
Hristo Terezov
651791b8df feat(deeplinking): Pass state to openDesktopApp. 2019-06-10 04:14:41 -07:00
virtuacoplenny
09cc738219 fix(recording): do not prompt hidden participants for name (#4309)
* fix(recording): do not prompt hidden participants for name

* squash: update package.json
2019-06-10 11:27:08 +01:00
Leonard Kim
6d8ec4d147 fix(unsupported): stop recommending safari 2019-06-07 07:36:20 -07:00
Leonard Kim
d65a068fdb feat(deep-linking): hide web button on unsupported browsers 2019-06-07 07:36:20 -07:00
Leonard Kim
cf23045f8d feat(unsupported): provide custom blacklist for branding 2019-06-07 07:36:20 -07:00
Leonard Kim
e47d2d13ce fix(deep-linking): deep link first, then show unsupported
Re-structure the custom routing to split between
platforms instead of between intended route features.
This made it easier for me to understand where to
do the checks for unsupported browser after deep-linking
had been checked.
2019-06-07 07:36:20 -07:00
Aaron van Meerten
07b7f03aa7 Merge pull request #4308 from jitsi/prosody-token-allow-asap-server-override
allows override of asap key server in token utility
2019-06-06 14:26:25 -06:00
Aaron van Meerten
7ce44f85ca changed to using a setter for the asapKeyServer 2019-06-06 15:22:38 -05:00
Aaron van Meerten
41e0d782ce allows override of asap key server in token utility 2019-06-06 14:41:46 -05:00
Aaron van Meerten
2a8fafdd36 Merge pull request #4303 from jitsi/start-silent
Adds a config param startSilent to disable audio output.
2019-06-05 12:29:57 -06:00
damencho
faee1c139e Adds a config param startSilent to disable audio output. 2019-06-05 18:01:18 +01:00
virtuacoplenny
eb644987ce fix(settings): do not use non-set localStorage values (#4299)
If a value is not set in localStorage then null is
returned. null should not be converted to an empty
string (via _.escape) because that will then be
stored in localStorage as the user set preference
and will keep overriding any other values set
in localStorage for the displayname.
2019-06-04 17:42:48 -07:00
damencho
de60a70daf Commit from translate.jitsi.org by user damencho.: 555 of 625 strings translated (8 fuzzy). 2019-06-03 11:19:10 +00:00
damencho
2904dfa794 Commit from translate.jitsi.org by user damencho.: 584 of 625 strings translated (2 fuzzy). 2019-06-03 11:19:01 +00:00
damencho
d51cf7c581 Commit from translate.jitsi.org by user damencho.: 625 of 625 strings translated (0 fuzzy). 2019-06-03 10:58:25 +00:00
Hristo Terezov
f25e6c6a5d chore(package.json): Update lib-jitsi-meet version 2019-06-01 02:28:04 -07:00
Hristo Terezov
5fb9422513 feat(API): Add show feedback parameter to hangup 2019-06-01 02:28:04 -07:00
Hristo Terezov
d01cfc8466 fix(conference): API left event. 2019-06-01 02:28:04 -07:00
Saúl Ibarra Corretgé
fa3888991f rn: avoid logging initial props in release builds
They may contain sensitive information.
2019-05-31 11:49:36 +02:00
virtuacoplenny
ded355a807 fix(settings): use moderator check helper (#4292) 2019-05-30 14:10:40 -07:00
Leonard Kim
b655c8d54a fix(large-video): clear remote video stream on track removal
VideoLayout schedules a large video update by passing in
the video stream on the small video instance. When a stream
is removed, the UI is removed from the small video instance
but a reference to the stream is left. So when VideoLayout
schedules the large video update after a stream removal,
the old stream from the small video instance is re-used,
even though it has been removed.

This change also brings balance with RemoteVideo method
"addRemoteStreamElement" which sets the stream on the
small video instance, so now "removeRemoteStreamElement
unsets it.
2019-05-30 09:46:35 -07:00
Leonard Kim
42a6e6faaf ref(large-video): remove redundant call to update on stream removal 2019-05-30 09:46:35 -07:00
Leonard Kim
c7954c284d ref(large-video): move layout update on stream removal to layout middleware 2019-05-30 09:46:35 -07:00
virtuacoplenny
251da1861a feat(api): notify api of mic and camera errors (#4289)
- Use actions to notify the rest of the app that
  a mic or camera error has occurred
- Use middleware to respond to those notifications
  of errors by showing in-app notifications and
  notifying the external api
2019-05-29 14:17:07 -07:00
Hristo Terezov
9712804040 fix(Amplitude): user id 2019-05-29 09:53:31 -07:00
Hristo Terezov
fecbef0aff fix(AmplitudeModule): class name 2019-05-29 17:22:50 +02:00
Saúl Ibarra Corretgé
d65b71b584 rn: add ability to set the conference subject 2019-05-29 14:48:02 +02:00
Saúl Ibarra Corretgé
579d291bca config: add ability to pass the subject as a URL parameter 2019-05-29 14:48:02 +02:00
Saúl Ibarra Corretgé
871026f4ba conference: clear the pending subject after it has been set 2019-05-29 14:48:02 +02:00
Saúl Ibarra Corretgé
9a8a070c62 rn: show conference subject if set 2019-05-29 14:48:02 +02:00
Leonard Kim
7cf4c7bd78 Revert "feat(screenshare): enable auto-pin of latest and last screenshare"
This reverts commit f42d0411b1.

The UX provided by this feature flag in its current state is not
desired. Also, I noticed filmstrip sometimes failing to properly
update small video display mode on pin/unpin. The feature is
being left in for consumers of jitsi-meet to enable as needed.
2019-05-28 15:28:50 -07:00
Hristo Terezov
72a1def571 feat(config): whitelist config.analytics 2019-05-24 13:42:12 -07:00
damencho
0dad99c3b7 Enables local video flip menu by default. 2019-05-24 23:09:24 +03:00
Hristo Terezov
840c0190c4 fix(deep-linking): Don't rely on custom scheme 2019-05-24 12:51:14 -07:00
Leonard Kim
e0fdeea69b fix(large-video): do not stretch dominant speaker avatar 2019-05-24 12:00:35 -07:00
Leonard Kim
e3612929f8 fix(avatar): dynamically size avatar in dynamically sizable filmstrip 2019-05-24 12:00:35 -07:00
Hristo Terezov
70921bb6ef feat(analytics): local tracks duration event. 2019-05-24 10:09:25 -07:00
Saúl Ibarra Corretgé
371ca4eef1 ios: don't require bitcode for Debug builds 2019-05-24 14:11:08 +02:00
Bettenbuk Zoltan
54fdb7066f feat: scrollable bottom sheet 2019-05-24 14:06:17 +02:00
Bettenbuk Zoltan
85bcb0c757 fix: auth dialog button labels 2019-05-24 11:35:56 +02:00
Bettenbuk Zoltan
d387cbe5bd fix: iOS 10 bottom sheet style 2019-05-24 11:28:28 +02:00
paweldomas
1bc28e4904 watchos: display a message if the recent list is empty 2019-05-24 09:41:31 +02:00
Saúl Ibarra Corretgé
cb3419ba2a android: enter PiP mode when pressing back button
When in a conference, try to enter PiP when pressing the back button. If this is
not possible (because it's unsupported, not enabled, etc.) fall back to the
previous behavior of simply hanging up.
2019-05-23 16:00:12 +02:00
Saúl Ibarra Corretgé
a2f8e156da app: avoid loading config when going back to the welcome page 2019-05-23 15:16:31 +02:00
Saúl Ibarra Corretgé
a4cf79c161 rn: fix losing audio if call is hangup too quickly
This PR changes the logic for connecting / disconnecting conferences. Instead of
doing it in mount / unmount events from the Conference component, it moves the
logic to the appNavigatee action.

This fixes a regression introduced in 774c5ecd when trying to make sure the
conference terminated event is always sent.

By moving the logic to appNavigate we no longer depend on side-effects for
connecting / disconnecting, and the code should be more maintainable moving
forward.

An improvement to this is the concept of sessions, which, while not tackled
here, was taken into consideration.
2019-05-23 15:16:31 +02:00
Saúl Ibarra Corretgé
9352517705 ios: always log delegate method calls 2019-05-23 15:16:31 +02:00
Saúl Ibarra Corretgé
47d5163c52 rn: don't tag builds by default
People run these in their own checkout and will run into problems because
tagging will fail.
2019-05-23 12:07:04 +02:00
Bettenbuk Zoltan
def22b01bb fix: set explicit color for search field to avoid theme override 2019-05-23 12:06:50 +02:00
Saúl Ibarra Corretgé
9445cf99fd Revert "ios: remove no longer needed code"
This reverts commit 603d161788.
2019-05-22 18:10:35 +02:00
paweldomas
96b226de24 watchos: change the icons
Inverts the icons to follow more what's in the phone app instead of
CallKit.
2019-05-22 17:25:35 +02:00
Bettenbuk Zoltan
5101f69e4e feat: don’t render moderator icon if everyone is moderator 2019-05-22 14:08:52 +02:00
François Benaiteau
61b66e0edf doc: fix incorrect code examples for universal / deep linking 2019-05-22 14:08:37 +02:00
Bettenbuk Zoltan
700051f809 fix: device selection colour scheme support 2019-05-22 12:29:28 +02:00
Дамян Минков
d16e10baec room-lock: adds ability to allow only digits for room locking 2019-05-22 09:43:17 +02:00
ibauersachs
11e5c14f83 Commit from translate.jitsi.org by user ibauersachs.: 317 of 625 strings translated (31 fuzzy). 2019-05-21 17:02:23 +00:00
ibauersachs
ded58d77d1 Commit from translate.jitsi.org by user ibauersachs.: 319 of 613 strings translated (26 fuzzy). 2019-05-21 16:58:20 +00:00
ibauersachs
8642c372c4 Commit from translate.jitsi.org by user ibauersachs.: 323 of 583 strings translated (4 fuzzy). 2019-05-21 16:56:52 +00:00
ibauersachs
edbf591059 Commit from translate.jitsi.org by user ibauersachs.: 430 of 583 strings translated (18 fuzzy). 2019-05-21 16:55:09 +00:00
jitsi-pootle
ded4291d6a New files added from translate.jitsi.org based on templates 2019-05-21 14:09:04 +00:00
Дамян Минков
a14fead0f3 Groups devices notifications by type audio/video. (#4238)
* Groups devices notifications by type audio/video.

* Fixes passing correct device array.
2019-05-20 21:35:42 +01:00
Saúl Ibarra Corretgé
466e1e3eb8 android: fix publishing new async storage package
The naming didn't match, so adjust it. @ cannot be used for maven artifact
names.
2019-05-20 17:33:36 +02:00
Saúl Ibarra Corretgé
8a90f0dab1 android: include SDK version in Maven repo commit message 2019-05-20 17:33:17 +02:00
Leonard Kim
d7e0aa3f61 fix(api): enable the external api before the first redux update
For the external api to fire update events out of the iframe, it
must first be initialized within the jitsi app. Any invocations
by the app to send updates events before initialization will
cause the api to swallow the events. The chosen fix is to
initialize the api earlier so the first update of app's redux
store fires update events that the api will also fire out of
the iframe.

This change will affect current behavior in that right now
the update event of the initial set of the avatar url is
blocked, but the change will make that event fire out of the
iframe.
2019-05-20 11:56:08 +02:00
Leonard Kim
37b343a797 feat(api): add ability to toggle tile view 2019-05-20 02:53:16 -07:00
Leonard Kim
149485905c fix(api): store passed in devices as user selected
Currently devices set through the api are stored
as ids, and not user selected. This can cause
other existing user selected devices to take
precedence over the devices passed into the api.
2019-05-17 10:47:31 +01:00
Aaron van Meerten
7f1df5629e Merge pull request #4229 from jitsi/poltergeist-prefix-support
updates bosh to support optional prefix
2019-05-16 15:40:28 -06:00
Leonard Kim
f42d0411b1 feat(screenshare): enable auto-pin of latest and last screenshare 2019-05-16 14:19:34 -07:00
Aaron van Meerten
8d1d573266 updates bosh to support optional prefix
use optional prefix in poltergeist room lookup
2019-05-16 14:23:36 -05:00
Leonard Kim
d86b60ea72 fix(chat): maintain bottom scroll on input resize 2019-05-15 08:06:35 -07:00
Leonard Kim
dfe5fbb702 ref(chat): change initial input size to 1 line 2019-05-15 08:06:35 -07:00
Leonard Kim
09f881c0f5 ref(chat): bring in package for text area auto-resizing 2019-05-15 08:06:35 -07:00
Leonard Kim
f1546008f9 ref(chat): removed unused getChatInputRef callback for input 2019-05-15 08:06:35 -07:00
Leonard Kim
d8df7fde84 ref(chat): clean up public blur/focus methods on input
Method blur is not called. Method blur is called
internally only.
2019-05-15 08:06:35 -07:00
Saúl Ibarra Corretgé
1c809eb428 ios: strip bitcode when releasing the SDK 2019-05-15 14:07:25 +02:00
Saúl Ibarra Corretgé
e94edcd4ae ios: automagically download a bitcode WebRTC build if needed 2019-05-15 09:54:17 +02:00
paweldomas
b48651396f fix(travis): upload through ssh proxy 2019-05-14 19:37:37 -05:00
Leonard Kim
e2044074ad Revert "fix(welcome-page): remove watermark container to avoid z-index wars"
This reverts commit 890151fa72.
2019-05-14 12:42:54 -07:00
Saúl Ibarra Corretgé
f060ac9db1 ios: notify RTCAudioSession about CallKit AVAudioSession activation 2019-05-14 21:09:39 +02:00
Leonard Kim
5a53d7f32a fix(chat): re-fix letting long messages wrap 2019-05-14 09:20:25 -07:00
Leonard Kim
4eec13da1c ref(chat): de-parameterize AbstractMessageContainer 2019-05-14 09:20:25 -07:00
Leonard Kim
cb8282dfe5 ref(chat): remove unused method 2019-05-14 09:20:25 -07:00
Leonard Kim
5cd0b1a9be fix(chat): fix auto-scrolling to bottom
Empower the parent.
2019-05-14 09:20:25 -07:00
Leonard Kim
504fadaf71 ref(chat): on web, move timestamp to chat message 2019-05-14 09:20:25 -07:00
Leonard Kim
7187e540a8 ref(chat): on native, show messages as grouped by sender 2019-05-14 09:20:25 -07:00
Leonard Kim
34dffbfc5e ref(chat): on native, group messages by sender (no styling) 2019-05-14 09:20:25 -07:00
Leonard Kim
a9637f93c3 ref(chat): create AbstractMessageContainer
So mobile and web can share logic for grouping chat
messages by sender.
2019-05-14 09:20:25 -07:00
Leonard Kim
0e8b0a9c5c ref(chat): create web MessageContainer component 2019-05-14 09:20:25 -07:00
Saúl Ibarra Corretgé
e66b596a0d ios: add ability to override SDK version when releasing 2019-05-14 17:00:02 +02:00
Saúl Ibarra Corretgé
6f320f463d rn: don't use annotated tags when building the SDKs 2019-05-14 17:00:02 +02:00
Saúl Ibarra Corretgé
02955ab57c deps: react-native@0.59.8
https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#v0598
2019-05-14 10:22:50 +02:00
Leonard Kim
a9d76a2577 fix(large-video): vertically align center screenshare
Stop using special case logic for aligning screenshare videos.
It may be possible to have positioning all done using CSS but that
seems to be a more significant refactoring.
2019-05-10 08:09:56 -07:00
Bettenbuk Zoltan
dcf31baf3a doc: update google auth doc 2019-05-10 13:22:05 +02:00
Bettenbuk Zoltan
1e346f10ab rn: fix streaming key input color 2019-05-10 13:22:05 +02:00
Leonard Kim
a114d55fac fix(chat): ensure really long words can trigger wrapping 2019-05-09 08:25:47 -07:00
Leonard Kim
afde717ca4 ref(chat): use message type as classname 2019-05-09 07:06:27 -07:00
Leonard Kim
fb5a45f714 feat(chat): on web, group messages by sender 2019-05-09 07:06:27 -07:00
Дамян Минков
f5ac18da18 Add option to allow guest(moderators) to add a room password 2019-05-09 13:30:38 +02:00
Saúl Ibarra Corretgé
103ae363f6 ios: fix CallKit crash in development mode
It's possible a CallKit event arrives when the React Bridge has been torn down
and there is an assert that checks this. In order to avoid a crash, just skip
the event.
2019-05-09 13:22:58 +02:00
damencho
9bde673397 Updates copy info with parltcipant name info if available. 2019-05-09 10:33:55 +01:00
paweldomas
ff6b27eafa fix(travis): add watch dev prov profile 2019-05-08 19:01:28 -05:00
paweldomas
8cb19ccbf6 fix(travis): download WebRTC bitcode 2019-05-08 19:01:28 -05:00
damencho
198eba3682 Does not play sound notifications on the recording side. 2019-05-08 10:27:05 -07:00
Leonard Kim
a49f62238b ref(chat): clean up extra dom 2019-05-08 08:57:00 -07:00
Leonard Kim
a8233bdb84 ref(chat): move some colors to css variables 2019-05-08 08:57:00 -07:00
Leonard Kim
ec2826e0fc ref(chat): make wider 2019-05-08 08:57:00 -07:00
Leonard Kim
3d9606f6da ref(chat): use somewhat transparent background 2019-05-08 08:57:00 -07:00
Leonard Kim
01458eeff9 ref(chat): add a header for holding the close button 2019-05-08 08:57:00 -07:00
Leonard Kim
0318568a30 ref(chat): add light top border on input for visual separation 2019-05-08 08:57:00 -07:00
Leonard Kim
4d04141f24 ref(chat): change input placeholder 2019-05-08 08:57:00 -07:00
Leonard Kim
afbc622fb9 ref(chat): differentiate local and remote messages with background color 2019-05-08 08:57:00 -07:00
Leonard Kim
fbc7f865ec ref(chat): change chat bubble borders based on sender
For remote chat messages, all corners should be rounded
except the top left. For local messages all corners
should be rounded except the top right.
2019-05-08 08:57:00 -07:00
Leonard Kim
2a4bac7a27 ref(chat): remove chat bubble arrow 2019-05-08 08:57:00 -07:00
Saúl Ibarra Corretgé
b45a5da6e2 rn: use new AsyncStorage package
It was extracted from the RN core to a community maintained package.
2019-05-08 16:03:09 +02:00
Saúl Ibarra Corretgé
2fad9f9ba8 ios: update Podfile.lock 2019-05-08 12:12:54 +01:00
Saúl Ibarra Corretgé
8b0e5b9d15 android: set system navbar color to match the header 2019-05-08 12:44:17 +02:00
paweldomas
0889ffdf27 android fix: do not enter PiP mode when the permissions alert is shown
Entering PiP mode while the permissions dialog is display will not only
fail, but also mess up the Activity lifecycle on some OS versions.
We may end up with two activity/fragment instances and a situation where
the onStop callback was not called yet on the instance #1 while
the onResume has been already called on instance #2.
2019-05-08 10:15:14 +02:00
Bettenbuk Zoltan
86d0d4fc22 rn: add DialInSummary 2019-05-07 18:02:14 +02:00
Bettenbuk Zoltan
7e9df74e60 rn: add generic alert dialog 2019-05-07 18:02:14 +02:00
Bettenbuk Zoltan
3eca67e1ad rn: add HeaderWithNavigation component 2019-05-07 18:02:14 +02:00
Дамян Минков
c040b3a7dd Fall back to using label for preferred devices (#4171)
* Skips setting undefined device id to sink in audio preview.

* Fallbacks to use labels for user selected devices.

* Fixes comment.
2019-05-07 09:53:01 +01:00
Leonard Kim
3f4a71c26d fix(welcome-page): remove watermark container to avoid z-index wars
By making the container 100% height and position relative, that
would cause it to overlap any static-positioned  elements below it.
The 100% makes it so that any watermarks intended for the bottom
of the page show up on the bottom of the page. However, it's not
needed because watermark stylings already try to position the
watermarks at the bottom.
2019-05-04 11:03:48 -07:00
Leonard Kim
e7db8d6812 fix(chat): save chat error messages into redux
The proper field name is "messageType",
not "type." Also using "type" would
override the actionType.
2019-05-03 14:06:36 -07:00
Saúl Ibarra Corretgé
7d2ac0244d deps: react-native-webrtc@4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43
New M69 build with Metal crash fixes.
2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
c0efea5168 ios: enable bitcode
Time has come. We need to enable bitcode. It's optional for iOS targets, but
mandatory for the entire project if there is a watchOS target. Since we have a
watchOS target, it's time to enable it.
2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
5ed53dcef5 ios: update Fastlane for watchOS app 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
746159a1ac ios: set compilation mode to "wholemodule" for release builds 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
43a8fd2a53 ios: set iOS deployment target correctly everywhere 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
a26bb2c1a6 watchos: add watchOS app
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
2019-05-03 19:29:30 +02:00
paweldomas
e4af5ddbe9 feat(base/connection): throw error and add isInviteURLReady 2019-05-03 19:29:30 +02:00
Дамян Минков
768cff48a4 Notify for new device (#4165)
* Fix detecting preferred audio output.

Fixes detecting when a new output device is found and we have stored user preference of using that device.

* Does not store which is the currently open device on save.

Does not save the currently opened device when saving settings dialog, this will be done once we successfully replace the tracks to use the new devices.

* Saves opened audio device after successfully changing it.

If we do it earlier _updateAudioDeviceId is using localAudio and can store wrong value.

* Adds notification for new non preferred devices.

A notification is shown which gives an option to the user to select and use the newly plugged devices.
Adding custom button and handler for the action to the notifications.

* Changes logic to search and handle all newly added devices from array.

* Moves some utility methods to features/base/devices.
2019-05-03 18:25:33 +01:00
damencho
384f0d4317 Removes hardcoded defaulting to US number from the code. 2019-05-03 16:55:22 +01:00
damencho
0ec4e6a805 Makes numbers clickable on the more numbers page when opened on mobile. 2019-05-03 16:55:22 +01:00
Saúl Ibarra Corretgé
5cc01b074e ios: update Podfile.lock for RN update 2019-05-03 10:27:17 +02:00
damencho
deaf5ba612 Always uses the id for the device extrackted from the track.
When updating the currently used devices always uses the id that is used by the local track instance.
2019-05-02 11:55:46 +01:00
damencho
740c1eb84f Adds new persistent state for devices user selection.
The state about currently opened devices is filtered and not stored, where we only store when user selects a device preferences.
Also allow changing input devices for Firefox when we are not in a conference.
2019-05-02 11:55:46 +01:00
Saúl Ibarra Corretgé
2d45709a6a android: add the ability to make a "libre" build
A libre build will exclude the following:

- Analytics modules
- Google Play services GMS
- Crashlytics
- Firebase
2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
6bbc2927ab analytics: don't initialize handlers if they are not properly configured 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
08891b17b6 android: expose JitsiMeetActivity.leave() 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
aab3428347 android: make JitsiMeetActivity.join public 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
bf7b1c5cfc rn: add support for alpha.jitsi.net 2019-05-01 23:23:24 +02:00
Saúl Ibarra Corretgé
7b347baab6 deps: react-native@0.59.5 2019-05-01 19:16:08 +02:00
Saúl Ibarra Corretgé
f9b3d470e9 cc: fix showing CC button if config option is undefined 2019-04-30 14:50:56 +02:00
Saúl Ibarra Corretgé
7b78fa45f4 invite: don't consider "add people" enabled if there is no search URL
This avoids showing the + button when there is no service configured, ie with
the default Jitsi Meet install.
2019-04-30 14:50:56 +02:00
Saúl Ibarra Corretgé
34dcbd991e rn: wait for animation before hiding SlidingView 2019-04-30 12:45:53 +02:00
Saúl Ibarra Corretgé
70dc22c107 rn: refactor BottomSheet
Avoid using a Modal since those create trouble with the view hierarchy.
2019-04-30 12:45:53 +02:00
damencho
89719520e2 Disposes the tracks in component was unmounted while creating those.
The issue is if you quickly click Devices and then another tab, we may leave open tracks (video light stays on even when you are video muted).
2019-04-29 14:38:17 +00:00
Дамян Минков
ce7bdb35ac Merge pull request #4152 from jitsi/prosody-0.10-update
Updates config if prosody 0.10 is used.
2019-04-29 14:36:55 +00:00
Дамян Минков
bf8c716477 Merge pull request #4150 from jitsi/invitation-update
Update copy invite text.
2019-04-29 14:36:46 +00:00
Дамян Минков
93e8d755d3 Merge pull request #4148 from zbettenbuk/recording-web-css-fix
Safeguard Container style when used cross-platform
2019-04-29 14:36:35 +00:00
damencho
c09eee0985 Disables chat when we are in recorder mode. 2019-04-29 14:36:22 +00:00
damencho
4f6a0d7d3a Updates config if prosody 0.10 is used. 2019-04-29 15:24:55 +01:00
damencho
dd5233d31b Update copy invite text. 2019-04-29 15:06:36 +01:00
Bettenbuk Zoltan
31638133b7 Safeguard Container style when used cross-platform 2019-04-29 13:37:30 +02:00
Bettenbuk Zoltan
b886f8d72d rn: specify chat text field font color 2019-04-26 21:33:11 +02:00
Дамян Минков
a6555c5d24 Singleton follow me (#4144)
* Prints errors in case of wrong initialization.

Not printing can masks some errors in the code.

* Allow only one Follow Me moderator in a meeting.

* Sends Follow Me state with all presences of the moderator.

This fixes an issue where the moderator sends the Follow Me state and then for example mute or unmute video (this will produce a presence without Follow Me state) and the new comers will not reflect current Follow Me state till a change of it comes.

* Changes fixing comments.

* Changes fixing comments.
2019-04-26 18:11:53 +00:00
Hristo Terezov
98c8fb09c4 feat(package.json): Update lib-jitsi-meet. 2019-04-26 07:54:38 -07:00
Leonard Kim
b76b261cab fix(invite): show telephone icon 2019-04-26 07:46:41 -07:00
Bettenbuk Zoltan
0b6c51f666 rn: replace 3rd party chat library with custom implementation 2019-04-26 15:17:36 +02:00
Sylvia van Os
1cb9bbc7a4 Fix wrong filename change 2019-04-26 09:06:43 +00:00
Sylvia van Os
fee9bdb98c Fix NAT documentation 2019-04-26 09:06:43 +00:00
virtuacoplenny
fb82cf4517 fix(modal): bump dep to 8.0.1 to remove scrollbars (#4139) 2019-04-25 11:58:11 -07:00
Saúl Ibarra Corretgé
85388b8d23 ios: handle some corner cases with Firebase Dynamic Links
- handle some weird bug
(https://github.com/firebase/firebase-ios-sdk/issues/233)
- use a common function to extract the URL off a dynamic link
2019-04-25 18:18:09 +02:00
Saúl Ibarra Corretgé
33f133ac25 ios: simplify code for handling CallKit listeners
Replace the Swift array with an Objective-C one, since it's going to store
Objective-C objects and not Swift objects (or Swift objects which inherit from
NSObject, which is equivalent).

This avoids the need for JMCallKitEventListenerWrapper entirely, since an
NSArray can store NSObjectProtocol objects, unlike a Swift array, which prompted
the creation of the wrapper in the first place.
2019-04-25 18:17:55 +02:00
Saúl Ibarra Corretgé
774c5ecd18 rn: ensure the conference terminated event is always sent
Dear reader, I'm not proud at all of what you are about to read, but sometimes
life just gives you lemons, so enjoy some lemonade!

Joining a conference implies first creating the XMPP connection and then joining
the MUC. It's very possible the XMPP connection was made but there was no chance
for the conference to be created.

This patch fixes this case by artificially genrating a conference terminated
event in such case. In order to have all the necessary knowledge for this event
to be sent the connection now keeps track of the conference that runs it.

In addition, there is an even more obscure corner case: it's not impossible to
try to disconnect when there is not even a connection. This was fixed by
creating a fake disconnect event. Alas the location URL is lost at this point,
but it's better than nothing I guess.
2019-04-25 14:04:26 +02:00
Saúl Ibarra Corretgé
ccc5e19e3c rn: fix filling LoadConfigOverlay's background 2019-04-24 17:41:28 +02:00
Saúl Ibarra Corretgé
32a81b0be5 rn: add our benevolent employer to the list of known domains 2019-04-24 17:36:41 +02:00
Saúl Ibarra Corretgé
59db39d4d9 rn: cleanup old code
This legacy code was added about a year ago to ease the migration between
releases:
631f51d627

I consider this not to be needed anymore.
2019-04-24 17:36:41 +02:00
damencho
2219298501 Updates web styling for file recording service sharing option. 2019-04-24 14:54:33 +00:00
Bettenbuk Zoltan
f92d530b0a Fix double file recording sharing switch 2019-04-24 10:35:43 +00:00
Bettenbuk Zoltan
e98c169c2f [RN] Fix iOS keyboard bug on invite search dialog 2019-04-24 11:48:09 +02:00
Saúl Ibarra Corretgé
6bf962817b ios: add a CallKit icon
The SDK will now search for an asset called "CallKitIcon" on the main bundle,
and fallback to a built-in asset it it's not there, allowing SDK users to
customize it by just adding asset with that name.
2019-04-24 10:03:46 +02:00
virtuacoplenny
4c286b8580 chore(deps): bump lib to get fixed rtc.destroy call (#4122) 2019-04-23 15:38:32 -07:00
Дамян Минков
37639a5614 Merge pull request #4121 from jitsi/remove-edge-support
Removes Edge support.
2019-04-23 20:32:17 +00:00
Bettenbuk Zoltan
b7198ba4b3 Add recording file sharing switch 2019-04-23 20:32:10 +00:00
damencho
2180d33e3d Adds alias for external_api.js in all default web config. 2019-04-23 20:31:53 +00:00
damencho
43a0ae578e Removes Edge support. 2019-04-23 17:55:07 +01:00
Bettenbuk Zoltan
154200460d Add some other paths to proxy bypass 2019-04-23 18:00:27 +02:00
Saúl Ibarra Corretgé
9a92dc578c ios: fix resetting CallKit's CXProvider
When CallKit is enabled / disabled, a new CXProvider must be created in order to
not confuse CallKit (it misbehaves otherwise).
2019-04-23 09:55:01 +02:00
paweldomas
eb38300c0d chore: update LJM to 1bfc96a2876d6527bfa27cf46d4f1e9f6e65edbc
Updates LJM in order to stop printing few obsolete error messages.
2019-04-18 12:24:23 -05:00
paweldomas
37b1ccbe61 ios: update react-native-werbtc in order to fix leaking streams 2019-04-18 12:24:23 -05:00
Bettenbuk Zoltan
725f9b1961 [RN] Rename lock room button 2019-04-18 14:18:08 +01:00
Leonard Kim
b172639237 fix(follow-me): remove duplicate default state 2019-04-17 15:58:55 -05:00
virtuacoplenny
c7013f5c4b ref(follow-me): hook into redux (#3991)
Use subscribers to detect state change and emit those
out to other participants. Use middleware to register
the command listener.
2019-04-17 08:05:32 -07:00
Saúl Ibarra Corretgé
aefa836406 Revert "misc: don't show a warning on Safari with VP8"
This reverts commit 9625be1db3.
2019-04-17 15:15:48 +02:00
virtuacoplenny
f6c410610a fix(toolbar): let click through gradient (#4107)
Otherwise it can eat clicks on elements it is above,
like YouTube and Etherpad controls.
2019-04-17 06:15:08 -07:00
Saúl Ibarra Corretgé
603d161788 ios: remove no longer needed code
Ever since we switched to handling track events instead of mute actions this has
been dead code. It was also added in the wrong place, since it's responsibility
of the JS code to solve the ping-pong problem.
2019-04-17 13:24:42 +02:00
Saúl Ibarra Corretgé
c1f8a35156 doc: add links to the sample SDK applications repo 2019-04-17 09:37:28 +02:00
virtuacoplenny
866dc4dbc6 ref(subtitles): remove logic around dialing transcriber (#4011) 2019-04-16 12:27:17 -07:00
damencho
69a12395d2 Removes debug log and adds safety check whether config exists. 2019-04-16 21:16:38 +02:00
virtuacoplenny
17627291e8 ref(css): use var for desktop drag area margin (#4104) 2019-04-16 11:45:25 -07:00
Hristo Terezov
30669c7699 feat(lib-jitsi-meet): Update version. 2019-04-16 17:05:02 +01:00
Hristo Terezov
4abc2db24a fix(device-selection): Default device change. 2019-04-16 17:05:02 +01:00
Bettenbuk Zoltan
2b4ace75ae [RN] Add connection indicator 2019-04-16 17:33:23 +02:00
Saúl Ibarra Corretgé
3217ef2bb4 ios: make sure symbols are uploaded to TestFlight
While that option should default to true, let's be explicit about it.
2019-04-16 15:43:15 +02:00
Bettenbuk Zoltan
e5caca9cfd [RN] Add display name label to tile view 2019-04-15 18:58:15 +02:00
Bettenbuk Zoltan
42c85c22a9 [RN] rearrange display-name files for later refactor 2019-04-15 18:58:15 +02:00
Leonard Kim
fd0eef4c84 fix(chat): change margins to avoid different background color 2019-04-12 22:39:09 +01:00
Leonard Kim
ab022c62f5 fix(filmstrip): bring down height to avoid electron drag area 2019-04-12 22:39:09 +01:00
Leonard Kim
f9c0c3e2f6 fix(chat): bring down elements to avoid electron drag area 2019-04-12 22:39:09 +01:00
paweldomas
70ec7c5b3d ios: bump travis osx_image to 10.2 2019-04-12 16:16:57 -05:00
virtuacoplenny
ca38bd53fe fix(chat): use css for arrow (#4097) 2019-04-12 13:59:03 -07:00
Leonard Kim
b3cae9a962 fix(chat): allow smiley opener to expand in width
The chat icons are different on windows and mac, with
windows icons being bigger. By settings a specific
width on the smiley container, windows would see
part of the smiley cut off.
2019-04-12 18:29:04 +01:00
Saúl Ibarra Corretgé
b768b88491 android: add ability to override SDK version when releasing 2019-04-12 15:39:29 +02:00
Saúl Ibarra Corretgé
9f339c452b android: raise SDK version 2019-04-12 15:39:29 +02:00
Leonard Kim
c34f9cf233 fix(screenshare): properly gate autopin behavior behind flag check 2019-04-11 09:09:48 -07:00
virtuacoplenny
76642b7c4b feat(screenshare): add auto pin of latest screen share (#4076) 2019-04-11 08:53:34 -07:00
Saúl Ibarra Corretgé
b78989f5f2 android: improve SDK release script
- don't hardcode defaults in gradle files
- allow for uploading also to HTTP URLs
- support HTTP authentication when publishing
2019-04-11 17:43:33 +02:00
virtuacoplenny
088b5d95c2 chore(deps): update lib for listener leak fix (#4084) 2019-04-11 08:00:05 -07:00
virtuacoplenny
c6e5adbe0e fix(large-video): respect update in progress when queuing update (#4078)
When a fade in/out animation is in progress, another large
video update can be queued but can try to force itself onto
large video. For example a pin can be in progress and while
the fade in/out animation plays, local video can change its
video type during the animation and forcing an update of
large video. This results in local video getting forcible
updated onto large video while the pinned video is left on
small video only.
2019-04-10 08:16:02 -07:00
Bettenbuk Zoltan
8bb56be317 [RN] Add conference connecting overlay 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
84b917d708 Reorg overlay feature files 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
18d908ce84 Fix flow errors from base/connection 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
3987655f2a Refactor config loading 2019-04-10 15:47:36 +02:00
Saúl Ibarra Corretgé
ee3b8af4cf ios: remove PiP sample application
It now lives here: https://github.com/jitsi/jitsi-meet-sdk-samples
2019-04-10 15:10:47 +02:00
Saúl Ibarra Corretgé
9625be1db3 misc: don't show a warning on Safari with VP8 2019-04-10 14:15:02 +02:00
Saúl Ibarra Corretgé
21c0745504 android,ios: now working on version 19.2 2019-04-10 14:14:04 +02:00
Saúl Ibarra Corretgé
26c9ee5f9c deps: lib-jitsi-meet@9659b4e413b12c637810fb2ab52354f1357a177e 2019-04-10 12:32:57 +02:00
Saúl Ibarra Corretgé
9b7af64e11 ios: raise SDK version 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
f26c5570df ios: update sample PiP app
- Xcode 10.2 + Swift 5
- Latest SDK API
- Fix warnings
2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
d37a0eee3a ios: fix compilation warnings 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
024fc73e63 ios: update to Xcode 5 and Swift 5 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
bdaabf6d3d odeps: react-native@0.59.4
Fixes a crash on some old Android devices.
2019-04-09 16:08:45 +02:00
virtuacoplenny
7a677ead93 ref(device-selection): set audio output sink id after receiving ref (#4066)
The Audio.js setRef callback does not behave like react ref callback
in that the former will not have fired before componentDidMount
but the later will have. So for audio output preview, trying to set
sink id on mount will no-op because it does not have a ref yet to
Audio.js, possibly leading to audio output previews playing on
the default speaker device. This generally has not been a user
visible problem due to coincidence; other re-renders necessary
by the parent of audio output preview will have triggered
componentDidUpdates on the audio out preview, which would then
set the sink id on the Audio.js ref it should have received
by then.
2019-04-08 10:38:06 -07:00
virtuacoplenny
e7812c7d84 fix(device-selection): search for device by label and kind (#4064)
Searching for a device (id) by label alone can result in
false results when devices share labels, such as a mic
and speaker having the same label. To prevent such,
specify the device kind to be found instead of iterating
over all device kinds.
2019-04-08 10:03:45 -07:00
damencho
ea54713f9a Supports prosody 0.11 when configuring.
Doing few changes needed for general config and for tokens.
2019-04-05 17:18:17 +02:00
virtuacoplenny
5a99697ae2 fix(toolbox): fix typo in action type for hide timeout (#4069) 2019-04-04 10:53:14 -07:00
virtuacoplenny
ec09085a50 fix(device-selection): set audio output device on initial configuration
When the iFrame api is used to set a preferred audio output using
options passed into the JitsiMeetExternalAPI constructor, no logic
fires to actually change the audio output destination.
2019-04-04 08:10:01 -07:00
virtuacoplenny
b731459ea4 fix(device-selection): use device kind when getting current devices (#4059)
Devices of different kinds can have the same id, such as speaker
and mic both being default. Using id only can then lead to
incorrectly setting device descriptions in the current devices
object.
2019-04-03 08:06:41 -07:00
Saúl Ibarra Corretgé
f73d3a4063 ios: add SDK release script 2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
4c3cf8c14a android: add an improved SDK release script
It releases the SDK and all dependencies (including React Native) to the
specified Maven repo.
2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
1f371ab055 android: simplify qualifying dependencies when publishing
Use an ever increasing number so no manual updates are necessary.
2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
dfeb26597b android: make Maven repo used for publising configurable 2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
384f7d7890 ios: update Podfile.lock 2019-04-02 16:18:09 +02:00
Bettenbuk Zoltan
4d9dcf5d43 [RN] Add InfoDialogButton 2019-04-02 16:18:09 +02:00
Saúl Ibarra Corretgé
e217e10af5 android: update custom version for native dependencies 2019-04-02 14:17:45 +02:00
Saúl Ibarra Corretgé
7feec7c11d deps: react-native-sound€0.10.12 2019-04-02 14:17:45 +02:00
Saúl Ibarra Corretgé
36eb27e233 rn: add build information to SettingsView 2019-04-02 12:40:35 +02:00
Bettenbuk Zoltan
b791fc32fd [RN] Make BaseIndicator render simpler 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
b1a70240fc Clear raise hand status on confidence leave 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
50d7c1521f Remove legacy web raise hand code 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
5d9762b429 Extract notification timeout to a constant 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
4e78502c9e Generalize indicators 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
6ff733dae0 Platform generic notification for raised hand 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
2dc59b9ea0 [RN] Add button to toggle raised hand 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
e65918564b [RN] Add UI for raised hand feature 2019-04-01 21:03:36 +02:00
Bettenbuk Zoltan
ce9744b9c3 Move participant event handler to a platform generic location 2019-04-01 21:03:36 +02:00
damencho
b413457a4f Commit from translate.jitsi.org by user damencho.: 262 of 588 strings translated (0 fuzzy). 2019-04-01 12:41:41 +00:00
damencho
75daedf9ab Commit from translate.jitsi.org by user damencho.: 406 of 583 strings translated (30 fuzzy). 2019-04-01 12:40:08 +00:00
damencho
45eeea447a Commit from translate.jitsi.org by user damencho.: 583 of 583 strings translated (0 fuzzy). 2019-04-01 12:40:00 +00:00
damencho
16fcc55ad1 Commit from translate.jitsi.org by user damencho.: 583 of 583 strings translated (0 fuzzy). 2019-04-01 12:39:52 +00:00
damencho
a70009e486 Commit from translate.jitsi.org by user damencho.: 583 of 583 strings translated (0 fuzzy). 2019-04-01 12:39:41 +00:00
damencho
06502e5aac Commit from translate.jitsi.org by user damencho.: 423 of 583 strings translated (24 fuzzy). 2019-04-01 12:39:33 +00:00
damencho
6316447d4b Commit from translate.jitsi.org by user damencho.: 504 of 583 strings translated (0 fuzzy). 2019-04-01 12:39:06 +00:00
jitsi-pootle
df5fa71b92 New files added from translate.jitsi.org based on templates 2019-04-01 12:39:06 +00:00
Bettenbuk Zoltan
10e951c17c Reorg notifications feature files 2019-03-29 18:52:44 +01:00
Hristo Terezov
f12317dc59 docs(api.md): Comply with our coding style. 2019-03-29 16:39:21 +00:00
Hristo Terezov
829e5597d5 fix(iframe-api-devices): Misc small issues. 2019-03-29 15:42:02 +00:00
Hristo Terezov
f2e0704b93 fix(filmstrip-only): DeviceSelectionPopup 2019-03-29 15:42:02 +00:00
Hristo Terezov
a7aaf31c79 feat(iframe-api): Add deviceListChanged event. 2019-03-29 15:42:02 +00:00
Hristo Terezov
4967488e56 ref(iframe-api-devices): Use labels instead of IDs 2019-03-29 15:42:02 +00:00
Hristo Terezov
ed1d3d3df5 fix(api-devices): Initial device function calls 2019-03-29 15:42:02 +00:00
Hristo Terezov
427f49367b feat(iframe-api): Device handling. 2019-03-29 15:42:02 +00:00
Saúl Ibarra Corretgé
659e420005 ios: make sure Fastlane can update the provisioning profile
https://docs.fastlane.tools/codesigning/xcode-project/#xcode-9-and-up
2019-03-29 14:50:59 +01:00
Saúl Ibarra Corretgé
9a46606f0d misc: s/Atlassian/8x8/ 2019-03-29 13:11:36 +01:00
Leonard Kim
3b911b0362 chore(deps): bump lib-jitsi-meet for permissions api fixes 2019-03-28 08:47:42 -05:00
Philip-Choi
7ae8ae5791 doc: update README 2019-03-28 09:46:03 +01:00
paweldomas
a386740103 fix(ConnectionService): history and audio focus on Samsung devices
On some Samsung devices the call done with the ConnectionService end up
in the native call history which we don't want. That's fixable by
marking the Connection as "external" just before the call is
disconnected.

Another issue specific to Samsung devices about the audio focus not
always being release when that call ends. That's fixable by marking
the call as holding just before disconnecting it.
2019-03-27 13:39:52 -05:00
Saúl Ibarra Corretgé
451949f49d android: enable PiP support by default in JitsiMeetActivity 2019-03-27 17:39:09 +01:00
Saúl Ibarra Corretgé
61ed459971 android: add JitsiMeetActivity.launch helper methods
They greatly simplify starting a JitsiMeetActivity by encapsulating the creation
of the Intent adn extras placement.

In order to make this possible JitsiMeetConferenceOptions now implements
Parcelable so it can be serialized and passed around when creating an Intent.
2019-03-27 17:39:09 +01:00
Saúl Ibarra Corretgé
c30a4a0aa6 android: make Amplitude and Dropbox modules package private 2019-03-27 17:39:09 +01:00
paweldomas
e839684ae9 fix(base/conference): tracks not added to the conference
If tracks are created while the conference is in the 'joining' state
they will never be added.
2019-03-27 10:06:59 +01:00
Saúl Ibarra Corretgé
15c5a2339b android: fix getting permission request results
Now that we have both a Fragment and an Activity there are lifecycle methods
that overlap. If a Fragment requests permission by calling requestPermissions
then the result handler will be called on itself. React Native's permissions
module, however, calls ActivityCompat.requestPermissions on the Activity, thus
we need to handle the results at the Activity level and not at the Fragment
level.
2019-03-26 11:56:14 -05:00
virtuacoplenny
d7e112aaf0 fix(display-name): do not default name to placeholder name (#4027)
* ref(display-name): do not pass in display name

The component gets the state itself from redux.

* fix(display-name): do not default name to placeholder name

The web display name component supports inline editing of
the name. Problems can occur when the displayed name
differs from the actual saved name, because participants
without a display name, including the local user, have
a different, default display name displayed. So when
editing starts, the input field is populated with the
default name. To workaround such while supporting fetching
the display name using mapStateToProps, pass in both the
name which should be shown and the name value saved in
settings.

* ref(display-name): rename methods
2019-03-26 09:34:02 -07:00
Saúl Ibarra Corretgé
24339b2461 ios: update Podfile.lock 2019-03-26 13:47:57 +01:00
Bettenbuk Zoltan
5b02c575f7 eslint-config-jitsi#1.0.0 2019-03-26 13:35:02 +01:00
Mayur Shah
1f8904a95b deps: react-native@0.59.2 2019-03-26 10:53:50 +01:00
Saúl Ibarra Corretgé
50268a08a0 ios: ensure the git tree is clean when / after building 2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
985385f364 ios: update fastlane Fastfile 2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
f662edd135 ios: don't bundle a dummy GoogleService-Info.plist file
It complicates automated builds.
2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
7ebcf69937 android: add fastlane integration 2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
40364ae269 misc: update gitignore 2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
030af37668 android: generate versionCode automatically
It's a number whichb must be ever increasing with each build submitted to the
store.

Automate its value by using the number of seconds since 1st of January 2019.
That should be enough for ~680 years.
2019-03-25 19:08:12 +01:00
Saúl Ibarra Corretgé
e29bc4bbb6 deps: update react-native-callstats to version 3.58.2 2019-03-25 14:56:52 +01:00
Bettenbuk Zoltan
13212a5980 [RN] Replace chat modal with SlidingView 2019-03-25 14:52:43 +01:00
Bettenbuk Zoltan
2a5adfc601 Remove some Flow annotations 2019-03-25 13:53:08 +01:00
paweldomas
19e8e8710a fix(Android/ConnectionService): do not display the address
Turns out that on Samsung phones the calls placed with
the ConnectionService appear in the calls log as weird long numbers.
The system mangles the address we give it ("sip:meet.jit.si/something")
into this weird long number and the call to request.getAddress() returns
that. Turn off the presentation as neither this number nor our address
makes sense. This way the call appears as from "Unknown" caller in call
history which is still not perfect, but better than the random number.

Note that other phones will preserve the originally passed address value
(tested on One Plus 5).
2019-03-25 09:24:33 +01:00
paweldomas
3b24124d57 fix(Android/ConnectionService): mic not working
Turns out the microphone will not work on some devices when starting in
"audio only", because the audio mode is not set to the MODE_IN_COMMUNICATION,
but to the MODE_IN_CALL. Calling setAudioModeIsVoip(true) makes
the system adjust to MODE_IN_COMMUNICATION and the mic works fine.
2019-03-25 09:24:33 +01:00
damencho
6894de00cc Fixes a typo of getting default number. 2019-03-23 09:59:25 +00:00
paweldomas
6d0b6bee85 ref(AudioModeModule): check 1 method to enable ConnectionService 2019-03-22 09:17:14 +01:00
virtuacoplenny
ac02a17943 feat(notifications): provide a way to turn off sticky notifications (#4010) 2019-03-21 14:06:33 -07:00
paweldomas
043d4db314 fix(NotificationsContainer.native): flow error 2019-03-21 17:09:56 +01:00
Saúl Ibarra Corretgé
6a919916d3 ios: pin all pod dependencies 2019-03-21 16:57:58 +01:00
Saúl Ibarra Corretgé
1de4897a6b ios: xcode project change shenanigans
Signing wouldn't work, disabling it and enabling it again created these changes.
Oh well!
2019-03-21 16:29:18 +01:00
paweldomas
0175690a2b ref(mobile): display only the topmost notification
Only one notification will be displayed at a time on mobile.
2019-03-21 15:47:14 +01:00
paweldomas
c7979a3944 feat(mobile): add 1 liner notifications
Adds 1 liner notifications to mobile. Only the title is displayed. In
case the title is missing there's a fallback to the description.
2019-03-21 15:47:14 +01:00
paweldomas
15fd27543a ref(Conference): extract AbstractConference 2019-03-21 15:47:14 +01:00
paweldomas
64f8a8d700 fix(AbstractNotificationsContainer): broken timeouts chain
If user dismisses the not topmost notification the timeout will be
cleared and a new one will not be set, because the top notification
remained the same (see the if at line 90).
2019-03-21 15:47:14 +01:00
paweldomas
95f684da2f fix(AbstractNotificationsContainer): dismiss timeout not always set
The docs of 'componentDidUpdate' say that it's not called for the
initial render. If the component is added to the DOM with 1 notification
already, then the update will not happen and timeout will never be set
which will effectively break the timeouts chain.
2019-03-21 15:47:14 +01:00
paweldomas
f3f8dc2072 ref: move participant joined notification to the middleware 2019-03-21 15:47:14 +01:00
Saúl Ibarra Corretgé
08efc46f21 android: fix crash in debug mode 2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
e32336b96f android: run the React packager when running from AS
When running the app from Android Studio the React packager is not automatically
started. In vanilla RN projects this is done by the "react-native run-android"
command, but often times it is desired to run from Android Studio.

This fixes that by starting the packager from Gradle.
2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
c91880859b android: fix gradle warning 2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
cff78d7a83 android: disable delta updates
It's enabled by default, but marked as experimental (uh?!). It creates trouble
as sometimes the packager goes bananas. Disable them until further notice, our
bundle is not that large anyway.
2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
49a0c03ff0 ios: fix deprecation warning
NSURLConnection sendSynchronousRequest is deprecated since iOS 9. Replace the
method by whjat's currently on RN master, which implements a modern alternative.
2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
2c592f61c3 android: enable 64bit builds 2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
c025c7e132 flow: tame the beast
🔥🔥🔥
2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
278d3a163b flow: update type definitions 2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
0e92e73789 chore: use strings as action types
Using anything non-serializable for action types is discouraged:
https://redux.js.org/faq/actions#actions

In fact, this is the Flow definition for dispatching actions:

declare export type DispatchAPI<A> = (action: A) => A;
declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;

Note how the `type` field is defined as a subtype of string, which Symbol isn’t.
2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
75527e01dd deps: update lib-jitsi-meet 2019-03-21 14:47:55 +01:00
Saúl Ibarra Corretgé
b53a034aaf deps: update React Native to version 0.59
This new version comes with an updated JSC runtime, so we no longer need to
depend on the updated version ourselves.
2019-03-21 14:47:55 +01:00
paweldomas
4d1c0cf219 fix eslint error 2019-03-19 21:59:45 +01:00
virtuacoplenny
a667c9bff2 ref: js-utils for random and room name generator (#3975) 2019-03-19 10:35:36 -07:00
Damien Fetis
e652117571 Remove the boolean conversion of authLogin string to display the string value instead of 'true'. (#3995) 2019-03-19 08:55:14 -07:00
Hristo Terezov
a6719896a2 fix(recording): Respect the selected recording service. 2019-03-15 20:12:25 +00:00
damencho
f5a7e0bccb Adds provider name to fix welcomepage text.
* Removes unused ADD_PEOPLE_APP_NAME
* Moves deep-link header background and logo size as variables.
* Fixes more numbers page space in the header.
* Fixes left padding on deep-linking mobile page.
2019-03-15 11:24:18 +00:00
damencho
f94db0da2c Adjust some paths to respect base. 2019-03-14 11:22:37 +00:00
paweldomas
460593a93e chrome: bump LJM to 74f48e168eec4c05fd8600812cc00e6e34e9ab90
Required for the Spot's TURN changes to work
2019-03-13 14:25:19 -05:00
paweldomas
19a27e75bd feat(spot): pass JitsiConnection to ProxyConnectionService to get TURN 2019-03-13 14:25:19 -05:00
Hristo Terezov
cb8e9eed5e feat(subject): UI 2019-03-12 23:03:58 +00:00
Saúl Ibarra Corretgé
2715e81f1d rn: add more SDK documentation 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
f941f15def ios: remove Jitsi Meet specific defaults
The app should always provide them.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
7712c6913c android: make ReactInstanceManagerHolder.emitEvent return void 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
45b6a8b5d5 android: throw if a unsupported type makes it to the props Bundle 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
26ca0e6630 android: throw if the overlsay permission is not granted in Debug mode 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
7978f9f5f4 misc: update .gitignore 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
d39290f9fa rn: refactor conference events
Consolidate all failure cases into a single one: CONFERENCE_TERMINATED. If the
conference ended gracefully no error indicator will be present, otherwise there
will be.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
f696a6dbe2 ios: update SDK documentation 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
bf3bcd65d6 android: add JitsiMeetActivity
It renders a single JitsiMeetFragment which holds the JitsiMeetView view.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
a7018970ca android: update SDK documentation 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
20edb7c279 android: make onExternalAPIEvent protected 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
59b00d022b android: don't proxy enterPictureInPicture in JitsiMeetFragment 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
53722fd2e6 android: remove ReactContextUtils
In practice, we are never going to be in a position where we don't have a
ReactContext but we do have some React Native code running. So let's not expect
the impossible.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
54bab793e5 android: remove JitsiMeetViewAdapter
It was never used and typicallt the Activity / Fragment holding the
JitsiMeetView object will be the listener.

In addition, once we refactor the events they will be reduced into far fewer.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
975ff9c83d rn: support passing serverURL and room to URL object
That's what the SDK passes now, if the room URL is not absolute.
2019-03-12 16:55:28 +01:00
paweldomas
5b3e8a9b5e android: introduce JitsiMeetConferenceOptions
Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org>
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
aedcfba263 ios: introduce JitsiMeetConferenceOptions 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
b97cb3509a rn: document externalAPIScope prop 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
7d8ea85ea0 rn: start removing defaultURL 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
e4c3e15791 rn: simplified code
There is no need for AbstractApp to require some getWindowLocation function.
It's only used in one place and we even polyfill it on mobile.

Thus replace it's usage with more specific functions.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
56135bd085 android: add initial implementation of join / leave 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
549b495d16 ios: add initial implementation of join / leave 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
f3abca6462 ios: add ability to control deep / universal linking
Since the SDK may be embedded with other apps, we need to recognize our custom
URL scheme and universal links in order to tell the user if we will process the
request or not.

Make them configurable with sane defaults.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
405905be82 rn: raise SDK version 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
468b02b812 ios: adjust to latest Swift syntax 2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
3fa5aed950 rn: drop deep / universal links handling from JS
It's now all handled in the SDK an we'll get the new URLs via props.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
90803c8ff6 android: SDK v2 pass one
Add JitsiMeetFragment and refactor the app to use it.
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
dbc88b972e ios: SDK v2 pass one
- cleanup
- API simplification (single loadURL method)
- JitsiMeet singleton for linking helpers and globals
- Linking moved to app
2019-03-12 16:55:28 +01:00
Saúl Ibarra Corretgé
1c47720a08 misc: ignore build artifacts 2019-03-12 16:55:28 +01:00
Hristo Terezov
59fc3642a6 feat(amplitude): add mobile implementation 2019-03-12 16:48:08 +01:00
Saúl Ibarra Corretgé
19b4b92150 deps: update lib-jitsi-meet 2019-03-12 16:48:08 +01:00
Bettenbuk Zoltan
8400d01d75 [RN] Add color scheme support to dialog buttons 2019-03-12 12:36:15 +01:00
Bettenbuk Zoltan
d04068344a [RN] Make header button same size as header label 2019-03-12 12:36:15 +01:00
Bettenbuk Zoltan
55a971c0fd [RN] Add color scheme support to header 2019-03-12 12:36:15 +01:00
Bettenbuk Zoltan
20c1b1cfae [RN] Wrap PagedList navigator with SafeAreaView 2019-03-12 12:36:15 +01:00
Bettenbuk Zoltan
ecb44b6ab4 [RN] Make the header more compact 2019-03-12 12:36:15 +01:00
Jose Angel Gonzalez
039805eba3 fix(android-sdk): Recover audio device if the OS changes it 2019-03-12 09:55:51 +01:00
virtuacoplenny
22277ad799 feat(api): add notification for when filmstrip gets toggled (#3974) 2019-03-11 11:17:28 -07:00
Hristo Terezov
2af1e8da95 fix(remote-video-menu): Icon position 2019-03-11 17:36:58 +00:00
Дамян Минков
12d0aef686 Updates recording dialog. (#3953)
* Updates recording dialog.

* Update config.js doc.

* Adds comment and make a check more intuitive.

* Changes of using enum for recording types.
2019-03-11 09:17:21 -07:00
Hristo Terezov
f439ad2999 feat(popover): Make the popover menus customizable. 2019-03-11 16:04:20 +00:00
Leonard Kim
81d4f694b7 fix(chat): prevent empty messages 2019-03-09 12:09:29 +01:00
Saúl Ibarra Corretgé
c737d46d90 android: update gradle plugin version 2019-03-08 17:24:49 +01:00
Saúl Ibarra Corretgé
3f2a559d64 rn: now working on version 19.1 2019-03-08 14:04:03 +01:00
Saúl Ibarra Corretgé
bdb3099073 android: fix running on Android < M
The android.telecom.CallAudioState class was only added in API level 23 (Android
M), so make sure we don't import it in lower versioned devices.
2019-03-08 11:37:25 +01:00
damencho
b3a05db286 Update dropbox redirect uri to always use the main domain static page. 2019-03-07 15:39:16 +00:00
virtuacoplenny
08f2edf350 feat(screenshare): emit source type when starting screenshare (#3959)
* feat(screenshare): emit source type when starting screenshare

* squash: update doc
2019-03-06 21:46:17 -08:00
Bettenbuk Zoltan
98c7430b6f [RN] Replace red screen with dialog 2019-03-07 01:09:03 +01:00
Bettenbuk Zoltan
ebdcbe122a Change dialog button property keys 2019-03-07 01:09:03 +01:00
virtuacoplenny
31c1034be7 deps(chore): bump lib-jitsi-meet to e398584 (#3958)
Bring over two fixes for spot. One is for
identifying the screenshare type when using
a camera for screenshare or when using a proxy
stream. Also bring in a fix to avoid a js error
in chrome ios.
2019-03-06 15:39:01 -08:00
Hristo Terezov
a9d82a79ea fix(toolbar): Move buttons to overflow menu when the space isn't enough 2019-03-06 17:51:31 +00:00
Bettenbuk Zoltan
27e1f5a1bc [RN] Avoid adding undefined in the invite 2019-03-06 16:52:22 +01:00
virtuacoplenny
dbedee5e22 chore(deps): update to lib 320919e (#3951) 2019-03-05 17:02:22 -08:00
Дамян Минков
636c63397b Adds integrations doc. (#3929)
* Adds integrations doc.

Google, Microsoft and Dropbox for now.

* Updates doc.
2019-02-28 09:09:09 +00:00
damencho
67e7994e36 Removes unused config. 2019-02-27 16:45:26 +00:00
damencho
40f03fedc2 Replaces emoji flags with flag from a png.
Seems like windows does not have emojis for flags.
2019-02-27 16:45:26 +00:00
Hristo Terezov
55149670da fix(dropbox-auth): In Electron. 2019-02-27 16:12:54 +00:00
Gabriel-Tiberiu Imre-Lucaci
5739e1deaa feat(external_api): notify when api is disposed 2019-02-27 14:39:04 +00:00
Bettenbuk Zoltan
b6e2701991 [RN] Add invite screen 2019-02-27 13:26:21 +01:00
Bettenbuk Zoltan
38b1be1291 [RN] Extract AvatarListItem 2019-02-27 13:26:21 +01:00
damencho
555f8b3a99 Fixes toll free position. 2019-02-26 17:08:56 +00:00
Дамян Минков
ea4d49f2a0 Adds new format of phoneList service and re-design dial in numbers page. (#3903)
* Adds new format of phoneList service and re-design dial in numbers page.

Adds flags and country names (with translations) for the numbers if using the new format.

* Fixes tests and fixes get default number.

* Updates swagger with new format.

* Moves html back yo table.

Fixes displaying on mobile and also the tel: URI generation. The tel: URI is tested on Android and iOS and seems to work (Android was not interpreting 'p', but both seems to like ',').

* Fixes a wrong return statement.

* Small fixes.
2019-02-26 13:32:46 +00:00
fossterer
d7eea8abbc Added links related to NAT config in a new FAQ doc 2019-02-26 09:53:48 +00:00
paweldomas
1b8ef9a05a chore: update LJM to 5a9fc76739bcf0bed50676c7be160f688f3a19b5 2019-02-25 14:16:05 -06:00
Emil Ivov
ac7311cb52 Merge pull request #3920 from jitsi/emcho-patch-3
Update api.md
2019-02-23 17:04:13 +00:00
Emil Ivov
f498c8d402 Update api.md 2019-02-23 16:39:27 +00:00
Leonard Kim
8c8b09878c fix(screensharing): do not sync camera device id on start
When a conference is started, the currently used
camera device id is saved. I believe this is happening
because lib-jitsi-meet does not use exact device id
mathcing when calling getUserMedia, so it's possibl
to request camera A but get camera B back because
camera A is not available. When config.startScreenSharing
is true, the syncing occurs and saves the desktop
source id. So when screensharing is stopped, jitsi-meet
requests that desktop source id instead of the preferred
camera.
2019-02-22 10:50:43 -06:00
Leonard Kim
03f8d8b51a fix(external_api): detect and skip params for hash routers 2019-02-22 10:34:49 -06:00
Hristo Terezov
32083fc44d fix(connection-quality): Bring back the icon. 2019-02-21 18:49:49 +00:00
Hristo Terezov
c4361ed7da feat(css): configurable Videolayot and overflow menu. 2019-02-21 18:49:49 +00:00
Hristo Terezov
a95d38a0f4 feat(thumbnail-indicators): Configurable icon sizes. 2019-02-21 18:49:49 +00:00
Hristo Terezov
981600a999 fix(toolbar): button distance and colors. 2019-02-21 18:49:49 +00:00
Hristo Terezov
0d674001d2 chore(icons): Cleanup 2019-02-21 16:18:01 +00:00
Hristo Terezov
f7b930409b feat(toolbox): Redesign. 2019-02-21 00:42:13 +00:00
paweldomas
4312512d2f feat(external API): add feedbackPromptDisplayed event
Adds a new event fired when Jitsi Meet shows the feedback prompt.
2019-02-20 11:59:46 -06:00
Saúl Ibarra Corretgé
b7b2745dae ios: update podfile for CocoaPods 1.6.0 2019-02-19 19:13:07 +01:00
damencho
fc129d9849 Adds setting subject and adding event on receiving such change. 2019-02-19 13:22:27 +00:00
paweldomas
54c36198d0 fix(mobile/call-integration): cleanup if leave takes too long
The conference disconnection process is asynchronous which means there's
no guarantee that there will be CONFERENCE_LEFT event for the old
conference, before the next conference is joined. Because of that we can
end up with two simultaneous calls on the native side which is not
always supported. End the call on CONFERENCE_WILL_LEAVE to fix this
corner case.
2019-02-16 17:10:04 -08:00
virtuacoplenny
16b440bbd0 chore(deps): upgrade webpack-dev-server 3.1.10 to 3.1.14 (#3900) 2019-02-15 09:03:05 -08:00
Bettenbuk Zoltan
d56d01cebb [Android] Change the type of the color scheme 2019-02-15 13:33:38 +01:00
Leonard Kim
d872728966 fix(recording): support passing styles in firefox
Using an array of styles in Firefox causes an error
that triggers jitsi-meet to redirect to a static page.
2019-02-15 10:11:26 +01:00
Saúl Ibarra Corretgé
877cea59e7 ios: don't configure CXProvider if CallKit is disabled 2019-02-14 13:16:31 -08:00
Saúl Ibarra Corretgé
a4b3f8ade6 android: don't build javadocs when publishing react-native plugins
They generate a bunch of harmless yet confusing error messages and they are not
really useful.
2019-02-14 13:16:04 -08:00
damencho
2ac5d136dc Detects nginx-extras package. Fixes #3891. 2019-02-14 14:05:27 +00:00
Saúl Ibarra Corretgé
7e320a5d38 ios: refactor AudioMode to use RTCAudioSession
RTCAudioSession is a thin wrapper around AVAudioSession provided by the WebRTC
framework. It makes some use-cases easier, and leads us closer to manual audio
unit management, which we will likely need in the near future.
2019-02-14 10:20:45 +01:00
Saúl Ibarra Corretgé
7289e59ca9 audio-mode: don't change the mode unless there is no active conference
If a new conference is joined and as a result the current one is terminated,
don't ever attempt to set the audio mode.
2019-02-14 10:20:45 +01:00
Saúl Ibarra Corretgé
e1b989e99b ios: make sure our CXProvider is invalidated when CallKit is disabled 2019-02-14 10:20:45 +01:00
Saúl Ibarra Corretgé
070a34e30d ios: enable proximity sensor on the main thread
Fixes this issue:

Main Thread Checker: UI API called on a background thread: -[UIApplication setExpectsFaceContact:inLandscape:]
PID: 25442, TID: 10886619, Thread name: (none), Queue name: com.facebook.react.ProximityQueue, QoS: 0
Backtrace:
4   JitsiMeet                           0x000000010a0eaadc -[Proximity setEnabled:] + 64
5   CoreFoundation                      0x00000001fea34630 <redacted> + 144
6   CoreFoundation                      0x00000001fe912450 <redacted> + 292
7   CoreFoundation                      0x00000001fe913034 <redacted> + 60
8   JitsiMeet                           0x000000010a4e08e8 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 492
9   JitsiMeet                           0x000000010a4e7a10 _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicE + 248
10  JitsiMeet                           0x000000010a4e776c ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 88
11  libdispatch.dylib                   0x000000010b943824 _dispatch_call_block_and_release + 24
12  libdispatch.dylib                   0x000000010b944dc8 _dispatch_client_callout + 16
13  libdispatch.dylib                   0x000000010b94ce6c _dispatch_lane_serial_drain + 720
14  libdispatch.dylib                   0x000000010b94db60 _dispatch_lane_invoke + 460
15  libdispatch.dylib                   0x000000010b957bfc _dispatch_workloop_worker_thread + 1220
16  libsystem_pthread.dylib             0x00000001fe6490dc _pthread_wqthread + 312
17  libsystem_pthread.dylib             0x00000001fe64bcec start_wqthread + 4
2019-02-14 10:20:45 +01:00
Aaron van Meerten
e144c2fb3e Merge pull request #3886 from jitsi/invitation-post-application-json
invite post to use application/JSON
2019-02-13 16:42:47 -06:00
Aaron van Meerten
1a5e2763c1 use fetch syntax from virtuacoplenny 2019-02-13 16:23:26 -06:00
Saúl Ibarra Corretgé
a4121fef36 deps: update package-lock.json for npm 6.7.0 2019-02-13 21:59:38 +01:00
Aaron van Meerten
76638f524d invite post to use application/JSON
changed to .ajax from .post to allow content type to be set
2019-02-12 16:28:33 -06:00
Saúl Ibarra Corretgé
8ea693616d color-scheme: fix React warning
A reducer must always return a state or null to ignore it. When the color scheme
is undefined we should return the previous state.
2019-02-12 20:22:28 +01:00
Дамян Минков
2442ef80b0 Adds Afrikaans to languages. (#3884) 2019-02-12 13:18:56 +00:00
Saúl Ibarra Corretgé
87f171caa4 feat(ScreenSharing): use sane defaults
Both Chrome and Firefox can work without extensions now, so it no longer makes
sense to default to disabling it in Chrome. Moreover, rely on the fact that
undefined is falsey so no actual config needs to be provided.
2019-02-12 10:00:23 +00:00
Bettenbuk Zoltan
e094b6516a [RN] Add color scheme support - Components 2019-02-08 11:43:21 +01:00
Bettenbuk Zoltan
2941f5dde4 [RN] Add color scheme support - JS 2019-02-08 11:43:21 +01:00
Bettenbuk Zoltan
eec7a1b628 [RN] Add color scheme support - native 2019-02-08 11:43:21 +01:00
Saúl Ibarra Corretgé
5f7a515610 rn: drop {AddPeople,Invite}Controller
We are going to implement the invite dialog *inside* the SDK, so there is no
need to have all this machinery anymore.
2019-02-08 09:02:15 +01:00
virtuacoplenny
b7133f5717 fix(large-video): do not show avatar if no url (#3871)
* fix(large-video): do not show avatar if no url

By default the large video dominant speaker avatar
has an empty src, which will result in a broken
image displaying. There is also disconnect with
non-react code trying to set an undefined src.
To prevent such until local avatar generation
work is done in the future, just don't show the
avatar.

* fix(conference): set the room instance earlier

Set the room instance on APP.conference before triggering
a redux update of the conference being set,, because
middleware can then fire and call methods on APP.conference
that depend on the room being set.

* get local participant directly from store instead of from global
2019-02-06 19:19:02 -08:00
virtuacoplenny
f77e1dc591 fix(speaker-levels): convert calculation from string to float (#3870) 2019-02-06 10:49:20 -08:00
virtuacoplenny
4d817fc6c2 fix(home): fix plus button alignment for calendar events (#3869) 2019-02-06 09:33:44 -08:00
Paweł Domas
b8a7037959 Merge pull request #3866 from jitsi/ice_failed_notification
chore(deps): update LJM to get ICE failed notifications
2019-02-06 09:00:55 -06:00
Saúl Ibarra Corretgé
6f95c50d6e Revert "misc: make URL protocol matching regexes non-greedy"
This reverts commit 7c911eca96.

I'm dumb. We need global mode because otherwise lastIndex is not updated in the
regex object, which we rely upon, so this is intentional.
2019-02-06 15:49:44 +01:00
Bettenbuk Zoltan
9f3ef43daa [RN] Add conference navigation bar 2019-02-06 14:27:25 +01:00
Bettenbuk Zoltan
46713cab3b Move Labels to Conference 2019-02-06 14:27:25 +01:00
Bettenbuk Zoltan
8065cc0348 [RN] Remove unused code 2019-02-06 14:27:25 +01:00
Bettenbuk Zoltan
045a2d6aca Extract isToolboxVisible function 2019-02-06 14:27:25 +01:00
Bettenbuk Zoltan
d7d9bc4eeb Reorganize conference feature files 2019-02-06 14:27:25 +01:00
Saúl Ibarra Corretgé
33db155eb9 ios: don't override AVAudioSession category and mode in default state
When we are in the default state (ie, not in a meeting) we shouldn't override
the AVAudioSession category and mode. It's a singleton and we might be bothering
other components of the host app which use it.
2019-02-06 10:17:39 +01:00
paweldomas
1cfd6164f5 chore(deps): update LJM to get ICE failed notifications
Updates LJM to 2e1436e20d4d8fb6020497a87b2714dff38a6c86 which includes
the ICE failed notification logic.
2019-02-05 21:45:02 -06:00
bgrozev
d9cf33b4c4 fix: Shows the "turn" indication for non-p2p connections. (#3865) 2019-02-05 23:13:59 +00:00
virtuacoplenny
2b56822a41 fix(ie11): redirect to recommended browsers page (#3853) 2019-02-05 08:26:27 -08:00
damencho
c34fee4305 Commit from translate.jitsi.org by user damencho.: 500 of 583 strings translated (0 fuzzy). 2019-02-05 13:36:52 +00:00
jitsi-pootle
ddc8a670f9 New files added from translate.jitsi.org based on templates 2019-02-05 10:09:34 +00:00
Saúl Ibarra Corretgé
7c911eca96 misc: make URL protocol matching regexes non-greedy 2019-02-02 21:21:21 +01:00
Saúl Ibarra Corretgé
f3c83f6e6d rn: finally fix Android deep-linking
The URL cannot end in a /.
2019-02-02 21:21:21 +01:00
Aaron van Meerten
b9a14acd3c adds conference to lookup of dial in numbers (#3859) 2019-02-01 19:10:34 -08:00
Aaron van Meerten
c998dbb47e Merge pull request #3858 from jmacelroy/master
Normalizing subdomain when checking JWTs; similar to room.
2019-02-01 13:53:39 -06:00
jmacelroy
573cc64fcd Normalizing subdomain when checking JWTs; similar to room. 2019-02-01 13:19:33 -06:00
Saúl Ibarra Corretgé
53c232fd76 misc: fix off-by-one error
e729f0948c contained an off-by-one error:

URI_PROTOCOL_PATTERN includes the colon, so after applyting the regex we are
left with something like '//example.com/room' thus we only need to strip the
first 2 characters.

🤦
2019-02-01 15:22:17 +01:00
paweldomas
3b6e34e96b fix(JitsiMeetLogStorage): do not log whole message
The logMessage can be very long. Probably only it's length could be
important to why sendApplicationLog has failed. Stringify the error
though.
2019-02-01 10:34:03 +01:00
paweldomas
8fe5814831 ref(JitsiMeetLogStorage): move to base/logging 2019-02-01 10:34:03 +01:00
paweldomas
2305effa5c feat(RN): enable log collector on mobile
Stores the Logger.LogCollector instance in base/logging state instead of
global APP variable and enables it on mobile.
2019-02-01 10:34:03 +01:00
Saúl Ibarra Corretgé
e729f0948c android: fix deep-linking from web
Looks like custom-scheme links no longer work in all browsers. They do on
Firefox, but the don't in Chrome and other default browsers.

So, switch to intent links on Android:
https://developer.chrome.com/multidevice/android/intents

Example:
```
<a href="intent://meet.jit.si/test123#Intent;scheme=org.jitsi.meet;package=org.jitsi.meet;end">Open Jitsi Meet</a>
```
2019-02-01 09:30:09 +01:00
virtuacoplenny
6f57d58dd9 fix(participant): update local name only on explicit update (#3849)
Dominant speaker events can trigger local participant updates
without a display name. Do not update the name unless there
is an explicit update in the action.
2019-01-31 15:46:34 -08:00
paweldomas
d0858b95b8 update lib-jitsi-meet 2019-01-31 13:50:51 -06:00
Saúl Ibarra Corretgé
5afb057387 rn: polyfill callstats
Instead of bundling it in lib-jitsi-meet, which unnecessarily increases
lib-jitsi-meet's bundle size, polyfill it here so it's available in the global
scope, just like the web does.
2019-01-31 13:50:51 -06:00
Saúl Ibarra Corretgé
5d86e3b674 deps: update react-native-callstats to 3.57.1 2019-01-31 13:50:51 -06:00
Paweł Domas
f8294fb312 android: add ConnectionService
* feat(Android): implement ConnectionService

Adds basic integration with Android's ConnectionService by implementing
the outgoing call scenario.

* ref(callkit): rename _SET_CALLKIT_SUBSCRIPTIONS

* ref(callkit): move feature to call-integration directory

* feat(ConnectionService): synchronize video state

* ref(AudioMode): use ConnectionService on API >= 26

Not ready yet - few details left mentioned in the FIXMEs

* feat(ConnectionService): add debug logs

Adds logs to trace the calls.

* fix(ConnectionService): leaking ConnectionImpl instances

Turns out there is no callback fired back from the JavaScript side after
the disconnect or abort event is sent from the native. The connection
must be marked as disconnected and removed immediately.

* feat(ConnectionService): handle onCreateOutgoingConnectionFailed

* ref(ConnectionService): merge classes and move to the sdk package

* feat(CallIntegration): show Alert if outgoing call fails

* fix(ConnectionService): alternatively get call UUID from the account

Some Android flavours (or versions ?) do copy over extras to
the onCreateOutgoingConnectionFailed callback. But the call UUID is also
set as the PhoneAccount's label, so eventually it should be available
there.

* ref(ConnectionService): use call UUID as PhoneAccount ID.

The extra is not reliable on some custom Android flavours. It also makes
sense to use unique id for the account instead of the URL given that
it's created on the per call basis.

* fix(ConnectionService): abort the call when hold is requested

Turns out Android P can sometimes request HOLD even though there's no
HOLD capability added to the connection (what!?), so just abort the call
in that case.

* fix(ConnectionService): unregister account on call failure

Unregister the PhoneAccount onCreateOutgoingConnectionFailed. That's
before the ConnectionImpl instance is created which is normally
responsible for doing that.

* fix(AudioModeModule): make package private and run on the audio thread

* address other review comments
2019-01-31 17:20:53 +01:00
Aaron van Meerten
3ad99e24cf Merge pull request #3840 from jitsi/prosody-token-wildcard-subdomain
supports a '*' in the sub claim to allow access to any room
2019-01-29 13:48:33 -06:00
Saúl Ibarra Corretgé
14990a427a rn: set version to 19.0.0
This marks our switch to CalVer: http://calver.org/

Major: year
Minor: release number
Patch: build (in case we need to retry)
2019-01-29 17:25:00 +01:00
virtuacoplenny
a1383bf730 fix(local-recording): allow config override to enable (#3615)
* fix(local-recording): allow config override to enable

Config overrides are not set until some time after
APP_WILL_MOUNT has completed and not in the same execution
context as when APP_WILL_MOUNT is called. So instead
choose recording controller initialization at a later time.
The time chosen is after conference join because the
controller needs the conference instance to work.

* remove redundant conditional check
2019-01-29 08:22:50 -08:00
Saúl Ibarra Corretgé
9bfe54475b android: read Dropbox API from main package resources
This makes Dropbox work on apps using the SDK without needing to build it
themselves.
2019-01-29 15:39:20 +01:00
Saúl Ibarra Corretgé
d5a43426ed android: don't read Dropbox key from iOS files 2019-01-29 15:39:20 +01:00
Saúl Ibarra Corretgé
612028ce3c rn: fix showing Dropbox controls when recording
- remove unneeded dialog (it's taken care of by StartRecordingDialogContent)
- pass correct props so integrations (Dropbox) show up
2019-01-29 15:39:20 +01:00
Saúl Ibarra Corretgé
3cec4989fd ios: enable recording in dev mode
While Apple doesn't want to allow us to enable Dropbox, it's good to have it
available for testing.
2019-01-29 15:39:20 +01:00
Saúl Ibarra Corretgé
77f220753f ios: dynamically load Dropbox API key
Load it at build time from a "dropbox.key" file. The file should contain the API
key in a single line.
2019-01-29 15:39:20 +01:00
Aaron van Meerten
13165990fc supports a '*' in the sub claim to allow access to any room 2019-01-28 16:19:43 -06:00
Bettenbuk Zoltan
63ff0c27a9 [RN] Add display name to on-stage participant 2019-01-28 18:34:12 +01:00
Bettenbuk Zoltan
f2b2cfda44 Extract shouldRenderParticipantVideo from ParticipantView 2019-01-28 18:34:12 +01:00
Leonard Kim
1b59b21fa8 chore(deps): bump lib to get wireless screensharing service 2019-01-27 17:55:01 +01:00
virtuacoplenny
6241172af8 feat(screenshare): support remote wireless screensharing (#3809)
* feat(screenshare): support remote wireless screensharing

- Pass events to the ProxyConnectionService so it can
  handle establishing a peer connection so a remote
  participant, not in the conference, can send a
  video stream to the local participant to use as a
  local desktop stream.
- Modify the existing start screensharing flow to accept
  a desktop stream instead of always trying to create one.

* adjust ProxyConnectionService for lib review changes
2019-01-26 12:53:11 -08:00
Saúl Ibarra Corretgé
8e58ce7500 ios: re-enable live streaming on iOS 10
There was a missing delegate method call into RNGoogleSignIn, which fixed this.
2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
37d3625210 ios: fix Goggle Sign-In deep-lining 2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
111397d944 ios: style 2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
211b3b55b1 ios: simplify code 2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
8c0317cac0 ios: fix compilation warnings 2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
15c8f2b125 android: remove unused import 2019-01-25 11:06:35 +01:00
Saúl Ibarra Corretgé
349b1ff70e android: fix warning 2019-01-25 11:06:35 +01:00
Leonard Kim
244f206a87 chore(deps): bump lib for old conference listener cleanup 2019-01-25 09:19:10 +01:00
Bettenbuk Zoltan
82963b0aaf Add VSCode files to gitignore 2019-01-23 20:22:37 +01:00
paweldomas
92a412f814 chore(ios): update Podfile.lock 2019-01-23 17:04:41 +01:00
Guus der Kinderen
4b99caa1a9 Android SDK build instructions: add 'clean'
I'm ashamed to admit that I spent several _days_ chasing a bug that was already fixed. :( This obvious instruction would have been a time-saver.
2019-01-23 16:46:51 +01:00
Saúl Ibarra Corretgé
6190173ea7 misc: fixup MD format 2019-01-21 15:36:12 +01:00
Saúl Ibarra Corretgé
54df0f5d0f misc: add some more issue templates 2019-01-21 11:58:08 +01:00
damencho
4d440f5f64 Fixes showing video after waiting for owner. Fixes #3671. 2019-01-20 14:17:50 -08:00
virtuacoplenny
10624e87f5 ref(conference): change when the room reference is removed (#3808)
Delay removing the room reference. This is in case a
consumer of the API is attempting to submit feedback
after hangup but before redirecting to another page.
If the room reference is removed, feedback submission
will fail during this period.
2019-01-17 16:04:35 -08:00
Leonard Kim
7f29b47f3a chore(deps): update lib for camera-as-screenshare feature 2019-01-17 09:51:15 +01:00
Saúl Ibarra Corretgé
7c69308270 android: remove unused ProGuard rules file 2019-01-16 14:55:58 -06:00
Saúl Ibarra Corretgé
50b4212463 android: add missing ProGuard rules 2019-01-16 14:55:58 -06:00
Saúl Ibarra Corretgé
bb8fc8770a android: fix packager in debug mode in API 28
These values must match these ones in React Native:
5939d078a0/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java (L20-L22)
2019-01-16 14:55:12 -06:00
Bettenbuk Zoltan
79209535ea Centralise display name normalisation 2019-01-16 11:03:29 +01:00
Bettenbuk Zoltan
4bddae0bdb Remove default value from openDisplayNamePrompt action 2019-01-16 11:03:29 +01:00
Saúl Ibarra Corretgé
c203a452f7 ios: add initial Fastlane integration
Used for building and deploying builds to TestFlight and the App Store.
2019-01-16 11:01:42 +01:00
Saúl Ibarra Corretgé
515d2f11ce ios: set Google reverse client ID at build time
Read it from the GoogleService-Info.plist file and apply it into Info.plist.
2019-01-16 11:01:42 +01:00
Saúl Ibarra Corretgé
f7134722d0 ios: let the system reorder the file 2019-01-16 11:01:42 +01:00
Saúl Ibarra Corretgé
d8fa52fcaf ios: use a proper URL scheme placeholder
No caps are allowed, so this would trigger a rejection when uploading to
TestFlight.
2019-01-16 11:01:42 +01:00
Saúl Ibarra Corretgé
f7162c1500 rn: add some cleanup tasks when a conference ends / changes
- unpin participant (if the local one was pinned it would remain)
- close any dialog (except if authentication is pending)
2019-01-16 11:00:37 +01:00
virtuacoplenny
998db80db1 Merge pull request #3782 from virtuacoplenny/lenny/camera-as-ss
feat(screenshare): use camera as a screenshare source
2019-01-15 12:05:09 -08:00
Hristo Terezov
4575e7e119 fix(calendar): Remove logs with invalid calendar items. 2019-01-15 17:00:23 +01:00
Bettenbuk Zoltan
230b2b02fa Chat render improbement 2019-01-15 13:38:26 +01:00
Bettenbuk Zoltan
8a241ba2b7 [RN] Add chat functionality
Co-authored-by: DimaG <dgeorgiev06@gmail.com>
2019-01-15 11:33:12 +01:00
Bettenbuk Zoltan
82f714b608 Move display name handling into redux 2019-01-15 10:15:02 +01:00
Leonard Kim
8c9ba325ca fix(pinning): send a participant id on unpin
Analytics is erroring when unpinning because the logged
event sends null for the objectId. The objectId should
be the id of the person getting unpinned.
2019-01-15 09:58:45 +01:00
virtuacoplenny
693d4357a0 Merge pull request #3788 from virtuacoplenny/lenny/alpha-main
ref: alphabetize translation strings
2019-01-14 08:22:00 -08:00
Bettenbuk Zoltan
eef31d05cf [RN] Add an abstraction layer to Modal 2019-01-12 15:51:50 +01:00
Bettenbuk Zoltan
d7475a44e4 [RN] Extract header components for reuse 2019-01-12 15:51:50 +01:00
Leonard Kim
d09bfa7c0a ref: alphabetize translation strings 2019-01-11 15:33:01 -08:00
Leonard Kim
69dfa30142 feat(screenshare): use camera as a screenshare source
This feature is intended for spot. Spot can have an
HDMI -> usb adapter hooked up to it. In that case,
attempting to screenshare should use that adapter
as a screensharing source. Jitsi-Meet should pass
a configured screenshare source into lib-jitsi-meet
so it can be used as a source.
2019-01-11 09:52:53 -08:00
1365 changed files with 70723 additions and 35146 deletions

View File

@@ -2,22 +2,30 @@
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
node_modules/react-native/Libraries/react-native/React.js
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
node_modules/react-native/Libraries/react-native/React.js
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
; Ignore polyfills
.*/Libraries/polyfills/.*
node_modules/react-native/Libraries/polyfills/.*
; Ignore metro
.*/node_modules/metro/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/HMRLoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
; Ignore packages in node_modules which we (i.e. the jitsi-meet project) have
; seen to cause errors and we have chosen not to fix.
@@ -33,7 +41,6 @@
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
node_modules/react-native/flow-github/
[options]
emoji=true
@@ -41,6 +48,18 @@ emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
module.system=haste
module.system.haste.use_name_reducers=true
# get basename
@@ -53,8 +72,11 @@ module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/RNTester/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/IntegrationTests/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation.js
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
munge_underscores=true
@@ -65,22 +87,32 @@ suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.78.0
^0.104.0

View File

@@ -1,12 +1,13 @@
---
name: Bug Report
about: Before posting, please make sure you check https://community.jitsi.org
name: Bug report
about: Create a report to help us improve
---
*This Issue tracker is only for reporting bugs and tracking code related issues.*
Before posting, please make sure you check community.jitsi.org to see if the same or similar bugs have already been discussed. General questions, installation help, and feature requests can also be posted to community.jitsi.org.
Before posting, please make sure you check community.jitsi.org to see if the same or similar bugs have already been discussed.
General questions, installation help, and feature requests can also be posted to community.jitsi.org.
## Description
---

10
.github/ISSUE_TEMPLATE/2-help.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
name: Need help with Jitsi Meet?
about: Please ask it in our community at https://community.jitsi.org
---
If you have a question about Jitsi Meet that is not a bug report or feature
request, please post it in https://community.jitsi.org
Questions posted to this repository will be closed.

View File

@@ -0,0 +1,23 @@
---
name: "Feature request"
about: Suggest an idea for this project
---
<!--
Thank you for suggesting an idea to make Jitsi Meet better.
Please fill in as much of the template below as you're able.
Note that the ultimate decission for implementing features lies on the Jitsi team, not all feature requests shall be accepted.
-->
**Is your feature request related to a problem you are facing?**
Please describe the problem you are trying to solve.
**Describe the solution you'd like**
Please describe the desired behavior.
**Describe alternatives you've considered**
Please describe alternative solutions or features you have considered.

View File

@@ -0,0 +1,11 @@
---
name: Security issues
about: Please email security@jitsi.org
---
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.

16
.gitignore vendored
View File

@@ -35,6 +35,7 @@ xcuserdata
DerivedData
*.hmap
*.ipa
*.dSYM.zip
*.xcuserstate
project.xcworkspace
@@ -69,10 +70,23 @@ buck-out/
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
# Build artifacts
*.jsbundle
*.framework
android/app/debug
android/app/release
# precommit-hook
.jshintignore
.jshintrc
# VSCode files
android/.project
android/.settings/org.eclipse.buildship.core.prefs
# Secrets
android/app/dropbox.key
android/app/google-services.json
ios/app/dropbox.key
ios/app/GoogleService-Info.plist

View File

@@ -1,4 +1,6 @@
osx_image: xcode10
osx_image: xcode11.1
language: objective-c
script:
- "./ios/travis-ci/build-ipa.sh"
after_script:
- sleep 10

View File

@@ -13,7 +13,7 @@ Found a bug and know how to fix it? Great! Please read on.
## Contributor License Agreement
While the Jitsi projects are released under the
[Apache License 2.0](https://github.com/jitsi/jitsi-meet/blob/master/LICENSE), the copyright
holder and principal creator is [Atlassian](https://www.atlassian.com/). To
holder and principal creator is [8x8](https://www.8x8.com/). To
ensure that we can continue making these projects available under an Open Source license,
we need you to sign our Apache-based contributor
license agreement as either a [corporation](https://jitsi.org/ccla) or an

View File

@@ -3,6 +3,7 @@ CLEANCSS = ./node_modules/.bin/cleancss
DEPLOY_DIR = libs
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
LIBFLAC_DIR = node_modules/libflacjs/dist/min/
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
NODE_SASS = ./node_modules/.bin/node-sass
NPM = npm
OUTPUT_DIR = .
@@ -20,7 +21,7 @@ compile:
clean:
rm -fr $(BUILD_DIR)
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
deploy-init:
rm -fr $(DEPLOY_DIR)
@@ -45,8 +46,10 @@ deploy-appbundle:
$(OUTPUT_DIR)/analytics-ga.js \
$(BUILD_DIR)/analytics-ga.min.js \
$(BUILD_DIR)/analytics-ga.min.map \
$(BUILD_DIR)/analytics-amplitude.min.js \
$(BUILD_DIR)/analytics-amplitude.min.map \
$(BUILD_DIR)/video-blur-effect.min.js \
$(BUILD_DIR)/video-blur-effect.min.map \
$(BUILD_DIR)/rnnoise-processor.min.js \
$(BUILD_DIR)/rnnoise-processor.min.map \
$(DEPLOY_DIR)
deploy-lib-jitsi-meet:
@@ -63,6 +66,11 @@ deploy-libflac:
$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
$(DEPLOY_DIR)
deploy-rnnoise-binary:
cp \
$(RNNOISE_WASM_DIR)/rnnoise.wasm \
$(DEPLOY_DIR)
deploy-css:
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
@@ -71,7 +79,7 @@ deploy-css:
deploy-local:
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
dev: deploy-init deploy-css deploy-lib-jitsi-meet deploy-libflac
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac
$(WEBPACK_DEV_SERVER)
source-package:

114
README.md
View File

@@ -1,16 +1,16 @@
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](#security) and scalable video conferences. You can see Jitsi Meet in action [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](#security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
The Jitsi Meet client runs in your browser, without the need for installing anything on your computer. You can also try it out yourself at https://meet.jit.si .
The Jitsi Meet client runs in your browser, without installing anything on your computer. You can try it out at https://meet.jit.si .
Jitsi Meet allows for very efficient collaboration. It allows users to stream their desktop or only some windows. It also supports shared document editing with Etherpad.
Jitsi Meet allows very efficient collaboration. Users can stream their desktop or only some windows. It also supports shared document editing with Etherpad.
## Installation
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing the Jitsi Meet suite on your server and hosting your own conferencing service.
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing a Jitsi Meet suite on your server and hosting your own conferencing service.
Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we recommend following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
Installing Jitsi Meet is a simple experience. For Debian-based system, following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
@@ -31,82 +31,9 @@ You can get our mobile versions from here:
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
## Building the sources
## Development
Node.js >= 8 and npm >= 6 are required.
On Debian/Ubuntu systems, the required packages can be installed with:
```
sudo apt-get install npm nodejs
cd jitsi-meet
npm install
```
To build the Jitsi Meet application, just type
```
make
```
### Working with the library sources (lib-jitsi-meet)
By default the library is build from its git repository sources. The default dependency path in package.json is :
```json
"lib-jitsi-meet": "jitsi/lib-jitsi-meet",
```
To work with local copy you must change the path to:
```json
"lib-jitsi-meet": "file:///Users/name/local-lib-jitsi-meet-copy",
```
To make the project you must force it to take the sources as 'npm update' will not do it.
```
npm install lib-jitsi-meet --force && make
```
Or if you are making only changes to the library:
```
npm install lib-jitsi-meet --force && make deploy-lib-jitsi-meet
```
Alternative way is to use [npm link](https://docs.npmjs.com/cli/link).
It allows to link `lib-jitsi-meet` dependency to local source in few steps:
```bash
cd lib-jitsi-meet
#### create global symlink for lib-jitsi-meet package
npm link
cd ../jitsi-meet
#### create symlink from the local node_modules folder to the global lib-jitsi-meet symlink
npm link lib-jitsi-meet
```
So now after changes in local `lib-jitsi-meet` repository you can rebuild it with `npm run install` and your `jitsi-meet` repository will use that modified library.
Note: when using node version 4.x, the make file of jitsi-meet do npm update which will delete the link, no longer the case with version 6.x.
If you do not want to use local repository anymore you should run
```bash
cd jitsi-meet
npm unlink lib-jitsi-meet
npm install
```
### Running with webpack-dev-server for development
Use it at the CLI, type
```
make dev
```
By default the backend deployment used is `beta.meet.jit.si`, you can point the Jitsi-Meet app at a different backend by using a proxy server. To do this set the WEBPACK_DEV_SERVER_PROXY_TARGET variable:
```
export WEBPACK_DEV_SERVER_PROXY_TARGET=https://your-example-server.com
make dev
```
The app should be running at https://localhost:8080/
For web development see [here](doc/development.md), and for mobile see [here](doc/mobile.md).
## Contributing
@@ -115,27 +42,30 @@ see our [guidelines for contributing](CONTRIBUTING.md).
## Embedding in external applications
Jitsi Meet provides a very flexible way of embedding it in external applications by using the [Jitsi Meet API](doc/api.md).
Jitsi Meet provides a very flexible way of embedding in external applications by using the [Jitsi Meet API](doc/api.md).
## Security
WebRTC today does not provide a way of conducting multiparty conversations with
end-to-end encryption. As a matter of fact, unless you consistently vocally
compare DTLS fingerprints with your peers, the same goes for one-to-one calls.
As a result when using a Jitsi Meet instance, your stream is encrypted on the
network but decrypted on the machine that hosts the bridge.
WebRTC does not (yet) provide a way of conducting multi-party conversations with end-to-end encryption.
Unless you consistently compare DTLS fingerprints with your peers vocally, the same goes for one-to-one calls.
As a result, your stream is encrypted on the network but decrypted on the machine that hosts the bridge when using Jitsi Meet.
The Jitsi Meet architecture allows you to deploy your own version, including
all server components, and in that case your security guarantees will be roughly
equivalent to these of a direct one-to-one WebRTC call. This is what's unique to
all server components. In that case, your security guarantees will be roughly
equivalent to a direct one-to-one WebRTC call. This is the uniqueness of
Jitsi Meet in terms of security.
The [meet.jit.si](https://meet.jit.si) service is maintained by the Jitsi team
at [8x8](https://8x8.com).
## Mobile app
Jitsi Meet is also available as a React Native app for Android and iOS.
Instructions on how to build it can be found [here](doc/mobile.md).
## Security issues
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
**We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.**
## Acknowledgements
Jitsi Meet started out as a sample conferencing application using Jitsi Videobridge. It was originally developed by then ESTOS' developer Philipp Hancke who then contributed it to the community where development continues with joint forces!
Jitsi Meet started out as a sample conferencing application using Jitsi Videobridge. It was originally developed by ESTOS' developer Philipp Hancke who then contributed it to the community where development continues with joint forces!

View File

@@ -1,8 +1,15 @@
# Jitsi Meet SDK for Android
## Sample applications using the SDK
If you want to see how easy integrating the Jitsi Meet SDK into a native application is, take a look at the
[sample applications repository](https://github.com/jitsi/jitsi-meet-sdk-samples).
## Build your own, or use a pre-build SDK artifacts/binaries
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any modification to the SDK itself, it's suggested to use the pre-build SDK. This avoids the complexity of building and installing your own SDK artifacts/binaries.
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any
modification to the SDK itself or any of its dependencies, it's suggested to use the pre-build SDK. This avoids the
complexity of building and installing your own SDK artifacts/binaries.
### Use pre-build SDK artifacts/binaries
@@ -29,23 +36,10 @@ Dependency definitions belong in the individual module `build.gradle` files:
```gradle
dependencies {
// (other dependencies)
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
implementation ('org.jitsi.react:jitsi-meet-sdk:2.+') { transitive = true }
}
```
Also, enable 32bit mode for react-native, since react-native only supports 32bit apps. (If you have a 64bit device, it will not run unless this setting it set)
```gradle
android {
...
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
...
```
### Build and use your own SDK artifacts/binaries
<details>
@@ -57,49 +51,20 @@ A note on dependencies: Apart from the SDK, Jitsi also publishes a binary Maven
If you want to use a SDK that is built from source, you will likely benefit from composing a local Maven repository that contains these dependencies. The text below describes how you create a repository that includes both the SDK as well as these dependencies. For illustration purposes, we'll define the location of this local Maven repository as `/tmp/repo`
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the parent directory:
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the jitsi-meet project directory:
$ (cd ..; npm install)
npm install
This will pull in the dependencies in either binary format, or in source code format, somewhere under /node_modules/
At the time of writing, there are two packages pulled in in binary format.
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code
or binary form. These need to be assembled into Maven artifacts, and then published to your local Maven repository.
A script is provided to facilitate this. From the root of the jitsi-meet project repository, run:
To copy React Native to your local Maven repository, you can simply copy part of the directory structure that was pulled in by NPM:
./android/scripts/release-sdk.sh /tmp/repo
$ cp -r ../node_modules/react-native/android/com /tmp/repo/
In the same way, copy the JavaScriptCore dependency:
$ cp -r ../node_modules/jsc-android/dist/org /tmp/repo/
Alternatively, you can use the scripts located in the android/scripts directory to publish these dependencies to your Maven repo.
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code form. These need to be assembled into Maven artifacts, and then published to your local Maven repository. The SDK project facilitates this.
To prepare, Configure the Maven repositories in which you are going to publish the SDK artifacts/binaries. In `android/sdk/build.gradle` as well as in `android/build.gradle` modify the lines that contain:
"file:${rootProject.projectDir}/../../jitsi-maven-repository/releases"
Change this value (which represents the Maven repository location used internally by the Jitsi Developers) to the location of the repository that you'd like to use:
"file:/tmp/repo"
Make sure to do this in both files! Each file should require one line to be changed.
To create the release assembly for any _specific_ third-party React Native module that you need, you can execture the following commands, replace the module name in the examples below.
$ ./gradlew :react-native-webrtc:assembleRelease
$ ./gradlew :react-native-webrtc:publish
You build and publish the SDK itself in the same way:
$ ./gradlew :sdk:assembleRelease
$ ./gradlew :sdk:publish
Alternatively, you can assemble and publish _all_ subprojects, which include the react-native modules, but also the SDK itself, with a single command:
$ ./gradlew assembleRelease publish
This will build and publish the SDK, and all of its dependencies to the specified Maven repository (`/tmp/repo`) in
this example.
You're now ready to use the artifacts. In _your_ project, add the Maven repository that you used above (`/tmp/repo`) into your top-level `build.gradle` file:
@@ -117,7 +82,8 @@ Then, define the dependency `org.jitsi.react:jitsi-meet-sdk` into the `build.gra
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive dependencies of `jitsi-meet-sdk`.
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive
dependencies of `jitsi-meet-sdk`.
</details>
@@ -163,14 +129,14 @@ View is strongly recommended.
package org.jitsi.example;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v4.app.FragmentActivity;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.ReactActivityLifecycleCallbacks;
// Example
//
public class MainActivity extends AppCompatActivity {
public class MainActivity extends FragmentActivity implements JitsiMeetActivityInterface {
private JitsiMeetView view;
@Override
@@ -178,13 +144,13 @@ public class MainActivity extends AppCompatActivity {
int requestCode,
int resultCode,
Intent data) {
ReactActivityLifecycleCallbacks.onActivityResult(
JitsiMeetActivityDelegate.onActivityResult(
this, requestCode, resultCode, data);
}
@Override
public void onBackPressed() {
ReactActivityLifecycleCallbacks.onBackPressed();
JitsiMeetActivityDelegate.onBackPressed();
}
@Override
@@ -192,7 +158,10 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
view = new JitsiMeetView(this);
view.loadURL(null);
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions.Builder()
.setRoom("https://meet.jit.si/test123")
.build();
view.join(options);
setContentView(view);
}
@@ -204,12 +173,12 @@ public class MainActivity extends AppCompatActivity {
view.dispose();
view = null;
ReactActivityLifecycleCallbacks.onHostDestroy(this);
JitsiMeetActivityDelegate.onHostDestroy(this);
}
@Override
public void onNewIntent(Intent intent) {
ReactActivityLifecycleCallbacks.onNewIntent(intent);
JitsiMeetActivityDelegate.onNewIntent(intent);
}
@Override
@@ -217,144 +186,85 @@ public class MainActivity extends AppCompatActivity {
final int requestCode,
final String[] permissions,
final int[] grantResults) {
ReactActivityLifecycleCallbacks.onRequestPermissionsResult(requestCode, permissions, grantResults);
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onResume() {
super.onResume();
ReactActivityLifecycleCallbacks.onHostResume(this);
JitsiMeetActivityDelegate.onHostResume(this);
}
@Override
protected void onStop() {
super.onStop();
ReactActivityLifecycleCallbacks.onHostPause(this);
JitsiMeetActivityDelegate.onHostPause(this);
}
}
```
</details>
Starting with SDK version 1.22, a Glide module must be provided by the host app.
This makes it possible to use the Glide image processing library from both the
SDK and the host app itself.
You can use the code in `JitsiGlideModule.java` and adjust the package name.
When building, add the following code in your `app/build.gradle` file, adjusting
the Glide version to match the one in https://github.com/jitsi/jitsi-meet/blob/master/android/build.gradle
```
// Glide
implementation("com.github.bumptech.glide:glide:${glideVersion}") {
exclude group: "com.android.support", module: "glide"
}
implementation("com.github.bumptech.glide:annotations:${glideVersion}") {
exclude group: "com.android.support", module: "annotations"
}
```
### JitsiMeetActivity
This class encapsulates a high level API in the form of an Android `Activity`
which displays a single `JitsiMeetView`.
This class encapsulates a high level API in the form of an Android `FragmentActivity`
which displays a single `JitsiMeetView`. You can pass a URL as a `ACTION_VIEW`
on the Intent when starting it and it will join the conference, and will be
automatically terminated (finish() will be called on the activity) when the
conference ends or fails.
### JitsiMeetView
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
display a Jitsi Meet conference (or a welcome page).
#### join(options)
Joins the conference specified by the given `JitsiMeetConferenceOptions`.
#### leave()
Leaves the currently active conference. If the welcome page is enabled it will
go back to it, otherwise a black window will be shown.
#### dispose()
Releases all resources associated with this view. This method MUST be called
when the Activity holding this view is going to be destroyed, usually in the
`onDestroy()` method.
#### getDefaultURL()
Returns the default base URL used to join a conference when a partial URL (e.g.
a room name only) is specified to `loadURLString`/`loadURLObject`. If not set or
if set to `null`, the default built in JavaScript is used: https://meet.jit.si.
#### getListener()
Returns the `JitsiMeetViewListener` instance attached to the view.
#### isPictureInPictureEnabled()
Returns `true` if Picture-in-Picture is enabled; `false`, otherwise. If not
explicitly set (by a preceding `setPictureInPictureEnabled` call), defaults to
`true` if the platform supports Picture-in-Picture natively; `false`, otherwise.
#### isWelcomePageEnabled()
Returns true if the Welcome page is enabled; otherwise, false. If false, a black
empty view will be rendered when not in a conference. Defaults to false.
#### loadURL(URL)
Loads a specific URL which may identify a conference to join. If the specified
URL is null and the Welcome page is enabled, the Welcome page is displayed
instead.
#### loadURLString(String)
Loads a specific URL which may identify a conference to join. If the specified
URL is null and the Welcome page is enabled, the Welcome page is displayed
instead.
#### loadURLObject(Bundle)
Loads a specific URL which may identify a conference to join. The URL is
specified in the form of a Bundle of properties which (1) internally are
sufficient to construct a URL (string) while (2) abstracting the specifics of
constructing the URL away from API clients/consumers. If the specified URL is
null and the Welcome page is enabled, the Welcome page is displayed instead.
Example:
```java
Bundle config = new Bundle();
config.putBoolean("startWithAudioMuted", true);
config.putBoolean("startWithVideoMuted", false);
Bundle urlObject = new Bundle();
urlObject.putBundle("config", config);
urlObject.putString("url", "https://meet.jit.si/Test123");
view.loadURLObject(urlObject);
```
#### setDefaultURL(URL)
Sets the default URL. See `getDefaultURL` for more information.
NOTE: Must be called before (if at all) `loadURL`/`loadURLString` for it to take
effect.
#### setListener(listener)
Sets the given listener (class implementing the `JitsiMeetViewListener`
interface) on the view.
#### setPictureInPictureEnabled(boolean)
### JitsiMeetConferenceOptions
Sets whether Picture-in-Picture is enabled. If not set, Jitsi Meet SDK
automatically enables/disables Picture-in-Picture based on native platform
support.
This object encapsulates all the options that can be tweaked when joining
a conference.
NOTE: Must be called (if at all) before `loadURL`/`loadURLString` for it to take
effect.
Example:
#### setWelcomePageEnabled(boolean)
```java
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions.Builder()
.setServerURL(new URL("https://meet.jit.si"))
.setRoom("test123")
.setAudioMuted(false)
.setVideoMuted(false)
.setAudioOnly(false)
.setWelcomePageEnabled(false)
.build();
```
Sets whether the Welcome page is enabled. See `isWelcomePageEnabled` for more
information.
See the `JitsiMeetConferenceOptions` implementation for all available options.
NOTE: Must be called (if at all) before `loadURL`/`loadURLString` for it to take
effect.
### ReactActivityLifecycleCallbacks
### JitsiMeetActivityDelegate
This class handles the interaction between `JitsiMeetView` and its enclosing
`Activity`. Generally this shouldn't be consumed by users, because they'd be
@@ -410,29 +320,20 @@ This is a static method.
`JitsiMeetViewListener` provides an interface apps can implement to listen to
the state of the Jitsi Meet conference displayed in a `JitsiMeetView`.
`JitsiMeetViewAdapter`, a default implementation of the
`JitsiMeetViewListener` interface is also provided. Apps may extend the class
instead of implementing the interface in order to minimize boilerplate.
##### onConferenceFailed
Called when a joining a conference was unsuccessful or when there was an error
while in a conference.
The `data` `Map` contains an "error" key describing the error and a "url" key
with the conference URL.
#### onConferenceJoined
Called when a conference was joined.
The `data` `Map` contains a "url" key with the conference URL.
#### onConferenceLeft
#### onConferenceTerminated
Called when a conference was left.
Called when a conference was terminated either by user choice or due to a
failure.
The `data` `Map` contains a "url" key with the conference URL.
The `data` `Map` contains an "error" key with the error and a "url" key
with the conference URL. If the conference finished gracefully no `error`
key will be present.
#### onConferenceWillJoin
@@ -440,20 +341,6 @@ Called before a conference is joined.
The `data` `Map` contains a "url" key with the conference URL.
#### onConferenceWillLeave
Called before a conference is left.
The `data` `Map` contains a "url" key with the conference URL.
#### onLoadConfigError
Called when loading the main configuration file from the Jitsi Meet deployment
fails.
The `data` `Map` contains an "error" key with the error and a "url" key with the
conference URL which necessitated the loading of the configuration file.
## ProGuard rules
When using the SDK on a project some proguard rules have to be added in order
@@ -466,10 +353,6 @@ rules file: https://github.com/jitsi/jitsi-meet/blob/master/android/app/proguard
Picture-in-Picture style scenario, in a rectangle too small to accommodate its
"full" UI.
Jitsi Meet SDK automatically enables (unless explicitly disabled by a
`setPictureInPictureEnabled(false)` call) Android's native Picture-in-Picture
mode iff the platform is supported i.e. Android >= Oreo.
## Dropbox integration
To setup the Dropbox integration, follow these steps:

6
android/app/.classpath Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

23
android/app/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,2 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
boolean googleServicesEnabled = project.file('google-services.json').exists()
boolean googleServicesEnabled \
= project.file('google-services.json').exists() && !rootProject.ext.libreBuild
// Crashlytics integration is done as part of Firebase now, so it gets
// automagically activated with google-services.json
@@ -8,6 +9,11 @@ if (googleServicesEnabled) {
apply plugin: 'io.fabric'
}
// Use the number of seconds/10 since Jan 1 2019 as the versionCode.
// This lets us upload a new build at most every 10 seconds for the
// next ~680 years.
// https://stackoverflow.com/a/38643838
def vcode = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
android {
compileSdkVersion rootProject.ext.compileSdkVersion
@@ -15,37 +21,38 @@ android {
defaultConfig {
applicationId 'org.jitsi.meet'
versionCode Integer.parseInt(project.buildNumber)
versionCode vcode
versionName project.appVersion
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
packagingOptions {
// The project react-native does not provide 64-bit binaries at the
// time of this writing. Unfortunately, packaging any 64-bit
// binaries into the .apk will crash the app at runtime on 64-bit
// platforms.
exclude '/lib/mips64/**'
exclude '/lib/arm64-v8a/**'
exclude '/lib/x86_64/**'
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro'
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-release.pro'
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
}
sourceSets {
main {
java {
if (rootProject.ext.libreBuild) {
srcDir "src"
exclude "**/GoogleServicesHelper.java"
}
}
}
}
@@ -61,48 +68,34 @@ repositories {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'
}
implementation project(':sdk')
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
// Glide
implementation("com.github.bumptech.glide:glide:${rootProject.ext.glideVersion}") {
exclude group: "com.android.support", module: "glide"
}
implementation("com.github.bumptech.glide:annotations:${rootProject.ext.glideVersion}") {
exclude group: "com.android.support", module: "annotations"
}
annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.ext.glideVersion}"
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'
}
gradle.projectsEvaluated {
// Dropbox integration
//
def plistParser = new XmlSlurper(
/* validating */ false,
/* namespaceAware */ false,
/* allowDocTypeDeclaration */ true)
plistParser.setFeature(
'http://apache.org/xml/features/nonvalidating/load-external-dtd',
false)
def plist = plistParser.parse('../ios/app/src/Info.plist')
def dropboxScheme = plist.dict.array.dict.array.string.find { string ->
string.text().startsWith('db-')
def dropboxAppKey
if (project.file('dropbox.key').exists()) {
dropboxAppKey = project.file('dropbox.key').text.trim() - 'db-'
}
def dropboxAppKey = dropboxScheme?.text() - 'db-'
if (dropboxAppKey) {
android.defaultConfig.resValue('string', 'dropbox_app_key', "${dropboxAppKey}")
@@ -118,25 +111,57 @@ gradle.projectsEvaluated {
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="db-${dropboxAppKey}" />
</intent-filter>
</activity>""";
</activity>"""
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.processManifest.doLast {
def f = new File(manifestOutputDirectory, 'AndroidManifest.xml')
if (!f.isFile()) {
f = new File(new File(manifestOutputDirectory, output.dirName), 'AndroidManifest.xml')
}
if (f.exists()) {
def charset = 'UTF-8'
def s = f.getText(charset)
s = s.replace('</application>', "${dropboxActivity}</application>")
f.write(s, charset)
}
output.getProcessManifestProvider().get().doLast {
def outputDir = manifestOutputDirectory.get().asFile
def manifestPath = new File(outputDir, 'AndroidManifest.xml')
def charset = 'UTF-8'
def text
text = manifestPath.getText(charset)
text = text.replace('</application>', "${dropboxActivity}</application>")
manifestPath.write(text, charset)
}
}
}
}
// Run React packager
android.applicationVariants.all { variant ->
def targetName = variant.name.capitalize()
def currentRunPackagerTask = tasks.create(
name: "run${targetName}ReactPackager",
type: Exec) {
group = "react"
description = "Run the React packager."
doFirst {
println "Starting the React packager..."
def androidRoot = file("${projectDir}/../")
// Set up the call to the script
workingDir androidRoot
// Run the packager
commandLine("scripts/run-packager.sh")
}
// Set up dev mode
def devEnabled = !targetName.toLowerCase().contains("release")
// Only enable for dev builds
enabled devEnabled
}
def packageTask = variant.packageApplicationProvider.get()
packageTask.dependsOn(currentRunPackagerTask)
}
}
if (googleServicesEnabled) {

View File

@@ -1,5 +0,0 @@
-include proguard-rules.pro
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
-dontobfuscate

View File

@@ -9,13 +9,6 @@
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
@@ -60,18 +53,18 @@
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep class okio.** { *; }
-dontwarn okio.**
# FastImage + Glide
# WebRTC
-keep public class com.dylanvann.fastimage.* {*;}
-keep public class com.dylanvann.fastimage.** {*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class org.webrtc.** { *; }
-dontwarn org.chromium.build.BuildHooksAndroid
# Jisti Meet SDK
-keep class org.jitsi.meet.** { *; }
-keep class org.jitsi.meet.sdk.** { *; }
# We added the following when we switched minifyEnabled on. Probably because we
# ran the app and hit problems...
@@ -83,7 +76,6 @@
-keep class com.facebook.react.bridge.ReadableType { *; }
-keep class com.facebook.react.bridge.queue.NativeRunnable { *; }
-keep class com.facebook.react.devsupport.** { *; }
-keep class org.webrtc.** { *; }
-dontwarn com.facebook.react.devsupport.**
-dontwarn com.google.appengine.**
@@ -91,3 +83,6 @@
-dontwarn javax.servlet.**
# ^^^ We added the above when we switched minifyEnabled on.
# Rule to avoid build errors related to SVGs.
-keep public class com.horcrux.svg.** {*;}

View File

@@ -25,6 +25,7 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="alpha.jitsi.net" android:scheme="https" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>

View File

@@ -0,0 +1,40 @@
package org.jitsi.meet;
import android.net.Uri;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import io.fabric.sdk.android.Fabric;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
* Helper class to initialize Google related services and functionality.
* This functionality is compiled conditionally and called via reflection, that's why it was
* extracted here.
*
* "Libre builds" (builds with the LIBRE_BUILD flag set) will not include this file.
*/
final class GoogleServicesHelper {
public static void initialize(JitsiMeetActivity activity) {
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
Fabric.with(activity, new Crashlytics());
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
Uri dynamicLink = null;
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
if (dynamicLink != null) {
activity.join(dynamicLink.toString());
}
});
}
}
}

View File

@@ -1,16 +0,0 @@
package org.jitsi.meet;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
/**
* An AppGlideModule needs to be present for image loading events to work in
* react-native-fast-image. However, if this is defined by the SDK it will cause trouble with
* apps which are using Glide themselves.
*
* In order to avoid the problem, define a Jitsi Glide module here, so applications already using
* it are not in trouble.
*/
@GlideModule
public final class JitsiGlideModule extends AppGlideModule {
}

View File

@@ -17,243 +17,134 @@
package org.jitsi.meet;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.JitsiMeetViewListener;
import org.jitsi.meet.sdk.invite.AddPeopleController;
import org.jitsi.meet.sdk.invite.AddPeopleControllerListener;
import org.jitsi.meet.sdk.invite.InviteController;
import org.jitsi.meet.sdk.invite.InviteControllerListener;
import com.crashlytics.android.Crashlytics;
import com.facebook.react.bridge.UiThreadUtil;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import io.fabric.sdk.android.Fabric;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* The one and only {@link Activity} that the Jitsi Meet app needs. The
* The one and only Activity that the Jitsi Meet app needs. The
* {@code Activity} is launched in {@code singleTask} mode, so it will be
* created upon application initialization and there will be a single instance
* of it. Further attempts at launching the application once it was already
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
*
* This {@code Activity} extends {@link JitsiMeetActivity} to keep the React
* Native CLI working, since the latter always tries to launch an
* {@code Activity} named {@code MainActivity} when doing
* {@code react-native run-android}.
* launched will result in {@link MainActivity#onNewIntent(Intent)} being called.
*/
public class MainActivity extends JitsiMeetActivity {
/**
* The query to perform through {@link AddPeopleController} when the
* {@code InviteButton} is tapped in order to exercise the public API of the
* feature invite. If {@code null}, the {@code InviteButton} will not be
* rendered.
* The request code identifying requests for the permission to draw on top
* of other apps. The value must be 16-bit and is arbitrarily chosen here.
*/
private static final String ADD_PEOPLE_CONTROLLER_QUERY = null;
private static final int OVERLAY_PERMISSION_REQUEST_CODE
= (int) (Math.random() * Short.MAX_VALUE);
// JitsiMeetActivity overrides
//
@Override
protected JitsiMeetView initializeView() {
JitsiMeetView view = super.initializeView();
// XXX In order to increase (1) awareness of API breakages and (2) API
// coverage, utilize JitsiMeetViewListener in the Debug configuration of
// the app.
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(
"ReactNative",
JitsiMeetViewListener.class.getSimpleName() + " "
+ name + " "
+ data);
}
@Override
public void onConferenceFailed(Map<String, Object> data) {
on("CONFERENCE_FAILED", data);
}
@Override
public void onConferenceJoined(Map<String, Object> data) {
on("CONFERENCE_JOINED", data);
}
@Override
public void onConferenceLeft(Map<String, Object> data) {
on("CONFERENCE_LEFT", data);
}
@Override
public void onConferenceWillJoin(Map<String, Object> data) {
on("CONFERENCE_WILL_JOIN", data);
}
@Override
public void onConferenceWillLeave(Map<String, Object> data) {
on("CONFERENCE_WILL_LEAVE", data);
}
@Override
public void onLoadConfigError(Map<String, Object> data) {
on("LOAD_CONFIG_ERROR", data);
}
});
// inviteController
final InviteController inviteController
= view.getInviteController();
inviteController.setListener(new InviteControllerListener() {
public void beginAddPeople(
AddPeopleController addPeopleController) {
onInviteControllerBeginAddPeople(
inviteController,
addPeopleController);
}
});
inviteController.setAddPeopleEnabled(
ADD_PEOPLE_CONTROLLER_QUERY != null);
inviteController.setDialOutEnabled(
inviteController.isAddPeopleEnabled());
}
return view;
}
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.
// Technically, endAddPeople will automatically be invoked if there are
// no failedInviteees i.e. the invite succeeeded for all specified
// invitees.
addPeopleController.endAddPeople();
}
private void onAddPeopleControllerReceivedResults(
AddPeopleController addPeopleController,
List<Map<String, Object>> results,
String query) {
UiThreadUtil.assertOnUiThread();
int size = results.size();
if (size > 0) {
// Exercise AddPeopleController's inviteById implementation.
List<String> ids = new ArrayList<>(size);
for (Map<String, Object> result : results) {
Object id = result.get("id");
if (id != null) {
ids.add(id.toString());
}
}
addPeopleController.inviteById(ids);
return;
}
// 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.
addPeopleController.endAddPeople();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// As this is the Jitsi Meet app (i.e. not the Jitsi Meet SDK), we do
// want to enable some options.
// The welcome page defaults to disabled in the SDK at the time of this
// writing but it is clearer to be explicit about what we want anyway.
setWelcomePageEnabled(true);
super.onCreate(savedInstanceState);
protected boolean extraInitialize() {
Log.d(this.getClass().getSimpleName(), "LIBRE_BUILD="+BuildConfig.LIBRE_BUILD);
// Setup Crashlytics and Firebase Dynamic Links
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Fabric.with(this, new Crashlytics());
// Here we are using reflection since it may have been disabled at compile time.
try {
Class<?> cls = Class.forName("org.jitsi.meet.GoogleServicesHelper");
Method m = cls.getMethod("initialize", JitsiMeetActivity.class);
m.invoke(null, this);
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
.addOnSuccessListener(this, pendingDynamicLinkData -> {
Uri dynamicLink = null;
// In Debug builds React needs permission to write over other apps in
// order to display the warning and error overlays.
if (BuildConfig.DEBUG) {
if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
if (dynamicLink != null) {
try {
loadURL(new URL(dynamicLink.toString()));
} catch (MalformedURLException e) {
Log.d("ReactNative", "Malformed dynamic link", e);
}
}
});
return true;
}
}
return false;
}
@Override
protected void initialize() {
// Set default options
JitsiMeetConferenceOptions defaultOptions
= new JitsiMeetConferenceOptions.Builder()
.setWelcomePageEnabled(true)
.setServerURL(buildURL("https://meet.jit.si"))
.build();
JitsiMeet.setDefaultConferenceOptions(defaultOptions);
super.initialize();
}
@Override
public void onConferenceTerminated(Map<String, Object> data) {
Log.d(TAG, "Conference terminated: " + data);
}
// Activity lifecycle method overrides
//
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
&& canRequestOverlayPermission()) {
if (Settings.canDrawOverlays(this)) {
initialize();
return;
}
throw new RuntimeException("Overlay permission is required when running in Debug mode.");
}
super.onActivityResult(requestCode, resultCode, data);
}
// ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_MENU) {
JitsiMeet.showDevOptions();
return true;
}
return super.onKeyUp(keyCode, event);
}
// Helper methods
//
private @Nullable URL buildURL(String urlStr) {
try {
return new URL(urlStr);
} catch (MalformedURLException e) {
return null;
}
}
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(
"ReactNative",
InviteControllerListener.class.getSimpleName() + ".beginAddPeople");
String query = ADD_PEOPLE_CONTROLLER_QUERY;
if (query != null
&& (inviteController.isAddPeopleEnabled()
|| inviteController.isDialOutEnabled())) {
addPeopleController.setListener(new AddPeopleControllerListener() {
public void onInviteSettled(
AddPeopleController addPeopleController,
List<Map<String, Object>> failedInvitees) {
onAddPeopleControllerInviteSettled(
addPeopleController,
failedInvitees);
}
public void onReceivedResults(
AddPeopleController addPeopleController,
List<Map<String, Object>> results,
String query) {
onAddPeopleControllerReceivedResults(
addPeopleController,
results, query);
}
});
addPeopleController.performQuery(query);
} else {
// 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.
addPeopleController.endAddPeople();
}
private boolean canRequestOverlayPermission() {
return
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#66A8DD</color>
</resources>

View File

@@ -2,5 +2,6 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:navigationBarColor">#1081B2</item>
</style>
</resources>

View File

@@ -1,5 +1,6 @@
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
</domain-config>
</network-security-config>

View File

@@ -12,7 +12,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.27.0'
@@ -25,10 +25,10 @@ allprojects {
repositories {
google()
jcenter()
maven { url "$rootDir/../node_modules/jsc-android/dist" }
// React Native (JS, Obj-C sources, Android binaries) is installed from
// npm.
// React Native (JS, Obj-C sources, Android binaries) is installed from npm.
maven { url "$rootDir/../node_modules/react-native/android" }
// Android JSC is installed from npm.
maven { url("$rootDir/../node_modules/jsc-android/dist") }
}
// Make sure we use the react-native version in node_modules and not the one
@@ -42,12 +42,6 @@ allprojects {
def version = new JsonSlurper().parseText(file.text).version
details.useVersion version
}
if (details.requested.group == 'org.webkit'
&& details.requested.name == 'android-jsc') {
def file = new File("$rootDir/../node_modules/jsc-android/package.json")
def version = new JsonSlurper().parseText(file.text).version
details.useVersion "r${version.tokenize('.')[0]}"
}
}
}
}
@@ -62,66 +56,41 @@ allprojects {
publishing {
publications {}
repositories {
maven { url "file:${rootProject.projectDir}/../../jitsi-maven-repository/releases" }
maven {
url rootProject.ext.mavenRepo
if (!rootProject.ext.mavenRepo.startsWith("file")) {
credentials {
username rootProject.ext.mavenUser
password rootProject.ext.mavenPassword
}
}
}
}
}
}
// Use the number of seconds/10 since Jan 1 2019 as the version qualifier number.
// This will last for the next ~680 years.
// https://stackoverflow.com/a/38643838
def versionQualifierNumber = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
afterEvaluate { project ->
if (project.plugins.hasPlugin('android') || project.plugins.hasPlugin('android-library')) {
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
}
if (project.name.startsWith('react-native-')) {
def npmManifest = project.file('../package.json')
def json = new JsonSlurper().parseText(npmManifest.text)
// React Native modules have an npm peer dependency on react-native,
// they do not have an npm dependency on it. Further below though we
// choose a react-native version (range) when we represent them as
// Maven artifacts. Effectively, we are forking the projects by not
// complying with the full range of their npm peer dependency and,
// consequently, we should qualify their version.
def versionQualifier = '-jitsi-1'
if ('react-native-background-timer' == project.name)
versionQualifier = '-jitsi-3' // 2.0.0 + react-native 0.57
else if ('react-native-calendar-events' == project.name)
versionQualifier = '-jitsi-2' // 1.6.4 + react-native 0.57
else if ('react-native-fast-image' == project.name)
versionQualifier = '-jitsi-2' // 5.1.1 + react-native 0.57
else if ('react-native-google-signin' == project.name)
versionQualifier = '-jitsi-2' // 1.0.2 + react-native 0.57
else if ('react-native-immersive' == project.name)
versionQualifier = '-jitsi-5' // 2.0.0 + react-native 0.57
else if ('react-native-keep-awake' == project.name)
versionQualifier = '-jitsi-4' // 4.0.0 + react-native 0.57
else if ('react-native-linear-gradient' == project.name)
versionQualifier = '-jitsi-1' // 2.4.0 + react-native 0.57
else if ('react-native-sound' == project.name)
versionQualifier = '-jitsi-2' // 0.10.9 + react-native 0.57
else if ('react-native-vector-icons' == project.name)
versionQualifier = '-jitsi-3' // 6.0.2 + react-native 0.57
else if ('react-native-webrtc' == project.name)
versionQualifier = '-jitsi-9' // 6322a9b5a38ce590cfaea4041072ea87c8dbf558 + react-native 0.57
// Release every dependency the SDK has with a -jitsi-XXX qualified version. This allows
// us to pin the dependencies and make sure they are always updated, no matter what.
project.version = "${json.version}${versionQualifier}"
project.version = "${json.version}-jitsi-${versionQualifierNumber}"
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
if (rootProject.ext.has('buildToolsVersion')) {
buildToolsVersion rootProject.ext.buildToolsVersion
}
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
}
}
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.source
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
failOnError false
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
@@ -137,7 +106,6 @@ allprojects {
extension "aar"
}
artifact(androidSourcesJar)
artifact(androidJavadocsJar)
pom.withXml {
def pomXml = asNode()
pomXml.appendNode('name', project.name)
@@ -188,9 +156,13 @@ ext {
// of ours.
moduleGroupId = 'com.facebook.react'
// Glide
excludeAppGlideModule = true
glideVersion = "4.7.1" // keep in sync with react-native-fast-image
// Maven repo where artifacts will be published
mavenRepo = System.env.MVN_REPO ?: ""
mavenUser = System.env.MVN_USER ?: ""
mavenPassword = System.env.MVN_PASSWORD ?: ""
// Libre build
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
}
// If Android SDK is not installed, accept its license so that it

2
android/fastlane/Appfile Normal file
View File

@@ -0,0 +1,2 @@
json_key_file("")
package_name("org.jitsi.meet")

34
android/fastlane/Fastfile Normal file
View File

@@ -0,0 +1,34 @@
ENV["FASTLANE_SKIP_UPDATE_CHECK"] = "1"
opt_out_usage
default_platform(:android)
platform :android do
desc "Deploy a new version to Goolge Play (Closed Beta)"
lane :deploy do
# Cleanup
gradle(task: "clean")
# Build and sign the app
gradle(
task: "assemble",
build_type: "Release",
print_command: false,
properties: {
"android.injected.signing.store.file" => ENV["JITSI_KEYSTORE"],
"android.injected.signing.store.password" => ENV["JITSI_KEYSTORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["JITSI_KEY_ALIAS"],
"android.injected.signing.key.password" => ENV["JITSI_KEY_PASSWORD"],
}
)
# Upload built artifact to the Closed Beta track
upload_to_play_store(
track: "Closed Beta",
json_key: ENV["JITSI_JSON_KEY_FILE"],
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true
)
end
end

View File

@@ -0,0 +1,29 @@
fastlane documentation
================
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```
xcode-select --install
```
Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew cask install fastlane`
# Available Actions
## Android
### android deploy
```
fastlane android deploy
```
Deploy a new version to Goolge Play (Closed Beta)
----
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

View File

@@ -17,6 +17,8 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
buildNumber=2
appVersion=1.21.0
sdkVersion=1.21.0
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.4.0
sdkVersion=2.4.0

View File

@@ -1,6 +1,6 @@
#Wed Dec 19 12:02:47 CET 2018
#Fri Mar 08 13:36:51 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

View File

@@ -1,17 +0,0 @@
#!/bin/bash
CWD=$(dirname $0)
MVN_REPO=$(realpath $1)
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${CWD}/../../package.json | cut -d . -f 1)
pushd ${CWD}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
mvn \
deploy:deploy-file \
-Durl=file://${MVN_REPO} \
-Dfile=android-jsc-${JSC_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=android-jsc-${JSC_VERSION}.pom
popd

View File

@@ -1,19 +0,0 @@
#!/bin/bash
CWD=$(dirname $0)
MVN_REPO=$(realpath $1)
RN_VERSION=$(jq -r '.dependencies."react-native"' ${CWD}/../../package.json)
pushd ${CWD}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=file://${MVN_REPO} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-Dsources=react-native-${RN_VERSION}-sources.jar \
-Djavadoc=react-native-${RN_VERSION}-javadoc.jar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom
popd

107
android/scripts/release-sdk.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/bin/bash
set -e -u
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
DEFAULT_MVN_REPO="${THIS_DIR}/../../../jitsi-maven-repository/releases"
THE_MVN_REPO=${MVN_REPO:-${1:-$DEFAULT_MVN_REPO}}
MVN_HTTP=0
DEFAULT_SDK_VERSION=$(grep sdkVersion ${THIS_DIR}/../gradle.properties | cut -d"=" -f2)
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
RN_VERSION=$(jq -r '.dependencies."react-native"' ${THIS_DIR}/../../package.json)
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -d . -f 1 | cut -c 2-)
DO_GIT_TAG=${GIT_TAG:-0}
if [[ $THE_MVN_REPO == http* ]]; then
MVN_HTTP=1
else
MVN_REPO_PATH=$(realpath $THE_MVN_REPO)
THE_MVN_REPO="file:${MVN_REPO_PATH}"
fi
export MVN_REPO=$THE_MVN_REPO
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
echo "Using ${MVN_REPO} as the Maven repo"
if [[ $MVN_HTTP == 1 ]]; then
# Push React Native
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-DrepositoryId=${MVN_REPO_ID} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom || true
popd
# Push JSC
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-DrepositoryId=${MVN_REPO_ID} \
-Dfile=android-jsc-${JSC_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=android-jsc-${JSC_VERSION}.pom || true
popd
else
# Push React Native, if necessary
if [[ ! -d ${MVN_REPO}/com/facebook/react/react-native/${RN_VERSION} ]]; then
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom
popd
fi
# Push JSC, if necessary
if [[ ! -d ${MVN_REPO}/org/webkit/android-jsc/${JSC_VERSION} ]]; then
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-Dfile=android-jsc-${JSC_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=android-jsc-${JSC_VERSION}.pom
popd
fi
# Check if an SDK with that same version has already been released
if [[ -d ${MVN_REPO}/org/jitsi/react/jitsi-meet-sdk/${SDK_VERSION} ]]; then
echo "There is already a release with that version in the Maven repo!"
exit 1
fi
fi
# Now build and publish the Jitsi Meet SDK and its dependencies
echo "Building and publishing the Jitsi Meet SDK"
pushd ${THIS_DIR}/../
./gradlew clean assembleRelease publish
popd
if [[ $DO_GIT_TAG == 1 ]]; then
# The artifacts are now on the Maven repo, commit them
pushd ${MVN_REPO_PATH}
git add -A .
git commit -m "Jitsi Meet SDK + dependencies: ${SDK_VERSION}"
popd
# Tag the release
git tag android-sdk-${SDK_VERSION}
fi
# Done!
echo "Finished! Don't forget to push the tag and the Maven repo artifacts."

26
android/scripts/run-packager.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# This script is executed bt Gradle to start the React packager for Debug
# targets.
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${THIS_DIR}/../../node_modules/react-native/scripts/.packager.env"
adb reverse tcp:8081 tcp:8081
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
exit 2
fi
else
CMD="${THIS_DIR}/../../node_modules/react-native/scripts/launchPackager.command"
if [[ `uname` == "Darwin" ]]; then
open -g "${CMD}" || echo "Can't start packager automatically"
else
xdg-open "${CMD}" || echo "Can't start packager automatically"
fi
fi

6
android/sdk/.classpath Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

23
android/sdk/.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sdk</name>
<comment>Project sdk created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,2 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@@ -10,10 +10,25 @@ android {
}
buildTypes {
debug {}
debug {
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
}
sourceSets {
main {
java {
if (rootProject.ext.libreBuild) {
srcDir "src"
exclude "**/AmplitudeModule.java"
}
exclude "test/"
}
}
}
}
@@ -21,28 +36,36 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.fragment:fragment:1.0.0'
implementation 'org.webkit:android-jsc:+'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
api 'com.facebook.react:react-native:+'
implementation 'org.webkit:android-jsc:+'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.squareup.duktape:duktape-android:1.3.0'
if (!rootProject.ext.libreBuild) {
implementation 'com.amplitude:android-sdk:2.14.1'
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
exclude group: 'androidx'
}
}
implementation project(':react-native-background-timer')
implementation project(':react-native-calendar-events')
implementation(project(':react-native-fast-image')) {
exclude group: 'com.android.support'
}
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
exclude group: 'com.android.support'
}
implementation project(':react-native-community-async-storage')
implementation project(':react-native-community_netinfo')
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-linear-gradient')
implementation project(':react-native-sound')
implementation project(':react-native-vector-icons')
implementation project(':react-native-svg')
implementation project(':react-native-webrtc')
implementation project(':react-native-webview')
testImplementation 'junit:junit:4.12'
}
@@ -107,25 +130,25 @@ android.libraryVariants.all { def variant ->
currentBundleTask.ext.generatedResFolders = files(resourcesDir).builtBy(currentBundleTask)
currentBundleTask.ext.generatedAssetsFolders = files(jsBundleDir).builtBy(currentBundleTask)
variant.registerGeneratedResFolders(currentBundleTask.generatedResFolders)
variant.mergeResources.dependsOn(currentBundleTask)
def assetsDir = variant.mergeAssets.outputDir
def mergeAssetsTask = variant.mergeAssetsProvider.get()
def mergeResourcesTask = variant.mergeResourcesProvider.get()
variant.mergeAssets.doLast {
// Bundle fonts
//
copy {
from("${projectDir}/../../fonts/jitsi.ttf")
into("${assetsDir}/fonts")
}
mergeAssetsTask.dependsOn(currentBundleTask)
mergeResourcesTask.dependsOn(currentBundleTask)
mergeAssetsTask.doLast {
def assetsDir = mergeAssetsTask.outputDir
// Bundle sounds
//
copy {
from("${projectDir}/../../sounds/incomingMessage.wav")
from("${projectDir}/../../sounds/joined.wav")
from("${projectDir}/../../sounds/left.wav")
from("${projectDir}/../../sounds/liveStreamingOn.mp3")
from("${projectDir}/../../sounds/liveStreamingOff.mp3")
from("${projectDir}/../../sounds/outgoingRinging.wav")
from("${projectDir}/../../sounds/outgoingStart.wav")
from("${projectDir}/../../sounds/recordingOn.mp3")
@@ -138,19 +161,19 @@ android.libraryVariants.all { def variant ->
//
if (currentBundleTask.enabled) {
copy {
from(jsBundleDir)
from(jsBundleFile)
into(assetsDir)
}
}
}
variant.mergeResources.doLast {
mergeResourcesTask.doLast {
// Copy React resources
//
if (currentBundleTask.enabled) {
copy {
from(resourcesDir)
into(variant.mergeResources.outputDir)
into(mergeResourcesTask.outputDir)
}
}
}
@@ -162,7 +185,7 @@ publishing {
aarArchive(MavenPublication) {
groupId 'org.jitsi.react'
artifactId 'jitsi-meet-sdk'
version project.sdkVersion
version System.env.OVERRIDE_SDK_VERSION ?: project.sdkVersion
artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
extension "aar"
@@ -181,8 +204,7 @@ publishing {
def groupId = it.moduleGroup
def artifactId = it.moduleName
if (artifactId.startsWith('react-native-')
&& groupId.equals('jitsi-meet')) {
if (artifactId.startsWith('react-native-') && groupId.equals('jitsi-meet')) {
groupId = rootProject.ext.moduleGroupId
}
@@ -196,6 +218,14 @@ publishing {
}
repositories {
maven { url "file:${rootProject.projectDir}/../../jitsi-maven-repository/releases" }
maven {
url rootProject.ext.mavenRepo
if (!rootProject.ext.mavenRepo.startsWith("file")) {
credentials {
username rootProject.ext.mavenUser
password rootProject.ext.mavenPassword
}
}
}
}
}

View File

@@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/scorretge/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,30 +1,52 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.meet.sdk">
<!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<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-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
<activity
android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
<activity
android:name=".JitsiMeetActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:windowSoftInputMode="adjustResize">
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<service
android:name=".ConnectionService"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
</service>
<service android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService" />
</application>
</manifest>

View File

@@ -0,0 +1,102 @@
/*
* 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 com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.amplitude.api.Amplitude;
import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Implements the react-native module for the Amplitude integration.
*/
@ReactModule(name = AmplitudeModule.NAME)
class AmplitudeModule
extends ReactContextBaseJavaModule {
public static final String NAME = "Amplitude";
public AmplitudeModule(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* Initializes the Amplitude SDK.
*
* @param instanceName The name of the Amplitude instance. Should
* be used only for multi-project logging.
* @param apiKey The API_KEY of the Amplitude project.
*/
@ReactMethod
public void init(String instanceName, String apiKey) {
Amplitude.getInstance(instanceName).initialize(getCurrentActivity(), apiKey);
}
/**
* Sets the user ID for an Amplitude instance.
*
* @param instanceName The name of the Amplitude instance.
* @param userId The new value for the user ID.
*/
@ReactMethod
public void setUserId(String instanceName, String userId) {
Amplitude.getInstance(instanceName).setUserId(userId);
}
/**
* Sets the user properties for an Amplitude instance.
*
* @param instanceName The name of the Amplitude instance.
* @param userProps JSON string with user properties to be set.
*/
@ReactMethod
public void setUserProperties(String instanceName, ReadableMap userProps) {
if (userProps != null) {
Amplitude.getInstance(instanceName).setUserProperties(
new JSONObject(userProps.toHashMap()));
}
}
/**
* Log an analytics event.
*
* @param instanceName The name of the Amplitude instance.
* @param eventType The event type.
* @param eventPropsString JSON string with the event properties.
*/
@ReactMethod
public void logEvent(String instanceName, String eventType, String eventPropsString) {
try {
JSONObject eventProps = new JSONObject(eventPropsString);
Amplitude.getInstance(instanceName).logEvent(eventType, eventProps);
} catch (JSONException e) {
JitsiMeetLogger.e(e, "Error logging event");
}
}
@Override
public String getName() {
return NAME;
}
}

View File

@@ -15,17 +15,21 @@ import com.facebook.react.bridge.Promise;
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 = AndroidSettingsModule.NAME)
class AndroidSettingsModule
extends ReactContextBaseJavaModule {
public static final String NAME = "AndroidSettings";
public AndroidSettingsModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "AndroidSettings";
return NAME;
}
@ReactMethod

View File

@@ -23,13 +23,17 @@ import android.content.pm.PackageManager;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.module.annotations.ReactModule;
import java.util.HashMap;
import java.util.Map;
@ReactModule(name = AppInfoModule.NAME)
class AppInfoModule
extends ReactContextBaseJavaModule {
public static final String NAME = "AppInfo";
public AppInfoModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@@ -60,6 +64,9 @@ class AppInfoModule
Map<String, Object> constants = new HashMap<>();
constants.put(
"buildNumber",
packageInfo == null ? "" : String.valueOf(packageInfo.versionCode));
constants.put(
"name",
applicationInfo == null
@@ -68,12 +75,13 @@ class AppInfoModule
constants.put(
"version",
packageInfo == null ? "" : packageInfo.versionName);
constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD);
return constants;
}
@Override
public String getName() {
return "AppInfo";
return NAME;
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright @ 2017-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.content.Context;
import android.os.Build;
import android.telecom.CallAudioState;
import androidx.annotation.RequiresApi;
import java.util.HashSet;
import java.util.Set;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for
* Android versions >= O when ConnectionService is enabled.
*/
@RequiresApi(Build.VERSION_CODES.O)
class AudioDeviceHandlerConnectionService implements
AudioModeModule.AudioDeviceHandlerInterface,
RNConnectionService.CallAudioStateListener {
private final static String TAG = AudioDeviceHandlerConnectionService.class.getSimpleName();
/**
* Reference to the main {@code AudioModeModule}.
*/
private AudioModeModule module;
/**
* Converts any of the "DEVICE_" constants into the corresponding
* {@link android.telecom.CallAudioState} "ROUTE_" number.
*
* @param audioDevice one of the "DEVICE_" constants.
* @return a route number {@link android.telecom.CallAudioState#ROUTE_EARPIECE} if
* no match is found.
*/
private static int audioDeviceToRouteInt(String audioDevice) {
if (audioDevice == null) {
return CallAudioState.ROUTE_EARPIECE;
}
switch (audioDevice) {
case AudioModeModule.DEVICE_BLUETOOTH:
return CallAudioState.ROUTE_BLUETOOTH;
case AudioModeModule.DEVICE_EARPIECE:
return CallAudioState.ROUTE_EARPIECE;
case AudioModeModule.DEVICE_HEADPHONES:
return CallAudioState.ROUTE_WIRED_HEADSET;
case AudioModeModule.DEVICE_SPEAKER:
return CallAudioState.ROUTE_SPEAKER;
default:
JitsiMeetLogger.e(TAG + " Unsupported device name: " + audioDevice);
return CallAudioState.ROUTE_EARPIECE;
}
}
/**
* Populates given route mask into the "DEVICE_" list.
*
* @param supportedRouteMask an integer coming from
* {@link android.telecom.CallAudioState#getSupportedRouteMask()}.
* @return a list of device names.
*/
private static Set<String> routesToDeviceNames(int supportedRouteMask) {
Set<String> devices = new HashSet<>();
if ((supportedRouteMask & CallAudioState.ROUTE_EARPIECE) == CallAudioState.ROUTE_EARPIECE) {
devices.add(AudioModeModule.DEVICE_EARPIECE);
}
if ((supportedRouteMask & CallAudioState.ROUTE_BLUETOOTH) == CallAudioState.ROUTE_BLUETOOTH) {
devices.add(AudioModeModule.DEVICE_BLUETOOTH);
}
if ((supportedRouteMask & CallAudioState.ROUTE_SPEAKER) == CallAudioState.ROUTE_SPEAKER) {
devices.add(AudioModeModule.DEVICE_SPEAKER);
}
if ((supportedRouteMask & CallAudioState.ROUTE_WIRED_HEADSET) == CallAudioState.ROUTE_WIRED_HEADSET) {
devices.add(AudioModeModule.DEVICE_HEADPHONES);
}
return devices;
}
/**
* Used to store the most recently reported audio devices.
* Makes it easier to compare for a change, because the devices are stored
* as a mask in the {@link android.telecom.CallAudioState}. The mask is populated into
* the {@code availableDevices} on each update.
*/
private int supportedRouteMask = -1;
public AudioDeviceHandlerConnectionService() {
}
@Override
public void onCallAudioStateChange(final CallAudioState state) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
boolean audioRouteChanged
= audioDeviceToRouteInt(module.getSelectedDevice()) != state.getRoute();
int newSupportedRoutes = state.getSupportedRouteMask();
boolean audioDevicesChanged = supportedRouteMask != newSupportedRoutes;
if (audioDevicesChanged) {
supportedRouteMask = newSupportedRoutes;
Set<String> devices = routesToDeviceNames(supportedRouteMask);
module.replaceDevices(devices);
JitsiMeetLogger.i(TAG + " Available audio devices: " + devices.toString());
}
if (audioRouteChanged || audioDevicesChanged) {
module.resetSelectedDevice();
module.updateAudioRoute();
}
}
});
}
@Override
public void start(Context context, AudioModeModule audioModeModule) {
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
module = audioModeModule;
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (rcs != null) {
rcs.setCallAudioStateListener(this);
} else {
JitsiMeetLogger.w(TAG + " Couldn't set call audio state listener, module is null");
}
}
@Override
public void stop() {
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (rcs != null) {
rcs.setCallAudioStateListener(null);
} else {
JitsiMeetLogger.w(TAG + " Couldn't set call audio state listener, module is null");
}
}
public void setAudioRoute(String audioDevice) {
int newAudioRoute = audioDeviceToRouteInt(audioDevice);
RNConnectionService.setAudioRoute(newAudioRoute);
}
@Override
public boolean setMode(int mode) {
return true;
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright @ 2017-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.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.util.HashSet;
import java.util.Set;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for
* all post-M Android versions. This handler can be used on any Android versions >= M, but by
* default it's only used on versions < O, since versions >= O use ConnectionService, but it
* can be disabled.
*/
@RequiresApi(Build.VERSION_CODES.M)
class AudioDeviceHandlerGeneric implements
AudioModeModule.AudioDeviceHandlerInterface,
AudioManager.OnAudioFocusChangeListener {
private final static String TAG = AudioDeviceHandlerGeneric.class.getSimpleName();
/**
* Reference to the main {@code AudioModeModule}.
*/
private AudioModeModule module;
/**
* Constant defining a USB headset. Only available on API level >= 26.
* The value of: AudioDeviceInfo.TYPE_USB_HEADSET
*/
private static final int TYPE_USB_HEADSET = 22;
/**
* Indicator that we have lost audio focus.
*/
private boolean audioFocusLost = false;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private AudioManager audioManager;
/**
* {@link Runnable} for running audio device detection the main thread.
* This is only used on Android >= M.
*/
private final Runnable onAudioDeviceChangeRunner = new Runnable() {
@Override
public void run() {
Set<String> devices = new HashSet<>();
AudioDeviceInfo[] deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo info: deviceInfos) {
switch (info.getType()) {
case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
devices.add(AudioModeModule.DEVICE_BLUETOOTH);
break;
case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
devices.add(AudioModeModule.DEVICE_EARPIECE);
break;
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
devices.add(AudioModeModule.DEVICE_SPEAKER);
break;
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
case TYPE_USB_HEADSET:
devices.add(AudioModeModule.DEVICE_HEADPHONES);
break;
}
}
module.replaceDevices(devices);
JitsiMeetLogger.i(TAG + " Available audio devices: " + devices.toString());
module.updateAudioRoute();
}
};
private final android.media.AudioDeviceCallback audioDeviceCallback =
new android.media.AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(
AudioDeviceInfo[] addedDevices) {
JitsiMeetLogger.d(TAG + " Audio devices added");
onAudioDeviceChange();
}
@Override
public void onAudioDevicesRemoved(
AudioDeviceInfo[] removedDevices) {
JitsiMeetLogger.d(TAG + " Audio devices removed");
onAudioDeviceChange();
}
};
public AudioDeviceHandlerGeneric() {
}
/**
* Helper method to trigger an audio route update when devices change. It
* makes sure the operation is performed on the audio thread.
*/
private void onAudioDeviceChange() {
module.runInAudioThread(onAudioDeviceChangeRunner);
}
/**
* {@link AudioManager.OnAudioFocusChangeListener} interface method. Called
* when the audio focus of the system is updated.
*
* @param focusChange - The type of focus change.
*/
@Override
public void onAudioFocusChange(final int focusChange) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: {
JitsiMeetLogger.d(TAG + " Audio focus gained");
// Some other application potentially stole our audio focus
// temporarily. Restore our mode.
if (audioFocusLost) {
module.updateAudioRoute();
}
audioFocusLost = false;
break;
}
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
JitsiMeetLogger.d(TAG + " Audio focus lost");
audioFocusLost = true;
break;
}
}
}
});
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
@Override
public void start(Context context, AudioModeModule audioModeModule) {
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
module = audioModeModule;
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
// Setup runtime device change detection.
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
// Do an initial detection.
onAudioDeviceChange();
}
@Override
public void stop() {
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback);
}
@Override
public void setAudioRoute(String device) {
// Turn speaker on / off
audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER));
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
}
@Override
public boolean setMode(int mode) {
if (mode == AudioModeModule.DEFAULT) {
audioFocusLost = false;
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(this);
audioManager.setSpeakerphoneOn(false);
setBluetoothAudioRoute(false);
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
JitsiMeetLogger.w(TAG + " Audio focus request failed");
return false;
}
return true;
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright @ 2017-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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* {@link AudioModeModule.AudioDeviceHandlerInterface} module implementing device handling for
* legacy (pre-M) Android versions.
*/
class AudioDeviceHandlerLegacy implements
AudioModeModule.AudioDeviceHandlerInterface,
AudioManager.OnAudioFocusChangeListener,
BluetoothHeadsetMonitor.Listener {
private final static String TAG = AudioDeviceHandlerLegacy.class.getSimpleName();
/**
* Reference to the main {@code AudioModeModule}.
*/
private AudioModeModule module;
/**
* Indicator that we have lost audio focus.
*/
private boolean audioFocusLost = false;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private AudioManager audioManager;
/**
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
* old (< M) Android versions.
*/
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
public AudioDeviceHandlerLegacy() {
}
/**
* Helper method to trigger an audio route update when Bluetooth devices are
* connected / disconnected.
*/
@Override
public void onBluetoothDeviceChange(final boolean deviceAvailable) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
if (deviceAvailable) {
module.addDevice(AudioModeModule.DEVICE_BLUETOOTH);
} else {
module.removeDevice(AudioModeModule.DEVICE_BLUETOOTH);
}
module.updateAudioRoute();
}
});
}
/**
* Helper method to trigger an audio route update when a headset is plugged
* or unplugged.
*/
private void onHeadsetDeviceChange() {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
// XXX: isWiredHeadsetOn is not deprecated when used just for
// knowing if there is a wired headset connected, regardless of
// audio being routed to it.
//noinspection deprecation
if (audioManager.isWiredHeadsetOn()) {
module.addDevice(AudioModeModule.DEVICE_HEADPHONES);
} else {
module.removeDevice(AudioModeModule.DEVICE_HEADPHONES);
}
module.updateAudioRoute();
}
});
}
/**
* {@link AudioManager.OnAudioFocusChangeListener} interface method. Called
* when the audio focus of the system is updated.
*
* @param focusChange - The type of focus change.
*/
@Override
public void onAudioFocusChange(final int focusChange) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: {
JitsiMeetLogger.d(TAG + " Audio focus gained");
// Some other application potentially stole our audio focus
// temporarily. Restore our mode.
if (audioFocusLost) {
module.updateAudioRoute();
}
audioFocusLost = false;
break;
}
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
JitsiMeetLogger.d(TAG + " Audio focus lost");
audioFocusLost = true;
break;
}
}
}
});
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
@Override
public void start(Context context, AudioModeModule audioModeModule) {
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
module = audioModeModule;
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
// Setup runtime device change detection.
//
// Detect changes in wired headset connections.
IntentFilter wiredHeadSetFilter = new IntentFilter(AudioManager.ACTION_HEADSET_PLUG);
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
JitsiMeetLogger.d(TAG + " Wired headset added / removed");
onHeadsetDeviceChange();
}
};
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
// Detect Bluetooth device changes.
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(context, this);
// On Android < M, detect if we have an earpiece.
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
module.addDevice(AudioModeModule.DEVICE_EARPIECE);
}
// Always assume there is a speaker.
module.addDevice(AudioModeModule.DEVICE_SPEAKER);
}
@Override
public void stop() {
bluetoothHeadsetMonitor.stop();
bluetoothHeadsetMonitor = null;
}
@Override
public void setAudioRoute(String device) {
// Turn speaker on / off
audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER));
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
}
@Override
public boolean setMode(int mode) {
if (mode == AudioModeModule.DEFAULT) {
audioFocusLost = false;
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(this);
audioManager.setSpeakerphoneOn(false);
setBluetoothAudioRoute(false);
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
JitsiMeetLogger.w(TAG + " Audio focus request failed");
return false;
}
return true;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
* Copyright @ 2017-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.
@@ -16,16 +16,8 @@
package org.jitsi.meet.sdk;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
@@ -34,6 +26,9 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.HashMap;
import java.util.HashSet;
@@ -57,9 +52,9 @@ import java.util.concurrent.Executors;
* Before a call has started and after it has ended the
* {@code AudioModeModule.DEFAULT} mode should be used.
*/
class AudioModeModule
extends ReactContextBaseJavaModule
implements AudioManager.OnAudioFocusChangeListener {
@ReactModule(name = AudioModeModule.NAME)
class AudioModeModule extends ReactContextBaseJavaModule {
public static final String NAME = "AudioMode";
/**
* Constants representing the audio mode.
@@ -70,116 +65,33 @@ class AudioModeModule
* - VIDEO_CALL: Used for video calls. It will use the speaker by default,
* unless a wired or Bluetooth headset is connected.
*/
private static final int DEFAULT = 0;
private static final int AUDIO_CALL = 1;
private static final int VIDEO_CALL = 2;
/**
* Constant defining the action for plugging in a headset. This is used on
* our device detection system for API < 23.
*/
private static final String ACTION_HEADSET_PLUG
= (Build.VERSION.SDK_INT >= 21)
? AudioManager.ACTION_HEADSET_PLUG
: Intent.ACTION_HEADSET_PLUG;
/**
* Constant defining a USB headset. Only available on API level >= 26.
* The value of: AudioDeviceInfo.TYPE_USB_HEADSET
*/
private static final int TYPE_USB_HEADSET = 22;
/**
* The name of {@code AudioModeModule} to be used in the React Native
* bridge.
*/
private static final String MODULE_NAME = "AudioMode";
static final int DEFAULT = 0;
static final int AUDIO_CALL = 1;
static final int VIDEO_CALL = 2;
/**
* The {@code Log} tag {@code AudioModeModule} is to log messages with.
*/
static final String TAG = MODULE_NAME;
static final String TAG = NAME;
/**
* Indicator that we have lost audio focus.
* Whether or not the ConnectionService is used for selecting audio devices.
*/
private boolean audioFocusLost = false;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private final AudioManager audioManager;
private static final boolean supportsConnectionService = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
private static boolean useConnectionService_ = supportsConnectionService;
/**
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
* old (< M) Android versions.
*/
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
static boolean useConnectionService() {
return supportsConnectionService && useConnectionService_;
}
private AudioDeviceHandlerInterface audioDeviceHandler;
/**
* {@link ExecutorService} for running all audio operations on a dedicated
* thread.
*/
private static final ExecutorService executor
= Executors.newSingleThreadExecutor();
/**
* {@link Runnable} for running audio device detection the main thread.
* This is only used on Android >= M.
*/
private final Runnable onAudioDeviceChangeRunner = new Runnable() {
@TargetApi(Build.VERSION_CODES.M)
@Override
public void run() {
Set<String> devices = new HashSet<>();
AudioDeviceInfo[] deviceInfos
= audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for (AudioDeviceInfo info: deviceInfos) {
switch (info.getType()) {
case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
devices.add(DEVICE_BLUETOOTH);
break;
case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
devices.add(DEVICE_EARPIECE);
break;
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
devices.add(DEVICE_SPEAKER);
break;
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
case TYPE_USB_HEADSET:
devices.add(DEVICE_HEADPHONES);
break;
}
}
availableDevices = devices;
Log.d(TAG, "Available audio devices: " +
availableDevices.toString());
// Reset user selection
userSelectedDevice = null;
if (mode != -1) {
updateAudioRoute(mode);
}
}
};
/**
* {@link Runnable} for running update operation on the main thread.
*/
private final Runnable updateAudioRouteRunner
= new Runnable() {
@Override
public void run() {
if (mode != -1) {
updateAudioRoute(mode);
}
}
};
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
/**
* Audio mode currently in use.
@@ -189,10 +101,15 @@ class AudioModeModule
/**
* Audio device types.
*/
private static final String DEVICE_BLUETOOTH = "BLUETOOTH";
private static final String DEVICE_EARPIECE = "EARPIECE";
private static final String DEVICE_HEADPHONES = "HEADPHONES";
private static final String DEVICE_SPEAKER = "SPEAKER";
static final String DEVICE_BLUETOOTH = "BLUETOOTH";
static final String DEVICE_EARPIECE = "EARPIECE";
static final String DEVICE_HEADPHONES = "HEADPHONES";
static final String DEVICE_SPEAKER = "SPEAKER";
/**
* Device change event.
*/
private static final String DEVICE_CHANGE_EVENT = "org.jitsi.meet:features/audio-mode#devices-update";
/**
* List of currently available audio devices.
@@ -219,27 +136,6 @@ class AudioModeModule
*/
public AudioModeModule(ReactApplicationContext reactContext) {
super(reactContext);
audioManager
= (AudioManager)
reactContext.getSystemService(Context.AUDIO_SERVICE);
// Setup runtime device change detection.
setupAudioRouteChangeDetection();
// Do an initial detection on Android >= M.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
runInAudioThread(onAudioDeviceChangeRunner);
} else {
// On Android < M, detect if we have an earpiece.
PackageManager pm = reactContext.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
availableDevices.add(DEVICE_EARPIECE);
}
// Always assume there is a speaker.
availableDevices.add(DEVICE_SPEAKER);
}
}
/**
@@ -252,6 +148,7 @@ class AudioModeModule
public Map<String, Object> getConstants() {
Map<String, Object> constants = new HashMap<>();
constants.put("DEVICE_CHANGE_EVENT", DEVICE_CHANGE_EVENT);
constants.put("AUDIO_CALL", AUDIO_CALL);
constants.put("DEFAULT", DEFAULT);
constants.put("VIDEO_CALL", VIDEO_CALL);
@@ -260,31 +157,26 @@ class AudioModeModule
}
/**
* Gets the list of available audio device categories, i.e. 'bluetooth',
* 'earpiece ', 'speaker', 'headphones'.
*
* @param promise a {@link Promise} which will be resolved with an object
* containing a 'devices' key with a list of devices, plus a
* 'selected' key with the selected one.
* Notifies JS land that the devices list has changed.
*/
@ReactMethod
public void getAudioDevices(final Promise promise) {
private void notifyDevicesChanged() {
runInAudioThread(new Runnable() {
@Override
public void run() {
WritableMap map = Arguments.createMap();
map.putString("selected", selectedDevice);
WritableArray devices = Arguments.createArray();
WritableArray data = Arguments.createArray();
final boolean hasHeadphones = availableDevices.contains(DEVICE_HEADPHONES);
for (String device : availableDevices) {
if (mode == VIDEO_CALL && device.equals(DEVICE_EARPIECE)) {
// Skip earpiece when in video call mode.
if (hasHeadphones && device.equals(DEVICE_EARPIECE)) {
// Skip earpiece when headphones are plugged in.
continue;
}
devices.pushString(device);
WritableMap deviceInfo = Arguments.createMap();
deviceInfo.putString("type", device);
deviceInfo.putBoolean("selected", device.equals(selectedDevice));
data.pushMap(deviceInfo);
}
map.putArray("devices", devices);
promise.resolve(map);
ReactInstanceManagerHolder.emitEvent(DEVICE_CHANGE_EVENT, data);
JitsiMeetLogger.i(TAG + " Updating audio device list");
}
});
}
@@ -296,99 +188,40 @@ class AudioModeModule
*/
@Override
public String getName() {
return MODULE_NAME;
return NAME;
}
/**
* Helper method to trigger an audio route update when devices change. It
* makes sure the operation is performed on the main thread.
*
* Only used on Android >= M.
*/
void onAudioDeviceChange() {
runInAudioThread(onAudioDeviceChangeRunner);
}
/**
* Helper method to trigger an audio route update when Bluetooth devices are
* connected / disconnected.
*
* Only used on Android < M. Runs on the main thread.
*/
void onBluetoothDeviceChange() {
if (bluetoothHeadsetMonitor != null && bluetoothHeadsetMonitor.isHeadsetAvailable()) {
availableDevices.add(DEVICE_BLUETOOTH);
} else {
availableDevices.remove(DEVICE_BLUETOOTH);
}
if (mode != -1) {
updateAudioRoute(mode);
}
}
/**
* Helper method to trigger an audio route update when a headset is plugged
* or unplugged.
*
* Only used on Android < M.
*/
void onHeadsetDeviceChange() {
runInAudioThread(new Runnable() {
@Override
public void run() {
// XXX: isWiredHeadsetOn is not deprecated when used just for
// knowing if there is a wired headset connected, regardless of
// audio being routed to it.
//noinspection deprecation
if (audioManager.isWiredHeadsetOn()) {
availableDevices.add(DEVICE_HEADPHONES);
} else {
availableDevices.remove(DEVICE_HEADPHONES);
}
if (mode != -1) {
updateAudioRoute(mode);
}
}
});
}
/**
* {@link AudioManager.OnAudioFocusChangeListener} interface method. Called
* when the audio focus of the system is updated.
*
* @param focusChange - The type of focus change.
* Initializes the audio device handler module. This function is called *after* all Catalyst
* modules have been created, and that's why we use it, because {@link AudioDeviceHandlerConnectionService}
* needs access to another Catalyst module, so doing this in the constructor would be too early.
*/
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN: {
Log.d(TAG, "Audio focus gained");
// Some other application potentially stole our audio focus
// temporarily. Restore our mode.
if (audioFocusLost) {
updateAudioRoute(mode);
}
audioFocusLost = false;
break;
}
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
Log.d(TAG, "Audio focus lost");
audioFocusLost = true;
break;
public void initialize() {
setAudioDeviceHandler();
}
private void setAudioDeviceHandler() {
if (audioDeviceHandler != null) {
audioDeviceHandler.stop();
}
if (useConnectionService()) {
audioDeviceHandler = new AudioDeviceHandlerConnectionService();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
audioDeviceHandler = new AudioDeviceHandlerGeneric();
} else {
audioDeviceHandler = new AudioDeviceHandlerLegacy();
}
audioDeviceHandler.start(getReactApplicationContext(), this);
}
/**
* Helper function to run operations on a dedicated thread.
* @param runnable
*/
public void runInAudioThread(Runnable runnable) {
void runInAudioThread(Runnable runnable) {
executor.execute(runnable);
}
@@ -403,13 +236,13 @@ class AudioModeModule
@Override
public void run() {
if (!availableDevices.contains(device)) {
Log.d(TAG, "Audio device not available: " + device);
JitsiMeetLogger.w(TAG + " Audio device not available: " + device);
userSelectedDevice = null;
return;
}
if (mode != -1) {
Log.d(TAG, "User selected device set to: " + device);
JitsiMeetLogger.i(TAG + " User selected device set to: " + device);
userSelectedDevice = device;
updateAudioRoute(mode);
}
@@ -417,21 +250,6 @@ class AudioModeModule
});
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
/**
* Public method to set the current audio mode.
*
@@ -446,7 +264,7 @@ class AudioModeModule
return;
}
Runnable r = new Runnable() {
runInAudioThread(new Runnable() {
@Override
public void run() {
boolean success;
@@ -455,80 +273,28 @@ class AudioModeModule
success = updateAudioRoute(mode);
} catch (Throwable e) {
success = false;
Log.e(
TAG,
"Failed to update audio route for mode: " + mode,
e);
JitsiMeetLogger.e(e, TAG + " Failed to update audio route for mode: " + mode);
}
if (success) {
AudioModeModule.this.mode = mode;
promise.resolve(null);
} else {
promise.reject(
"setMode",
"Failed to set audio mode to " + mode);
promise.reject("setMode", "Failed to set audio mode to " + mode);
}
}
};
runInAudioThread(r);
});
}
/**
* Setup the audio route change detection mechanism. We use the
* {@link android.media.AudioDeviceCallback} API on Android >= 23 only.
* Sets whether ConnectionService should be used (if available) for setting the audio mode
* or not.
*
* @param use Boolean indicator of where it should be used or not.
*/
private void setupAudioRouteChangeDetection() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupAudioRouteChangeDetectionM();
} else {
setupAudioRouteChangeDetectionPreM();
}
}
/**
* Audio route change detection mechanism for Android API >= 23.
*/
@TargetApi(Build.VERSION_CODES.M)
private void setupAudioRouteChangeDetectionM() {
android.media.AudioDeviceCallback audioDeviceCallback =
new android.media.AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(
AudioDeviceInfo[] addedDevices) {
Log.d(TAG, "Audio devices added");
onAudioDeviceChange();
}
@Override
public void onAudioDevicesRemoved(
AudioDeviceInfo[] removedDevices) {
Log.d(TAG, "Audio devices removed");
onAudioDeviceChange();
}
};
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
}
/**
* Audio route change detection mechanism for Android API < 23.
*/
private void setupAudioRouteChangeDetectionPreM() {
Context context = getReactApplicationContext();
// Detect changes in wired headset connections.
IntentFilter wiredHeadSetFilter = new IntentFilter(ACTION_HEADSET_PLUG);
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Wired headset added / removed");
onHeadsetDeviceChange();
}
};
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
// Detect Bluetooth device changes.
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(this, context);
@ReactMethod
public void setUseConnectionService(boolean use) {
useConnectionService_ = use;
setAudioDeviceHandler();
}
/**
@@ -539,34 +305,21 @@ class AudioModeModule
* {@code false}, otherwise.
*/
private boolean updateAudioRoute(int mode) {
Log.d(TAG, "Update audio route for mode: " + mode);
JitsiMeetLogger.i(TAG + " Update audio route for mode: " + mode);
if (mode == DEFAULT) {
audioFocusLost = false;
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(this);
audioManager.setSpeakerphoneOn(false);
setBluetoothAudioRoute(false);
selectedDevice = null;
userSelectedDevice = null;
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(
this,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.d(TAG, "Audio focus request failed");
if (!audioDeviceHandler.setMode(mode)) {
return false;
}
if (mode == DEFAULT) {
selectedDevice = null;
userSelectedDevice = null;
notifyDevicesChanged();
return true;
}
boolean bluetoothAvailable = availableDevices.contains(DEVICE_BLUETOOTH);
boolean earpieceAvailable = availableDevices.contains(DEVICE_EARPIECE);
boolean headsetAvailable = availableDevices.contains(DEVICE_HEADPHONES);
// Pick the desired device based on what's available and the mode.
@@ -575,15 +328,12 @@ class AudioModeModule
audioDevice = DEVICE_BLUETOOTH;
} else if (headsetAvailable) {
audioDevice = DEVICE_HEADPHONES;
} else if (mode == AUDIO_CALL && earpieceAvailable) {
audioDevice = DEVICE_EARPIECE;
} else {
audioDevice = DEVICE_SPEAKER;
}
// Consider the user's selection
if (userSelectedDevice != null
&& availableDevices.contains(userSelectedDevice)) {
if (userSelectedDevice != null && availableDevices.contains(userSelectedDevice)) {
audioDevice = userSelectedDevice;
}
@@ -594,14 +344,99 @@ class AudioModeModule
}
selectedDevice = audioDevice;
Log.d(TAG, "Selected audio device: " + audioDevice);
JitsiMeetLogger.i(TAG + " Selected audio device: " + audioDevice);
// Turn bluetooth on / off
setBluetoothAudioRoute(audioDevice.equals(DEVICE_BLUETOOTH));
// Turn speaker on / off
audioManager.setSpeakerphoneOn(audioDevice.equals(DEVICE_SPEAKER));
audioDeviceHandler.setAudioRoute(audioDevice);
notifyDevicesChanged();
return true;
}
/**
* Gets the currently selected audio device.
*
* @return The selected audio device.
*/
String getSelectedDevice() {
return selectedDevice;
}
/**
* Resets the current device selection.
*/
void resetSelectedDevice() {
selectedDevice = null;
userSelectedDevice = null;
}
/**
* Adds a new device to the list of available devices.
*
* @param device The new device.
*/
void addDevice(String device) {
availableDevices.add(device);
resetSelectedDevice();
}
/**
* Removes a device from the list of available devices.
*
* @param device The old device to the removed.
*/
void removeDevice(String device) {
availableDevices.remove(device);
resetSelectedDevice();
}
/**
* Replaces the current list of available devices with a new one.
*
* @param devices The new devices list.
*/
void replaceDevices(Set<String> devices) {
availableDevices = devices;
resetSelectedDevice();
}
/**
* Re-sets the current audio route. Needed when devices changes have happened.
*/
void updateAudioRoute() {
if (mode != -1) {
updateAudioRoute(mode);
}
}
/**
* Interface for the modules implementing the actual audio device management.
*/
interface AudioDeviceHandlerInterface {
/**
* Start detecting audio device changes.
* @param context Android {@link Context} where detection should take place.
* @param audioModeModule Reference to the main {@link AudioModeModule}.
*/
void start(Context context, AudioModeModule audioModeModule);
/**
* Stop audio device detection.
*/
void stop();
/**
* Set the appropriate route for the given audio device.
*
* @param device Audio device for which the route must be set.
*/
void setAudioRoute(String device);
/**
* Set the given audio mode.
*
* @param mode The new audio mode to be used.
* @return Whether the operation was successful or not.
*/
boolean setMode(int mode);
}
}

View File

@@ -20,15 +20,16 @@ package org.jitsi.meet.sdk;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.ReadableMap;
import com.rnimmersive.RNImmersiveModule;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -77,6 +78,15 @@ public abstract class BaseReactView<ListenerT>
return null;
}
/**
* Gets all registered React views.
*
* @return An {@link ArrayList} containing all views currently held by React.
*/
static ArrayList<BaseReactView> getViews() {
return new ArrayList<>(views);
}
/**
* The unique identifier of this {@code BaseReactView} within the process
* for the purposes of {@link ExternalAPIModule}. The name scope was
@@ -101,8 +111,7 @@ public abstract class BaseReactView<ListenerT>
setBackgroundColor(BACKGROUND_COLOR);
ReactInstanceManagerHolder.initReactInstanceManager(
((Activity) context).getApplication());
ReactInstanceManagerHolder.initReactInstanceManager((Activity)context);
// Hook this BaseReactView into ExternalAPI.
externalAPIScope = UUID.randomUUID().toString();
@@ -170,7 +179,7 @@ public abstract class BaseReactView<ListenerT>
* @param data - The details of the event associated with/specific to the
* specified {@code name}.
*/
public abstract void onExternalAPIEvent(String name, ReadableMap data);
protected abstract void onExternalAPIEvent(String name, ReadableMap data);
protected void onExternalAPIEvent(
Map<String, Method> listenerMethods,

View File

@@ -1,5 +1,5 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
* Copyright @ 2017-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.
@@ -24,7 +24,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.util.Log;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* Helper class to detect and handle Bluetooth device changes. It monitors
@@ -32,68 +33,43 @@ import android.util.Log;
* about device changes when this occurs.
*/
class BluetoothHeadsetMonitor {
/**
* {@link AudioModeModule} where this monitor reports.
*/
private final AudioModeModule audioModeModule;
private final static String TAG = BluetoothHeadsetMonitor.class.getSimpleName();
/**
* The {@link Context} in which {@link #audioModeModule} executes.
* The {@link Context} in which this module executes.
*/
private final Context context;
/**
* Reference to the {@link BluetoothAdapter} object, used to access Bluetooth functionality.
*/
private BluetoothAdapter adapter;
/**
* Reference to a proxy object which allows us to query connected devices.
*/
private BluetoothHeadset headset;
/**
* Flag indicating if there are any Bluetooth headset devices currently
* available.
* receiver registered for receiving Bluetooth connection state changes.
*/
private boolean headsetAvailable = false;
private BroadcastReceiver receiver;
/**
* Helper for running Bluetooth operations on the main thread.
* Listener for receiving Bluetooth device change events.
*/
private final Runnable updateDevicesRunnable
= new Runnable() {
@Override
public void run() {
headsetAvailable
= (headset != null)
&& !headset.getConnectedDevices().isEmpty();
audioModeModule.onBluetoothDeviceChange();
}
};
private Listener listener;
public BluetoothHeadsetMonitor(
AudioModeModule audioModeModule,
Context context) {
this.audioModeModule = audioModeModule;
public BluetoothHeadsetMonitor(Context context, Listener listener) {
this.context = context;
AudioManager audioManager
= (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
Log.w(AudioModeModule.TAG, "Bluetooth SCO is not available");
return;
}
if (getBluetoothHeadsetProfileProxy()) {
registerBluetoothReceiver();
// Initial detection.
updateDevices();
}
this.listener = listener;
}
private boolean getBluetoothHeadsetProfileProxy() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null) {
Log.w(AudioModeModule.TAG, "Device doesn't support Bluetooth");
JitsiMeetLogger.w(TAG + " Device doesn't support Bluetooth");
return false;
}
@@ -103,9 +79,7 @@ class BluetoothHeadsetMonitor {
BluetoothProfile.ServiceListener listener
= new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(
int profile,
BluetoothProfile proxy) {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
headset = (BluetoothHeadset) proxy;
updateDevices();
@@ -119,21 +93,7 @@ class BluetoothHeadsetMonitor {
}
};
return
adapter.getProfileProxy(
context,
listener,
BluetoothProfile.HEADSET);
}
/**
* Returns the current headset availability.
*
* @return {@code true} if there is a Bluetooth headset connected;
* {@code false}, otherwise.
*/
public boolean isHeadsetAvailable() {
return headsetAvailable;
return adapter.getProfileProxy(context, listener, BluetoothProfile.HEADSET);
}
private void onBluetoothReceiverReceive(Context context, Intent intent) {
@@ -148,9 +108,7 @@ class BluetoothHeadsetMonitor {
switch (state) {
case BluetoothHeadset.STATE_CONNECTED:
case BluetoothHeadset.STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT headset connection state changed: " + state);
JitsiMeetLogger.d(TAG + " BT headset connection state changed: " + state);
updateDevices();
break;
}
@@ -158,15 +116,12 @@ class BluetoothHeadsetMonitor {
// XXX: This action will be fired when the connection established
// with a Bluetooth headset (called a SCO connection) changes state.
// When the SCO connection is active we route audio to it.
int state
= intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
switch (state) {
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT SCO connection state changed: " + state);
JitsiMeetLogger.d(TAG + " BT SCO connection state changed: " + state);
updateDevices();
break;
}
@@ -174,24 +129,63 @@ class BluetoothHeadsetMonitor {
}
private void registerBluetoothReceiver() {
BroadcastReceiver receiver = new BroadcastReceiver() {
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onBluetoothReceiverReceive(context, intent);
}
};
IntentFilter filter = new IntentFilter();
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
context.registerReceiver(receiver, filter);
}
/**
* Detects if there are new devices connected / disconnected and fires the
* {@link AudioModeModule#onAudioDeviceChange()} callback.
* {@link Listener} registered event.
*/
private void updateDevices() {
audioModeModule.runInAudioThread(updateDevicesRunnable);
boolean headsetAvailable = (headset != null) && !headset.getConnectedDevices().isEmpty();
listener.onBluetoothDeviceChange(headsetAvailable);
}
public void start() {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
JitsiMeetLogger.w(TAG + " Bluetooth SCO is not available");
return;
}
if (!getBluetoothHeadsetProfileProxy()) {
JitsiMeetLogger.w(TAG + " Couldn't get BT profile proxy");
return;
}
registerBluetoothReceiver();
// Initial detection.
updateDevices();
}
public void stop() {
if (receiver != null) {
context.unregisterReceiver(receiver);
}
if (adapter != null && headset != null) {
adapter.closeProfileProxy(BluetoothProfile.HEADSET, headset);
}
receiver = null;
headset = null;
adapter = null;
}
interface Listener {
void onBluetoothDeviceChange(boolean deviceAvailable);
}
}

View File

@@ -0,0 +1,449 @@
package org.jitsi.meet.sdk;
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.telecom.CallAudioState;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableNativeMap;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Jitsi Meet implementation of {@link ConnectionService}. At the time of this
* writing it implements only the outgoing call scenario.
*
* NOTE the class needs to be public, but is not part of the SDK API and should
* never be used directly.
*
* @author Pawel Domas
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public class ConnectionService extends android.telecom.ConnectionService {
/**
* Tag used for logging.
*/
static final String TAG = "JitsiConnectionService";
/**
* The extra added to the {@link ConnectionImpl} and
* {@link ConnectionRequest} which stores the {@link PhoneAccountHandle}
* created for the call.
*/
static final String EXTRA_PHONE_ACCOUNT_HANDLE
= "org.jitsi.meet.sdk.connection_service.PHONE_ACCOUNT_HANDLE";
/**
* Connections mapped by call UUID.
*/
static private final Map<String, ConnectionImpl> connections
= new HashMap<>();
/**
* The start call Promises mapped by call UUID.
*/
static private final HashMap<String, Promise> startCallPromises
= new HashMap<>();
/**
* Aborts all ongoing connections. This is a last resort mechanism which forces all resources to
* be freed on the system in case of fatal error.
*/
static void abortConnections() {
for (ConnectionImpl connection: getConnections()) {
connection.onAbort();
}
}
/**
* Adds {@link ConnectionImpl} to the list.
*
* @param connection - {@link ConnectionImpl}
*/
static void addConnection(ConnectionImpl connection) {
connections.put(connection.getCallUUID(), connection);
}
/**
* Returns all {@link ConnectionImpl} instances held in this list.
*
* @return a list of {@link ConnectionImpl}.
*/
static List<ConnectionImpl> getConnections() {
return new ArrayList<>(connections.values());
}
/**
* @return {@code true} if running a Samsung device.
*/
static boolean isSamsungDevice() {
return android.os.Build.MANUFACTURER.toLowerCase().contains("samsung");
}
/**
* Registers a start call promise.
*
* @param uuid - the call UUID to which the start call promise belongs to.
* @param promise - the Promise instance to be stored for later use.
*/
static void registerStartCallPromise(String uuid, Promise promise) {
startCallPromises.put(uuid, promise);
}
/**
* Removes {@link ConnectionImpl} from the list.
*
* @param connection - {@link ConnectionImpl}
*/
static void removeConnection(ConnectionImpl connection) {
connections.remove(connection.getCallUUID());
}
/**
* Used to adjusts the connection's state to
* {@link android.telecom.Connection#STATE_ACTIVE}.
*
* @param callUUID the call UUID which identifies the connection.
*/
static void setConnectionActive(String callUUID) {
ConnectionImpl connection = connections.get(callUUID);
if (connection != null) {
connection.setActive();
} else {
JitsiMeetLogger.e("%s setConnectionActive - no connection for UUID: %s", TAG, callUUID);
}
}
/**
* Used to adjusts the connection's state to
* {@link android.telecom.Connection#STATE_DISCONNECTED}.
*
* @param callUUID the call UUID which identifies the connection.
* @param cause disconnection reason.
*/
static void setConnectionDisconnected(String callUUID, DisconnectCause cause) {
ConnectionImpl connection = connections.get(callUUID);
if (connection != null) {
if (isSamsungDevice()) {
// Required to release the audio focus correctly.
connection.setOnHold();
// Prevents from including in the native phone calls history
connection.setConnectionProperties(
Connection.PROPERTY_SELF_MANAGED
| Connection.PROPERTY_IS_EXTERNAL_CALL);
}
// Note that the connection is not removed from the list here, but
// in ConnectionImpl's state changed callback. It's a safer
// approach, because in case the app would crash on the JavaScript
// side the calls would be cleaned up by the system they would still
// be removed from the ConnectionList.
connection.setDisconnected(cause);
connection.destroy();
} else {
JitsiMeetLogger.e(TAG + " endCall no connection for UUID: " + callUUID);
}
}
/**
* Unregisters a start call promise. Must be called after the Promise is
* rejected or resolved.
*
* @param uuid the call UUID which identifies the call to which the promise
* belongs to.
* @return the unregistered Promise instance or <tt>null</tt> if there
* wasn't any for the given call UUID.
*/
static Promise unregisterStartCallPromise(String uuid) {
return startCallPromises.remove(uuid);
}
/**
* Used to adjusts the call's state.
*
* @param callUUID the call UUID which identifies the connection.
* @param callState a map which carries the properties to be modified. See
* "KEY_*" constants in {@link ConnectionImpl} for the list of keys.
*/
static void updateCall(String callUUID, ReadableMap callState) {
ConnectionImpl connection = connections.get(callUUID);
if (connection != null) {
if (callState.hasKey(ConnectionImpl.KEY_HAS_VIDEO)) {
boolean hasVideo
= callState.getBoolean(ConnectionImpl.KEY_HAS_VIDEO);
JitsiMeetLogger.i(" %s updateCall: %s hasVideo: %s", TAG, callUUID, hasVideo);
connection.setVideoState(
hasVideo
? VideoProfile.STATE_BIDIRECTIONAL
: VideoProfile.STATE_AUDIO_ONLY);
}
} else {
JitsiMeetLogger.e(TAG + " updateCall no connection for UUID: " + callUUID);
}
}
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle accountHandle, ConnectionRequest request) {
ConnectionImpl connection = new ConnectionImpl();
connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
connection.setAddress(
request.getAddress(),
TelecomManager.PRESENTATION_UNKNOWN);
connection.setExtras(request.getExtras());
connection.setAudioModeIsVoip(true);
// NOTE there's a time gap between the placeCall and this callback when
// things could get out of sync, but they are put back in sync once
// the startCall Promise is resolved below. That's because on
// the JavaScript side there's a logic to sync up in .then() callback.
connection.setVideoState(request.getVideoState());
Bundle moreExtras = new Bundle();
moreExtras.putParcelable(
EXTRA_PHONE_ACCOUNT_HANDLE,
Objects.requireNonNull(request.getAccountHandle(), "accountHandle"));
connection.putExtras(moreExtras);
addConnection(connection);
Promise startCallPromise
= unregisterStartCallPromise(connection.getCallUUID());
if (startCallPromise != null) {
JitsiMeetLogger.d(TAG + " onCreateOutgoingConnection " + connection.getCallUUID());
startCallPromise.resolve(null);
} else {
JitsiMeetLogger.e(
TAG + " onCreateOutgoingConnection: no start call Promise for " + connection.getCallUUID());
}
return connection;
}
@Override
public Connection onCreateIncomingConnection(
PhoneAccountHandle accountHandle, ConnectionRequest request) {
throw new RuntimeException("Not implemented");
}
@Override
public void onCreateIncomingConnectionFailed(
PhoneAccountHandle accountHandle, ConnectionRequest request) {
throw new RuntimeException("Not implemented");
}
@Override
public void onCreateOutgoingConnectionFailed(
PhoneAccountHandle accountHandle, ConnectionRequest request) {
PhoneAccountHandle theAccountHandle = request.getAccountHandle();
String callUUID = theAccountHandle.getId();
JitsiMeetLogger.e(TAG + " onCreateOutgoingConnectionFailed " + callUUID);
if (callUUID != null) {
Promise startCallPromise = unregisterStartCallPromise(callUUID);
if (startCallPromise != null) {
startCallPromise.reject(
"CREATE_OUTGOING_CALL_FAILED",
"The request has been denied by the system");
} else {
JitsiMeetLogger.e(TAG + " startCallFailed - no start call Promise for UUID: " + callUUID);
}
} else {
JitsiMeetLogger.e(TAG + " onCreateOutgoingConnectionFailed - no call UUID");
}
unregisterPhoneAccount(theAccountHandle);
}
private void unregisterPhoneAccount(PhoneAccountHandle phoneAccountHandle) {
TelecomManager telecom = getSystemService(TelecomManager.class);
if (telecom != null) {
if (phoneAccountHandle != null) {
telecom.unregisterPhoneAccount(phoneAccountHandle);
} else {
JitsiMeetLogger.e(TAG + " unregisterPhoneAccount - account handle is null");
}
} else {
JitsiMeetLogger.e(TAG + " unregisterPhoneAccount - telecom is null");
}
}
/**
* Registers new {@link PhoneAccountHandle}.
*
* @param context the current Android context.
* @param address the phone account's address. At the time of this writing
* it's the call handle passed from the Java Script side.
* @param callUUID the call's UUID for which the account is to be created.
* It will be used as the account's id.
* @return {@link PhoneAccountHandle} described by the given arguments.
*/
static PhoneAccountHandle registerPhoneAccount(
Context context, Uri address, String callUUID) {
PhoneAccountHandle phoneAccountHandle
= new PhoneAccountHandle(
new ComponentName(context, ConnectionService.class),
callUUID);
PhoneAccount.Builder builder
= PhoneAccount.builder(phoneAccountHandle, address.toString())
.setAddress(address)
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING)
.addSupportedUriScheme(PhoneAccount.SCHEME_SIP);
PhoneAccount account = builder.build();
TelecomManager telecomManager
= context.getSystemService(TelecomManager.class);
telecomManager.registerPhoneAccount(account);
return phoneAccountHandle;
}
/**
* Connection implementation for Jitsi Meet's {@link ConnectionService}.
*
* @author Pawel Domas
*/
class ConnectionImpl extends Connection {
/**
* The constant which defines the key for the "has video" property.
* The key is used in the map which carries the call's state passed as
* the argument of the {@link RNConnectionService#updateCall} method.
*/
static final String KEY_HAS_VIDEO = "hasVideo";
/**
* Called when system wants to disconnect the call.
*
* {@inheritDoc}
*/
@Override
public void onDisconnect() {
JitsiMeetLogger.i(TAG + " onDisconnect " + getCallUUID());
WritableNativeMap data = new WritableNativeMap();
data.putString("callUUID", getCallUUID());
ReactInstanceManagerHolder.emitEvent(
"org.jitsi.meet:features/connection_service#disconnect",
data);
// The JavaScript side will not go back to the native with
// 'endCall', so the Connection must be removed immediately.
setConnectionDisconnected(
getCallUUID(),
new DisconnectCause(DisconnectCause.LOCAL));
}
/**
* Called when system wants to abort the call.
*
* {@inheritDoc}
*/
@Override
public void onAbort() {
JitsiMeetLogger.i(TAG + " onAbort " + getCallUUID());
WritableNativeMap data = new WritableNativeMap();
data.putString("callUUID", getCallUUID());
ReactInstanceManagerHolder.emitEvent(
"org.jitsi.meet:features/connection_service#abort",
data);
// The JavaScript side will not go back to the native with
// 'endCall', so the Connection must be removed immediately.
setConnectionDisconnected(
getCallUUID(),
new DisconnectCause(DisconnectCause.CANCELED));
}
@Override
public void onHold() {
// What ?! Android will still call this method even if we do not add
// the HOLD capability, so do the same thing as on abort.
// TODO implement HOLD
JitsiMeetLogger.w(TAG + " onHold %s - HOLD is not supported, aborting the call...", getCallUUID());
this.onAbort();
}
/**
* Called when there's change to the call audio state. Either by
* the system after the connection is initialized or in response to
* {@link #setAudioRoute(int)}.
*
* @param state the new {@link CallAudioState}
*/
@Override
public void onCallAudioStateChanged(CallAudioState state) {
JitsiMeetLogger.d(TAG + " onCallAudioStateChanged: " + state);
RNConnectionService module = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (module != null) {
module.onCallAudioStateChange(state);
}
}
/**
* Unregisters the account when the call is disconnected.
*
* @param state - the new connection's state.
*/
@Override
public void onStateChanged(int state) {
JitsiMeetLogger.d(
"%s onStateChanged: %s %s", TAG, Connection.stateToString(state), getCallUUID());
if (state == STATE_DISCONNECTED) {
removeConnection(this);
unregisterPhoneAccount(getPhoneAccountHandle());
}
}
/**
* Retrieves the UUID of the call associated with this connection.
*
* @return call UUID
*/
String getCallUUID() {
return getPhoneAccountHandle().getId();
}
private PhoneAccountHandle getPhoneAccountHandle() {
return getExtras().getParcelable(
ConnectionService.EXTRA_PHONE_ACCOUNT_HANDLE);
}
@Override
public String toString() {
return String.format(
"ConnectionImpl[address=%s, uuid=%s]@%d",
getAddress(), getCallUUID(), hashCode());
}
}
}

View File

@@ -22,7 +22,7 @@ import android.app.Activity;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
/**
* Defines the default behavior of {@code JitsiMeetActivity} and
* Defines the default behavior of {@code JitsiMeetFragment} and
* {@code JitsiMeetView} upon invoking the back button if no
* {@code JitsiMeetView} handles the invocation. For example, a
* {@code JitsiMeetView} may (1) handle the invocation of the back button

View File

@@ -1,4 +1,4 @@
package org.jitsi.meet.sdk.dropbox;
package org.jitsi.meet.sdk;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -20,6 +20,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.dropbox.core.android.Auth;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import java.util.HashMap;
import java.util.Map;
@@ -27,9 +28,13 @@ import java.util.Map;
/**
* Implements the react-native module for the dropbox integration.
*/
public class Dropbox
@ReactModule(name = DropboxModule.NAME)
class DropboxModule
extends ReactContextBaseJavaModule
implements LifecycleEventListener {
public static final String NAME = "Dropbox";
private String appKey;
private String clientId;
@@ -38,12 +43,14 @@ public class Dropbox
private Promise promise;
public Dropbox(ReactApplicationContext reactContext) {
public DropboxModule(ReactApplicationContext reactContext) {
super(reactContext);
String pkg = reactContext.getApplicationContext().getPackageName();
int resId = reactContext.getResources()
.getIdentifier("dropbox_app_key", "string", pkg);
appKey
= reactContext.getString(
org.jitsi.meet.sdk.R.string.dropbox_app_key);
= reactContext.getString(resId);
isEnabled = !TextUtils.isEmpty(appKey);
clientId = generateClientId();
@@ -129,7 +136,7 @@ public class Dropbox
@Override
public String getName() {
return "Dropbox";
return NAME;
}
/**

View File

@@ -16,20 +16,24 @@
package org.jitsi.meet.sdk;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* Module implementing an API for sending events from JavaScript to native code.
*/
@ReactModule(name = ExternalAPIModule.NAME)
class ExternalAPIModule
extends ReactContextBaseJavaModule {
private static final String TAG = ExternalAPIModule.class.getSimpleName();
public static final String NAME = "ExternalAPI";
private static final String TAG = NAME;
/**
* Initializes a new module instance. There shall be a single instance of
@@ -49,7 +53,7 @@ class ExternalAPIModule
*/
@Override
public String getName() {
return "ExternalAPI";
return NAME;
}
/**
@@ -63,16 +67,20 @@ class ExternalAPIModule
*/
@ReactMethod
public void sendEvent(String name, ReadableMap data, String scope) {
// Keep track of the current ongoing conference.
OngoingConferenceTracker.getInstance().onExternalAPIEvent(name, data);
// 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 BaseReactView which hosts it.
BaseReactView view = BaseReactView.findViewByExternalAPIScope(scope);
if (view != null) {
JitsiMeetLogger.d(TAG + " Sending event: " + name + " with data: " + data);
try {
view.onExternalAPIEvent(name, data);
} catch(Exception e) {
Log.e(TAG, "onExternalAPIEvent: error sending event", e);
JitsiMeetLogger.e(e, TAG + " onExternalAPIEvent: error sending event");
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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 com.facebook.react.bridge.Promise;
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;
import com.squareup.duktape.Duktape;
@ReactModule(name = JavaScriptSandboxModule.NAME)
class JavaScriptSandboxModule extends ReactContextBaseJavaModule {
public static final String NAME = "JavaScriptSandbox";
public JavaScriptSandboxModule(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* Evaluates the given code in a Duktape VM.
* @param code - The code that needs to evaluated.
* @param promise - Resolved with the output in case of success or rejected with an exception
* in case of failure.
*/
@ReactMethod
public void evaluate(String code, Promise promise) {
Duktape vm = Duktape.create();
try {
Object res = vm.evaluate(code);
promise.resolve(res.toString());
} catch (Throwable tr) {
promise.reject(tr);
} finally {
vm.close();
}
}
@Override
public String getName() {
return NAME;
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* 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.os.Bundle;
import com.facebook.react.ReactInstanceManager;
public class JitsiMeet {
/**
* Default {@link JitsiMeetConferenceOptions} which will be used for all conferences. When
* joining a conference these options will be merged with the ones passed to
* {@link JitsiMeetView} join().
*/
private static JitsiMeetConferenceOptions defaultConferenceOptions;
public static JitsiMeetConferenceOptions getDefaultConferenceOptions() {
return defaultConferenceOptions;
}
public static void setDefaultConferenceOptions(JitsiMeetConferenceOptions options) {
if (options != null && options.getRoom() != null) {
throw new RuntimeException("'room' must be null in the default conference options");
}
defaultConferenceOptions = options;
}
/**
* Returns the current conference URL as a string.
*
* @return the current conference URL.
*/
public static String getCurrentConference() {
return OngoingConferenceTracker.getInstance().getCurrentConference();
}
/**
* Helper to get the default conference options as a {@link Bundle}.
*
* @return a {@link Bundle} with the default conference options.
*/
static Bundle getDefaultProps() {
if (defaultConferenceOptions != null) {
return defaultConferenceOptions.asProps();
}
return new Bundle();
}
/**
* Used in development mode. It displays the React Native development menu.
*/
public static void showDevOptions() {
ReactInstanceManager reactInstanceManager
= ReactInstanceManagerHolder.getReactInstanceManager();
if (reactInstanceManager != null) {
reactInstanceManager.showDevOptionsDialog();
}
}
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright @ 2019-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,309 +16,212 @@
package org.jitsi.meet.sdk;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.modules.core.PermissionListener;
import java.net.URL;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.Map;
/**
* Base Activity for applications integrating Jitsi Meet at a higher level. It
* contains all the required wiring between the {@code JitsiMeetView} and
* the Activity lifecycle methods already implemented.
*
* 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 lifetime methods associated with this Activity are
* hooked to the React Native subsystem via proxy calls through the
* {@code JitsiMeetView} static methods.
* 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.
*/
public class JitsiMeetActivity
extends AppCompatActivity implements JitsiMeetActivityInterface {
public class JitsiMeetActivity extends FragmentActivity
implements JitsiMeetActivityInterface, JitsiMeetViewListener {
/**
* The request code identifying requests for the permission to draw on top
* of other apps. The value must be 16-bit and is arbitrarily chosen here.
*/
private static final int OVERLAY_PERMISSION_REQUEST_CODE
= (int) (Math.random() * Short.MAX_VALUE);
protected static final String TAG = JitsiMeetActivity.class.getSimpleName();
/**
* The default base {@code URL} used to join a conference when a partial URL
* (e.g. a room name only) is specified. The value is used only while
* {@link #view} equals {@code null}.
*/
private URL defaultURL;
private static final String ACTION_JITSI_MEET_CONFERENCE = "org.jitsi.meet.CONFERENCE";
private static final String JITSI_MEET_CONFERENCE_OPTIONS = "JitsiMeetConferenceOptions";
/**
* Instance of the {@link JitsiMeetView} which this activity will display.
*/
private JitsiMeetView view;
// Helpers for starting the activity
//
/**
* Whether Picture-in-Picture is enabled. The value is used only while
* {@link #view} equals {@code null}.
*/
private Boolean pictureInPictureEnabled;
/**
* Whether the Welcome page is enabled. The value is used only while
* {@link #view} equals {@code null}.
*/
private boolean welcomePageEnabled;
private boolean canRequestOverlayPermission() {
return
BuildConfig.DEBUG
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.M;
public static void launch(Context context, JitsiMeetConferenceOptions options) {
Intent intent = new Intent(context, JitsiMeetActivity.class);
intent.setAction(ACTION_JITSI_MEET_CONFERENCE);
intent.putExtra(JITSI_MEET_CONFERENCE_OPTIONS, options);
context.startActivity(intent);
}
/**
*
* @see JitsiMeetView#getDefaultURL()
*/
public URL getDefaultURL() {
return view == null ? defaultURL : view.getDefaultURL();
public static void launch(Context context, String url) {
JitsiMeetConferenceOptions options
= new JitsiMeetConferenceOptions.Builder().setRoom(url).build();
launch(context, options);
}
/**
* Initializes the {@link #view} of this {@code JitsiMeetActivity} with a
* new {@link JitsiMeetView} instance.
*/
private void initializeContentView() {
JitsiMeetView view = initializeView();
if (view != null) {
// XXX Allow extenders who override initializeView() to configure
// the view before the first loadURL(). Probably works around a
// problem related to ReactRootView#setAppProperties().
view.loadURL(null);
this.view = view;
setContentView(this.view);
}
}
/**
* Initializes a new {@link JitsiMeetView} instance.
*
* @return a new {@code JitsiMeetView} instance.
*/
protected JitsiMeetView initializeView() {
JitsiMeetView view = new JitsiMeetView(this);
// XXX Before calling JitsiMeetView#loadURL, make sure to call whatever
// is documented to need such an order in order to take effect:
view.setDefaultURL(defaultURL);
if (pictureInPictureEnabled != null) {
view.setPictureInPictureEnabled(
pictureInPictureEnabled.booleanValue());
}
view.setWelcomePageEnabled(welcomePageEnabled);
return view;
}
/**
*
* @see JitsiMeetView#isPictureInPictureEnabled()
*/
public boolean isPictureInPictureEnabled() {
return
view == null
? pictureInPictureEnabled
: view.isPictureInPictureEnabled();
}
/**
*
* @see JitsiMeetView#isWelcomePageEnabled()
*/
public boolean isWelcomePageEnabled() {
return view == null ? welcomePageEnabled : view.isWelcomePageEnabled();
}
/**
* 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.
*/
public void loadURL(@Nullable URL url) {
view.loadURL(url);
}
@Override
protected void onActivityResult(
int requestCode,
int resultCode,
Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
&& canRequestOverlayPermission()) {
if (Settings.canDrawOverlays(this)) {
initializeContentView();
}
return;
}
ReactActivityLifecycleCallbacks.onActivityResult(
this, requestCode, resultCode, data);
}
@Override
public void onBackPressed() {
ReactActivityLifecycleCallbacks.onBackPressed();
}
// Overrides
//
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// In Debug builds React needs permission to write over other apps in
// order to display the warning and error overlays.
if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
setContentView(R.layout.activity_jitsi_meet);
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
return;
if (!extraInitialize()) {
initialize();
}
initializeContentView();
}
@Override
protected void onDestroy() {
public void onDestroy() {
// Here we are trying to handle the following corner case: an application using the SDK
// is using this Activity for displaying meetings, but there is another "main" Activity
// with other content. If this Activity is "swiped out" from the recent list we will get
// Activity#onDestroy() called without warning. At this point we can try to leave the
// current meeting, but when our view is detached from React the JS <-> Native bridge won't
// 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();
if (AudioModeModule.useConnectionService()) {
ConnectionService.abortConnections();
}
JitsiMeetOngoingConferenceService.abort(this);
super.onDestroy();
if (view != null) {
view.dispose();
view = null;
}
ReactActivityLifecycleCallbacks.onHostDestroy(this);
}
// ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
ReactInstanceManager reactInstanceManager;
public void finish() {
leave();
if (!super.onKeyUp(keyCode, event)
&& BuildConfig.DEBUG
&& (reactInstanceManager
= ReactInstanceManagerHolder.getReactInstanceManager())
!= null
&& keyCode == KeyEvent.KEYCODE_MENU) {
reactInstanceManager.showDevOptionsDialog();
return true;
super.finish();
}
// Helper methods
//
protected JitsiMeetView getJitsiView() {
JitsiMeetFragment fragment
= (JitsiMeetFragment) getSupportFragmentManager().findFragmentById(R.id.jitsiFragment);
return fragment.getJitsiView();
}
public void join(@Nullable String url) {
JitsiMeetConferenceOptions options
= new JitsiMeetConferenceOptions.Builder()
.setRoom(url)
.build();
join(options);
}
public void join(JitsiMeetConferenceOptions options) {
getJitsiView().join(options);
}
public void leave() {
getJitsiView().leave();
}
private @Nullable JitsiMeetConferenceOptions getConferenceOptions(Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
Uri uri = intent.getData();
if (uri != null) {
return new JitsiMeetConferenceOptions.Builder().setRoom(uri.toString()).build();
}
} else if (ACTION_JITSI_MEET_CONFERENCE.equals(action)) {
return intent.getParcelableExtra(JITSI_MEET_CONFERENCE_OPTIONS);
}
return null;
}
/**
* Helper function called during activity initialization. If {@code true} is returned, the
* initialization is delayed and the {@link JitsiMeetActivity#initialize()} method is not
* called. In this case, it's up to the subclass to call the initialize method when ready.
*
* This is mainly required so we do some extra initialization in the Jitsi Meet app.
*
* @return {@code true} if the initialization will be delayed, {@code false} otherwise.
*/
protected boolean extraInitialize() {
return false;
}
protected void initialize() {
// Listen for conference events.
getJitsiView().setListener(this);
// Join the room specified by the URL the app was launched with.
// Joining without the room option displays the welcome page.
join(getConferenceOptions(getIntent()));
}
// Activity lifecycle methods
//
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
JitsiMeetActivityDelegate.onActivityResult(this, requestCode, resultCode, data);
}
@Override
public void onBackPressed() {
JitsiMeetActivityDelegate.onBackPressed();
}
@Override
public void onNewIntent(Intent intent) {
// XXX At least twice we received bug reports about malfunctioning
// loadURL in the Jitsi Meet SDK while the Jitsi Meet app seemed to
// functioning as expected in our testing. But that was to be expected
// because the app does not exercise loadURL. In order to increase the
// test coverage of loadURL, channel deep linking through loadURL.
Uri uri;
super.onNewIntent(intent);
if (Intent.ACTION_VIEW.equals(intent.getAction())
&& (uri = intent.getData()) != null
&& JitsiMeetView.loadURLStringInViews(uri.toString())) {
JitsiMeetConferenceOptions options;
if ((options = getConferenceOptions(intent)) != null) {
join(options);
return;
}
ReactActivityLifecycleCallbacks.onNewIntent(intent);
}
// https://developer.android.com/reference/android/support/v4/app/ActivityCompat.OnRequestPermissionsResultCallback
@Override
public void onRequestPermissionsResult(
final int requestCode,
final String[] permissions,
final int[] grantResults) {
ReactActivityLifecycleCallbacks.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onResume() {
super.onResume();
ReactActivityLifecycleCallbacks.onHostResume(this);
}
@Override
public void onStop() {
super.onStop();
ReactActivityLifecycleCallbacks.onHostPause(this);
JitsiMeetActivityDelegate.onNewIntent(intent);
}
@Override
protected void onUserLeaveHint() {
if (view != null) {
view.enterPictureInPicture();
}
getJitsiView().enterPictureInPicture();
}
/**
* Implementation of the {@code PermissionAwareActivity} interface.
*/
// JitsiMeetActivityInterface
//
@Override
public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) {
ReactActivityLifecycleCallbacks.requestPermissions(this, permissions, requestCode, listener);
JitsiMeetActivityDelegate.requestPermissions(this, permissions, requestCode, listener);
}
/**
*
* @see JitsiMeetView#setDefaultURL(URL)
*/
public void setDefaultURL(URL defaultURL) {
if (view == null) {
this.defaultURL = defaultURL;
} else {
view.setDefaultURL(defaultURL);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
*
* @see JitsiMeetView#setPictureInPictureEnabled(boolean)
*/
public void setPictureInPictureEnabled(boolean pictureInPictureEnabled) {
if (view == null) {
this.pictureInPictureEnabled
= Boolean.valueOf(pictureInPictureEnabled);
} else {
view.setPictureInPictureEnabled(pictureInPictureEnabled);
}
// JitsiMeetViewListener
//
@Override
public void onConferenceJoined(Map<String, Object> data) {
JitsiMeetLogger.i("Conference joined: " + data);
// Launch the service for the ongoing notification.
JitsiMeetOngoingConferenceService.launch(this);
}
/**
*
* @see JitsiMeetView#setWelcomePageEnabled(boolean)
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
if (view == null) {
this.welcomePageEnabled = welcomePageEnabled;
} else {
view.setWelcomePageEnabled(welcomePageEnabled);
}
@Override
public void onConferenceTerminated(Map<String, Object> data) {
JitsiMeetLogger.i("Conference terminated: " + data);
finish();
}
@Override
public void onConferenceWillJoin(Map<String, Object> data) {
JitsiMeetLogger.i("Conference will join: " + data);
}
}

View File

@@ -25,6 +25,7 @@ import android.os.Build;
import com.calendarevents.CalendarEventsPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.PermissionListener;
/**
@@ -32,7 +33,22 @@ import com.facebook.react.modules.core.PermissionListener;
* {@link Activity} lifecycle methods in order for the React side to be aware of
* it.
*/
public class ReactActivityLifecycleCallbacks {
public class JitsiMeetActivityDelegate {
/**
* Needed for making sure this class working with the "PermissionsAndroid"
* React Native module.
*/
private static PermissionListener permissionListener;
private static Callback permissionsCallback;
/**
* Tells whether or not the permissions request is currently in progress.
*
* @return {@code true} if the permssions are being requested or {@code false} otherwise.
*/
static boolean arePermissionsBeingRequested() {
return permissionListener != null;
}
/**
* {@link Activity} lifecycle method which should be called from
@@ -57,13 +73,6 @@ public class ReactActivityLifecycleCallbacks {
}
}
/**
* Needed for making sure this class working with the "PermissionsAndroid"
* React Native module.
*/
private static PermissionListener permissionListener;
private static Callback permissionsCallback;
/**
* {@link Activity} lifecycle method which should be called from
* {@link Activity#onBackPressed} so we can do the required internal
@@ -109,7 +118,13 @@ public class ReactActivityLifecycleCallbacks {
= ReactInstanceManagerHolder.getReactInstanceManager();
if (reactInstanceManager != null) {
reactInstanceManager.onHostPause(activity);
// Try to avoid a crash because some devices trip on this assert:
// https://github.com/facebook/react-native/blob/df4e67fe75d781d1eb264128cadf079989542755/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L512
// Why this happens is a mystery wrapped in an enigma.
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext != null && activity == reactContext.getCurrentActivity()) {
reactInstanceManager.onHostPause(activity);
}
}
}

View File

@@ -1,12 +1,12 @@
package org.jitsi.meet.sdk;
import android.support.v4.app.ActivityCompat;
import androidx.core.app.ActivityCompat;
import com.facebook.react.modules.core.PermissionAwareActivity;
/**
* This interface serves as the umbrella interface that applications not using
* {@code JitsiMeetActivity} must implement in order to ensure full
* {@code JitsiMeetFragment} must implement in order to ensure full
* functionality.
*/
public interface JitsiMeetActivityInterface

View File

@@ -0,0 +1,394 @@
/*
* 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.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import java.net.URL;
/**
* This class represents the options when joining a Jitsi Meet conference. The user can create an
* instance by using {@link JitsiMeetConferenceOptions.Builder} and setting the desired options
* there.
*
* The resulting {@link JitsiMeetConferenceOptions} object is immutable and represents how the
* conference will be joined.
*/
public class JitsiMeetConferenceOptions implements Parcelable {
/**
* Server where the conference should take place.
*/
private URL serverURL;
/**
* Room name.
*/
private String room;
/**
* Conference subject.
*/
private String subject;
/**
* JWT token used for authentication.
*/
private String token;
/**
* Color scheme override, see: https://github.com/jitsi/jitsi-meet/blob/dbedee5e22e5dcf9c92db96ef5bb3c9982fc526d/react/features/base/color-scheme/defaultScheme.js
*/
private Bundle colorScheme;
/**
* Feature flags. See: https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
*/
private Bundle featureFlags;
/**
* Set to {@code true} to join the conference with audio / video muted or to start in audio
* only mode respectively.
*/
private Boolean audioMuted;
private Boolean audioOnly;
private Boolean videoMuted;
/**
* USer information, to be used when no token is specified.
*/
private JitsiMeetUserInfo userInfo;
public URL getServerURL() {
return serverURL;
}
public String getRoom() {
return room;
}
public String getSubject() {
return subject;
}
public String getToken() {
return token;
}
public Bundle getColorScheme() {
return colorScheme;
}
public Bundle getFeatureFlags() {
return featureFlags;
}
public boolean getAudioMuted() {
return audioMuted;
}
public boolean getAudioOnly() {
return audioOnly;
}
public boolean getVideoMuted() {
return videoMuted;
}
public JitsiMeetUserInfo getUserInfo() {
return userInfo;
}
/**
* Class used to build the immutable {@link JitsiMeetConferenceOptions} object.
*/
public static class Builder {
private URL serverURL;
private String room;
private String subject;
private String token;
private Bundle colorScheme;
private Bundle featureFlags;
private Boolean audioMuted;
private Boolean audioOnly;
private Boolean videoMuted;
private JitsiMeetUserInfo userInfo;
public Builder() {
featureFlags = new Bundle();
}
/**\
* Sets the server URL.
* @param url - {@link URL} of the server where the conference should take place.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setServerURL(URL url) {
this.serverURL = url;
return this;
}
/**
* Sets the room where the conference will take place.
* @param room - Name of the room.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setRoom(String room) {
this.room = room;
return this;
}
/**
* Sets the conference subject.
* @param subject - Subject for the conference.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setSubject(String subject) {
this.subject = subject;
return this;
}
/**
* Sets the JWT token to be used for authentication when joining a conference.
* @param token - The JWT token to be used for authentication.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setToken(String token) {
this.token = token;
return this;
}
/**
* Sets the color scheme override so the app is themed. See:
* https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/color-scheme/defaultScheme.js
* for the structure.
* @param colorScheme - A color scheme to be applied to the app.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setColorScheme(Bundle colorScheme) {
this.colorScheme = colorScheme;
return this;
}
/**
* Indicates the conference will be joined with the microphone muted.
* @param muted - Muted indication.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setAudioMuted(boolean muted) {
this.audioMuted = muted;
return this;
}
/**
* Indicates the conference will be joined in audio-only mode. In this mode no video is
* sent or received.
* @param audioOnly - Audio-mode indicator.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setAudioOnly(boolean audioOnly) {
this.audioOnly = audioOnly;
return this;
}
/**
* Indicates the conference will be joined with the camera muted.
* @param videoMuted - Muted indication.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setVideoMuted(boolean videoMuted) {
this.videoMuted = videoMuted;
return this;
}
/**
* Sets the welcome page enabled / disabled. The welcome page lists recent meetings and
* calendar appointments and it's meant to be used by standalone applications. Defaults to
* false.
* @param enabled - Whether the welcome page should be enabled or not.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setWelcomePageEnabled(boolean enabled) {
this.featureFlags.putBoolean("welcomepage.enabled", enabled);
return this;
}
public Builder setFeatureFlag(String flag, boolean value) {
this.featureFlags.putBoolean(flag, value);
return this;
}
public Builder setFeatureFlag(String flag, String value) {
this.featureFlags.putString(flag, value);
return this;
}
public Builder setFeatureFlag(String flag, int value) {
this.featureFlags.putInt(flag, value);
return this;
}
public Builder setUserInfo(JitsiMeetUserInfo userInfo) {
this.userInfo = userInfo;
return this;
}
/**
* Builds the immutable {@link JitsiMeetConferenceOptions} object with the configuration
* that this {@link Builder} instance specified.
* @return - The built {@link JitsiMeetConferenceOptions} object.
*/
public JitsiMeetConferenceOptions build() {
JitsiMeetConferenceOptions options = new JitsiMeetConferenceOptions();
options.serverURL = this.serverURL;
options.room = this.room;
options.subject = this.subject;
options.token = this.token;
options.colorScheme = this.colorScheme;
options.featureFlags = this.featureFlags;
options.audioMuted = this.audioMuted;
options.audioOnly = this.audioOnly;
options.videoMuted = this.videoMuted;
options.userInfo = this.userInfo;
return options;
}
}
private JitsiMeetConferenceOptions() {
}
private JitsiMeetConferenceOptions(Parcel in) {
room = in.readString();
subject = in.readString();
token = in.readString();
colorScheme = in.readBundle();
featureFlags = in.readBundle();
userInfo = new JitsiMeetUserInfo(in.readBundle());
byte tmpAudioMuted = in.readByte();
audioMuted = tmpAudioMuted == 0 ? null : tmpAudioMuted == 1;
byte tmpAudioOnly = in.readByte();
audioOnly = tmpAudioOnly == 0 ? null : tmpAudioOnly == 1;
byte tmpVideoMuted = in.readByte();
videoMuted = tmpVideoMuted == 0 ? null : tmpVideoMuted == 1;
}
Bundle asProps() {
Bundle props = new Bundle();
// Android always has the PiP flag set by default.
if (!featureFlags.containsKey("pip.enabled")) {
featureFlags.putBoolean("pip.enabled", true);
}
props.putBundle("flags", featureFlags);
if (colorScheme != null) {
props.putBundle("colorScheme", colorScheme);
}
Bundle config = new Bundle();
if (audioMuted != null) {
config.putBoolean("startWithAudioMuted", audioMuted);
}
if (audioOnly != null) {
config.putBoolean("startAudioOnly", audioOnly);
}
if (videoMuted != null) {
config.putBoolean("startWithVideoMuted", videoMuted);
}
if (subject != null) {
config.putString("subject", subject);
}
Bundle urlProps = new Bundle();
// The room is fully qualified
if (room != null && room.contains("://")) {
urlProps.putString("url", room);
} else {
if (serverURL != null) {
urlProps.putString("serverURL", serverURL.toString());
}
if (room != null) {
urlProps.putString("room", room);
}
}
if (token != null) {
urlProps.putString("jwt", token);
}
if (token == null && userInfo != null) {
props.putBundle("userInfo", userInfo.asBundle());
}
urlProps.putBundle("config", config);
props.putBundle("url", urlProps);
return props;
}
// Parcelable interface
//
public static final Creator<JitsiMeetConferenceOptions> CREATOR = new Creator<JitsiMeetConferenceOptions>() {
@Override
public JitsiMeetConferenceOptions createFromParcel(Parcel in) {
return new JitsiMeetConferenceOptions(in);
}
@Override
public JitsiMeetConferenceOptions[] newArray(int size) {
return new JitsiMeetConferenceOptions[size];
}
};
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(room);
dest.writeString(subject);
dest.writeString(token);
dest.writeBundle(colorScheme);
dest.writeBundle(featureFlags);
dest.writeBundle(userInfo != null ? userInfo.asBundle() : new Bundle());
dest.writeByte((byte) (audioMuted == null ? 0 : audioMuted ? 1 : 2));
dest.writeByte((byte) (audioOnly == null ? 0 : audioOnly ? 1 : 2));
dest.writeByte((byte) (videoMuted == null ? 0 : videoMuted ? 1 : 2));
}
@Override
public int describeContents() {
return 0;
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright @ 2019-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* 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.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Base {@link Fragment} for applications integrating Jitsi Meet at a higher level. It
* contains all the required wiring between the {@code JitsiMeetView} and
* the Fragment lifecycle methods already implemented.
*
* In this fragment 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 Fragment are
* hooked to the React Native subsystem via proxy calls through the
* {@code JitsiMeetActivityDelegate} static methods.
*/
public class JitsiMeetFragment extends Fragment {
/**
* Instance of the {@link JitsiMeetView} which this activity will display.
*/
private JitsiMeetView view;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return this.view = new JitsiMeetView(getActivity());
}
public JitsiMeetView getJitsiView() {
return view;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
JitsiMeetActivityDelegate.onActivityResult(
getActivity(), requestCode, resultCode, data);
}
@Override
public void onDestroyView() {
if (view != null) {
view.dispose();
view = null;
}
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
JitsiMeetActivityDelegate.onHostDestroy(getActivity());
}
@Override
public void onResume() {
super.onResume();
JitsiMeetActivityDelegate.onHostResume(getActivity());
}
@Override
public void onStop() {
super.onStop();
JitsiMeetActivityDelegate.onHostPause(getActivity());
}
}

View File

@@ -0,0 +1,121 @@
/*
* 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.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 JitsiMeetOngoingConferenceService extends Service
implements OngoingConferenceTracker.OngoingConferenceListener {
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
static final class Actions {
static final String START = TAG + ":START";
static final String HANGUP = TAG + ":HANGUP";
}
static void launch(Context context) {
OngoingNotification.createOngoingConferenceNotificationChannel();
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
intent.setAction(Actions.START);
ComponentName componentName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
componentName = context.startForegroundService(intent);
} else {
componentName = context.startService(intent);
}
if (componentName == null) {
JitsiMeetLogger.w(TAG + " Ongoing conference service not started");
}
}
static void abort(Context context) {
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
context.stopService(intent);
}
@Override
public void onCreate() {
super.onCreate();
OngoingConferenceTracker.getInstance().addListener(this);
}
@Override
public void onDestroy() {
OngoingConferenceTracker.getInstance().removeListener(this);
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String action = intent.getAction();
if (Actions.START.equals(action)) {
Notification notification = OngoingNotification.buildOngoingConferenceNotification();
if (notification == null) {
stopSelf();
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
} else {
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " Service started");
}
} else if (Actions.HANGUP.equals(action)) {
JitsiMeetLogger.i(TAG + " Hangup requested");
// Abort all ongoing calls
if (AudioModeModule.useConnectionService()) {
ConnectionService.abortConnections();
}
stopSelf();
} else {
JitsiMeetLogger.w(TAG + " Unknown action received: " + action);
stopSelf();
}
return START_NOT_STICKY;
}
@Override
public void onCurrentConferenceChanged(String conferenceUrl) {
if (conferenceUrl == null) {
stopSelf();
JitsiMeetLogger.i(TAG + "Service stopped");
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* 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 org.jitsi.meet.sdk.log.JitsiMeetLogger;
class JitsiMeetUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
public static void register() {
Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
JitsiMeetUncaughtExceptionHandler uncaughtExceptionHandler
= new JitsiMeetUncaughtExceptionHandler(defaultUncaughtExceptionHandler);
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
}
private JitsiMeetUncaughtExceptionHandler(Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler) {
this.defaultUncaughtExceptionHandler = defaultUncaughtExceptionHandler;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
JitsiMeetLogger.e(e, this.getClass().getSimpleName() + " FATAL ERROR");
// Abort all ConnectionService ongoing calls
if (AudioModeModule.useConnectionService()) {
ConnectionService.abortConnections();
}
if (defaultUncaughtExceptionHandler != null) {
defaultUncaughtExceptionHandler.uncaughtException(t, e);
}
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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.os.Bundle;
import java.net.MalformedURLException;
import java.net.URL;
/**
* This class represents user information to be passed to {@link JitsiMeetConferenceOptions} for
* identifying a user.
*/
public class JitsiMeetUserInfo {
/**
* User's display name.
*/
private String displayName;
/**
* User's email address.
*/
private String email;
/**
* User's avatar URL.
*/
private URL avatar;
public JitsiMeetUserInfo() {}
public JitsiMeetUserInfo(Bundle b) {
super();
if (b.containsKey("displayName")) {
displayName = b.getString("displayName");
}
if (b.containsKey("email")) {
email = b.getString("email");
}
if (b.containsKey("avatarURL")) {
String avatarURL = b.getString("avatarURL");
try {
avatar = new URL(avatarURL);
} catch (MalformedURLException e) {
}
}
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public URL getAvatar() {
return avatar;
}
public void setAvatar(URL avatar) {
this.avatar = avatar;
}
Bundle asBundle() {
Bundle b = new Bundle();
if (displayName != null) {
b.putString("displayName", displayName);
}
if (email != null) {
b.putString("email", email);
}
if (avatar != null) {
b.putString("avatarURL", avatar.toString());
}
return b;
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,20 +19,19 @@ package org.jitsi.meet.sdk;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableMap;
import org.jitsi.meet.sdk.invite.InviteController;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Map;
public class JitsiMeetView
extends BaseReactView<JitsiMeetViewListener> {
public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
implements OngoingConferenceTracker.OngoingConferenceListener {
/**
* The {@code Method}s of {@code JitsiMeetViewListener} by event name i.e.
@@ -40,57 +40,6 @@ public class JitsiMeetView
private static final Map<String, Method> LISTENER_METHODS
= ListenerUtils.mapListenerMethods(JitsiMeetViewListener.class);
/**
* The {@link Log} tag which identifies the source of the log messages of
* {@code JitsiMeetView}.
*/
private static final String TAG = JitsiMeetView.class.getSimpleName();
/**
* Loads a specific URL {@code String} in all existing
* {@code JitsiMeetView}s.
*
* @param urlString he URL {@code String} to load in all existing
* {@code JitsiMeetView}s.
* @return If the specified {@code urlString} was submitted for loading in
* at least one {@code JitsiMeetView}, then {@code true}; otherwise,
* {@code false}.
*/
public static boolean loadURLStringInViews(String urlString) {
boolean loaded = false;
synchronized (views) {
for (BaseReactView view : views) {
if (view instanceof JitsiMeetView) {
((JitsiMeetView)view).loadURLString(urlString);
loaded = true;
}
}
}
return loaded;
}
/**
* The default base {@code URL} used to join a conference when a partial URL
* (e.g. a room name only) is specified to {@link #loadURLString(String)} or
* {@link #loadURLObject(Bundle)}.
*/
private URL defaultURL;
/**
* The entry point into the invite feature of Jitsi Meet. The Java
* counterpart of the JavaScript {@code InviteButton}.
*/
private final InviteController inviteController;
/**
* Whether Picture-in-Picture is enabled. If {@code null}, defaults to
* {@code true} iff the Android platform supports Picture-in-Picture
* natively.
*/
private Boolean pictureInPictureEnabled;
/**
* The URL of the current conference.
*/
@@ -99,22 +48,68 @@ public class JitsiMeetView
private volatile String url;
/**
* Whether the Welcome page is enabled.
* Helper method to recursively merge 2 {@link Bundle} objects representing React Native props.
*
* @param a - The first {@link Bundle}.
* @param b - The second {@link Bundle}.
* @return The merged {@link Bundle} object.
*/
private boolean welcomePageEnabled;
private static Bundle mergeProps(@Nullable Bundle a, @Nullable Bundle b) {
Bundle result = new Bundle();
if (a == null) {
if (b != null) {
result.putAll(b);
}
return result;
}
if (b == null) {
result.putAll(a);
return result;
}
// Start by putting all of a in the result.
result.putAll(a);
// Iterate over each key in b and override if appropriate.
for (String key : b.keySet()) {
Object bValue = b.get(key);
Object aValue = a.get(key);
String valueType = bValue.getClass().getSimpleName();
if (valueType.contentEquals("Boolean")) {
result.putBoolean(key, (Boolean)bValue);
} else if (valueType.contentEquals("String")) {
result.putString(key, (String)bValue);
} else if (valueType.contentEquals("Bundle")) {
result.putBundle(key, mergeProps((Bundle)aValue, (Bundle)bValue));
} else {
throw new RuntimeException("Unsupported type: " + valueType);
}
}
return result;
}
public JitsiMeetView(@NonNull Context context) {
super(context);
// The entry point into the invite feature of Jitsi Meet. The Java
// counterpart of the JavaScript InviteButton.
inviteController = new InviteController(externalAPIScope);
// 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);
}
@Override
public void dispose() {
OngoingConferenceTracker.getInstance().removeListener(this);
super.dispose();
}
/**
@@ -127,200 +122,72 @@ public class JitsiMeetView
* page.
*/
public void enterPictureInPicture() {
if (isPictureInPictureEnabled() && getURL() != null) {
PictureInPictureModule pipModule
= ReactInstanceManagerHolder.getNativeModule(
PictureInPictureModule pipModule
= ReactInstanceManagerHolder.getNativeModule(
PictureInPictureModule.class);
if (pipModule != null) {
try {
pipModule.enterPictureInPicture();
} catch (RuntimeException re) {
Log.e(TAG, "onUserLeaveHint: failed to enter PiP mode", re);
}
if (pipModule != null
&& PictureInPictureModule.isPictureInPictureSupported()
&& !JitsiMeetActivityDelegate.arePermissionsBeingRequested()
&& this.url != null) {
try {
pipModule.enterPictureInPicture();
} catch (RuntimeException re) {
JitsiMeetLogger.e(re, "Failed to enter PiP mode");
}
}
}
/**
* Gets the default base {@code URL} used to join a conference when a
* partial URL (e.g. a room name only) is specified to
* {@link #loadURLString(String)} or {@link #loadURLObject(Bundle)}. If not
* set or if set to {@code null}, the default built in JavaScript is used:
* https://meet.jit.si
*
* @return The default base {@code URL} or {@code null}.
* Joins the conference specified by the given {@link JitsiMeetConferenceOptions}. If there is
* already an active conference, it will be left and the new one will be joined.
* @param options - Description of what conference must be joined and what options will be used
* when doing so.
*/
public URL getDefaultURL() {
return defaultURL;
public void join(@Nullable JitsiMeetConferenceOptions options) {
setProps(options != null ? options.asProps() : new Bundle());
}
/**
* Gets the {@link InviteController} which represents the entry point into
* the invite feature of Jitsi Meet and is the Java counterpart of the
* JavaScript {@code InviteButton}.
*
* @return the {@link InviteController} which represents the entry point
* into the invite feature of Jitsi Meet and is the Java counterpart of the
* JavaScript {@code InviteButton}
* Leaves the currently active conference.
*/
public InviteController getInviteController() {
return inviteController;
public void leave() {
setProps(new Bundle());
}
/**
* Gets the URL of the current conference.
*
* XXX The method is meant for internal purposes only at the time of this
* writing because there is no equivalent API on iOS.
*
* @return the URL {@code String} of the current conference if any;
* otherwise, {@code null}.
* Helper method to set the React Native props.
* @param newProps - New props to be set on the React Native view.
*/
String getURL() {
return url;
}
private void setProps(@NonNull Bundle newProps) {
// Merge the default options with the newly provided ones.
Bundle props = mergeProps(JitsiMeet.getDefaultProps(), newProps);
/**
* Gets whether Picture-in-Picture is enabled. Picture-in-Picture is
* natively supported on Android API >= 26 (Oreo), so it should not be
* enabled on older platform versions.
*
* @return If Picture-in-Picture is enabled, {@code true}; {@code false},
* otherwise.
*/
public boolean isPictureInPictureEnabled() {
return
PictureInPictureModule.isPictureInPictureSupported()
&& (pictureInPictureEnabled == null
|| pictureInPictureEnabled);
}
/**
* Gets whether the Welcome page is enabled. If {@code true}, the Welcome
* page is rendered when this {@code JitsiMeetView} is not at a URL
* identifying a Jitsi Meet conference/room.
*
* @return {@code true} if the Welcome page is enabled; otherwise,
* {@code false}.
*/
public boolean isWelcomePageEnabled() {
return welcomePageEnabled;
}
/**
* Loads a specific {@link URL} which may identify a conference to join. If
* the specified {@code URL} is {@code null} and the Welcome page is
* enabled, the Welcome page is displayed instead.
*
* @param url The {@code URL} to load which may identify a conference to
* join.
*/
public void loadURL(@Nullable URL url) {
loadURLString(url == null ? null : url.toString());
}
/**
* Loads a specific URL which may identify a conference to join. The URL is
* specified in the form of a {@link Bundle} of properties which (1)
* internally are sufficient to construct a URL {@code String} while (2)
* abstracting the specifics of constructing the URL away from API
* clients/consumers. If the specified URL is {@code null} and the Welcome
* page is enabled, the Welcome page is displayed instead.
*
* @param urlObject The URL to load which may identify a conference to join.
*/
public void loadURLObject(@Nullable Bundle urlObject) {
Bundle props = new Bundle();
// defaultURL
if (defaultURL != null) {
props.putString("defaultURL", defaultURL.toString());
}
// inviteController
InviteController inviteController = getInviteController();
if (inviteController != null) {
props.putBoolean(
"addPeopleEnabled",
inviteController.isAddPeopleEnabled());
props.putBoolean(
"dialOutEnabled",
inviteController.isDialOutEnabled());
}
// pictureInPictureEnabled
props.putBoolean(
"pictureInPictureEnabled",
isPictureInPictureEnabled());
// url
if (urlObject != null) {
props.putBundle("url", urlObject);
}
// welcomePageEnabled
props.putBoolean("welcomePageEnabled", welcomePageEnabled);
// XXX The method loadURLObject: is supposed to be imperative i.e.
// XXX The setProps() method is supposed to be imperative i.e.
// a second invocation with one and the same URL is expected to join
// the respective conference again if the first invocation was followed
// by leaving the conference. However, React and, respectively,
// appProperties/initialProperties are declarative expressions i.e. one
// and the same URL will not trigger an automatic re-render in the
// JavaScript source code. The workaround implemented bellow introduces
// imperativeness in React Component props by defining a unique value
// per loadURLObject: invocation.
// "imperativeness" in React Component props by defining a unique value
// per setProps() invocation.
props.putLong("timestamp", System.currentTimeMillis());
createReactRootView("App", props);
}
/**
* Loads a specific URL {@link String} which may identify a conference to
* join. If the specified URL {@code String} is {@code null} and the Welcome
* page is enabled, the Welcome page is displayed instead.
*
* @param urlString The URL {@code String} to load which may identify a
* conference to join.
* Handler for {@link OngoingConferenceTracker} events.
* @param conferenceUrl
*/
public void loadURLString(@Nullable String urlString) {
Bundle urlObject;
if (urlString == null) {
urlObject = null;
} else {
urlObject = new Bundle();
urlObject.putString("url", urlString);
}
loadURLObject(urlObject);
}
/**
* The internal processing for the URL of the current conference set on the
* associated {@link JitsiMeetView}.
*
* @param eventName the name of the external API event to be processed
* @param eventData the details/specifics of the event to process determined
* by/associated with the specified {@code eventName}.
*/
private void maybeSetViewURL(String eventName, ReadableMap eventData) {
switch(eventName) {
case "CONFERENCE_WILL_JOIN":
setURL(eventData.getString("url"));
break;
case "CONFERENCE_FAILED":
case "CONFERENCE_WILL_LEAVE":
case "LOAD_CONFIG_ERROR":
String url = eventData.getString("url");
if (url != null && url.equals(getURL())) {
setURL(null);
}
break;
}
@Override
public void onCurrentConferenceChanged(String conferenceUrl) {
// This property was introduced in order to address
// an exception in the Picture-in-Picture functionality which arose
// because of delays related to bridging between JavaScript and Java. To
// reduce these delays do not wait for the call to be transferred to the
// UI thread.
this.url = conferenceUrl;
}
/**
@@ -331,63 +198,7 @@ public class JitsiMeetView
* by/associated with the specified {@code name}.
*/
@Override
public void onExternalAPIEvent(String name, ReadableMap data) {
// XXX The JitsiMeetView property URL was introduced in order to address
// an exception in the Picture-in-Picture functionality which arose
// because of delays related to bridging between JavaScript and Java. To
// reduce these delays do not wait for the call to be transferred to the
// UI thread.
maybeSetViewURL(name, data);
protected void onExternalAPIEvent(String name, ReadableMap data) {
onExternalAPIEvent(LISTENER_METHODS, name, data);
}
/**
* Sets the default base {@code URL} used to join a conference when a
* partial URL (e.g. a room name only) is specified to
* {@link #loadURLString(String)} or {@link #loadURLObject(Bundle)}. Must be
* called before {@link #loadURL(URL)} for it to take effect.
*
* @param defaultURL The {@code URL} to be set as the default base URL.
* @see #getDefaultURL()
*/
public void setDefaultURL(URL defaultURL) {
this.defaultURL = defaultURL;
}
/**
* Sets whether Picture-in-Picture is enabled. Because Picture-in-Picture is
* natively supported only since certain platform versions, specifying
* {@code true} will have no effect on unsupported platform versions.
*
* @param pictureInPictureEnabled To enable Picture-in-Picture,
* {@code true}; otherwise, {@code false}.
*/
public void setPictureInPictureEnabled(boolean pictureInPictureEnabled) {
this.pictureInPictureEnabled = pictureInPictureEnabled;
}
/**
* Sets the URL of the current conference.
*
* XXX The method is meant for internal purposes only. It does not
* {@code loadURL}, it merely remembers the specified URL.
*
* @param url the URL {@code String} which to be set as the URL of the
* current conference.
*/
void setURL(String url) {
this.url = url;
}
/**
* Sets whether the Welcome page is enabled. Must be called before
* {@link #loadURL(URL)} for it to take effect.
*
* @param welcomePageEnabled {@code true} to enable the Welcome page;
* otherwise, {@code false}.
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
this.welcomePageEnabled = welcomePageEnabled;
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* 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 java.util.Map;
/**
* Implements {@link JitsiMeetViewListener} so apps don't have to add stubs for
* all methods in the interface if they are only interested in some.
*/
public abstract class JitsiMeetViewAdapter
implements JitsiMeetViewListener {
@Override
public void onConferenceFailed(Map<String, Object> data) {
}
@Override
public void onConferenceJoined(Map<String, Object> data) {
}
@Override
public void onConferenceLeft(Map<String, Object> data) {
}
@Override
public void onConferenceWillJoin(Map<String, Object> data) {
}
@Override
public void onConferenceWillLeave(Map<String, Object> data) {
}
@Override
public void onLoadConfigError(Map<String, Object> data) {
}
}

View File

@@ -22,15 +22,6 @@ import java.util.Map;
* Interface for listening to events coming from Jitsi Meet.
*/
public interface JitsiMeetViewListener {
/**
* Called when joining a conference fails or an ongoing conference is
* interrupted due to a failure.
*
* @param data Map with an "error" key describing the problem, and a "url"
* key with the conference URL.
*/
void onConferenceFailed(Map<String, Object> data);
/**
* Called when a conference was joined.
*
@@ -39,11 +30,16 @@ public interface JitsiMeetViewListener {
void onConferenceJoined(Map<String, Object> data);
/**
* Called when the conference was left, typically after hanging up.
* Called when the active conference ends, be it because of user choice or
* because of a failure.
*
* @param data Map with a "url" key with the conference URL.
* @param data Map with an "error" key with the error and a "url" key with
* the conference URL. If the conference finished gracefully no `error`
* key will be present. The possible values for "error" are described here:
* https://github.com/jitsi/lib-jitsi-meet/blob/master/JitsiConnectionErrors.js
* https://github.com/jitsi/lib-jitsi-meet/blob/master/JitsiConferenceErrors.js
*/
void onConferenceLeft(Map<String, Object> data);
void onConferenceTerminated(Map<String, Object> data);
/**
* Called before the conference is joined.
@@ -51,21 +47,4 @@ public interface JitsiMeetViewListener {
* @param data Map with a "url" key with the conference URL.
*/
void onConferenceWillJoin(Map<String, Object> data);
/**
* Called before the conference is left.
*
* @param data Map with a "url" key with the conference URL.
*/
void onConferenceWillLeave(Map<String, Object> data);
/**
* Called when loading the main configuration file from the Jitsi Meet
* deployment fails.
*
* @param data Map with an "error" key with the error and a "url" key with
* the conference URL which necessitated the loading of the configuration
* file.
*/
void onLoadConfigError(Map<String, Object> data);
}

View File

@@ -0,0 +1,73 @@
/*
* 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 com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import javax.annotation.Nonnull;
/**
* Module implementing a "bridge" between the JS loggers and the native one.
*/
@ReactModule(name = LogBridgeModule.NAME)
class LogBridgeModule extends ReactContextBaseJavaModule {
public static final String NAME = "LogBridge";
public LogBridgeModule(@Nonnull ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return NAME;
}
@ReactMethod
public void trace(final String message) {
JitsiMeetLogger.v(message);
}
@ReactMethod
public void debug(final String message) {
JitsiMeetLogger.d(message);
}
@ReactMethod
public void info(final String message) {
JitsiMeetLogger.i(message);
}
@ReactMethod
public void log(final String message) {
JitsiMeetLogger.i(message);
}
@ReactMethod
public void warn(final String message) {
JitsiMeetLogger.w(message);
}
@ReactMethod
public void error(final String message) {
JitsiMeetLogger.e(message);
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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 com.facebook.react.bridge.ReadableMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
/**
* Helper class to keep track of what the current conference is.
*/
class OngoingConferenceTracker {
private static final OngoingConferenceTracker instance = new OngoingConferenceTracker();
private static final String CONFERENCE_WILL_JOIN = "CONFERENCE_WILL_JOIN";
private static final String CONFERENCE_TERMINATED = "CONFERENCE_TERMINATED";
private final Collection<OngoingConferenceListener> listeners =
Collections.synchronizedSet(new HashSet<OngoingConferenceListener>());
private String currentConference;
public OngoingConferenceTracker() {
}
public static OngoingConferenceTracker getInstance() {
return instance;
}
/**
* Gets the current active conference URL.
*
* @return - The current conference URL as a String.
*/
synchronized String getCurrentConference() {
return currentConference;
}
synchronized void onExternalAPIEvent(String name, ReadableMap data) {
if (!data.hasKey("url")) {
return;
}
String url = data.getString("url");
if (url == null) {
return;
}
switch(name) {
case CONFERENCE_WILL_JOIN:
currentConference = url;
updateListeners();
break;
case CONFERENCE_TERMINATED:
if (url.equals(currentConference)) {
currentConference = null;
updateListeners();
}
break;
}
}
void addListener(OngoingConferenceListener listener) {
listeners.add(listener);
}
void removeListener(OngoingConferenceListener listener) {
listeners.remove(listener);
}
private void updateListeners() {
synchronized (listeners) {
for (OngoingConferenceListener listener : listeners) {
listener.onCurrentConferenceChanged(currentConference);
}
}
}
public interface OngoingConferenceListener {
void onCurrentConferenceChanged(String conferenceUrl);
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.Random;
/**
* Helper class for creating the ongoing notification which is used with
* {@link JitsiMeetOngoingConferenceService}. It allows the user to easily get back to the app
* and to hangup from within the notification itself.
*/
class OngoingNotification {
private static final String TAG = OngoingNotification.class.getSimpleName();
private static final String CHANNEL_ID = "JitsiNotificationChannel";
private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
static void createOngoingConferenceNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
Context context = ReactInstanceManagerHolder.getCurrentActivity();
if (context == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
return;
}
NotificationManager notificationManager
= (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel(CHANNEL_ID);
if (channel != null) {
// The channel was already created, no need to do it again.
return;
}
channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);
notificationManager.createNotificationChannel(channel);
}
static Notification buildOngoingConferenceNotification() {
Context context = ReactInstanceManagerHolder.getCurrentActivity();
if (context == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
return null;
}
Intent notificationIntent = new Intent(context, context.getClass());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder = new NotificationCompat.Builder(context, CHANNEL_ID);
} else {
builder = new NotificationCompat.Builder(context);
}
builder
.setCategory(NotificationCompat.CATEGORY_CALL)
.setContentTitle(context.getString(R.string.ongoing_notification_title))
.setContentText(context.getString(R.string.ongoing_notification_text))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setAutoCancel(false)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setUsesChronometer(true)
.setOnlyAlertOnce(true)
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
// Add a "hang-up" action only if we are using ConnectionService.
if (AudioModeModule.useConnectionService()) {
Intent hangupIntent = new Intent(context, JitsiMeetOngoingConferenceService.class);
hangupIntent.setAction(JitsiMeetOngoingConferenceService.Actions.HANGUP);
PendingIntent hangupPendingIntent
= PendingIntent.getService(context, 0, hangupIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action hangupAction = new NotificationCompat.Action(0, "Hang up", hangupPendingIntent);
builder.addAction(hangupAction);
}
return builder.build();
}
}

View File

@@ -16,21 +16,27 @@
package org.jitsi.meet.sdk;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.PictureInPictureParams;
import android.os.Build;
import android.util.Log;
import android.util.Rational;
import com.facebook.react.bridge.Promise;
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;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
@ReactModule(name = PictureInPictureModule.NAME)
class PictureInPictureModule
extends ReactContextBaseJavaModule {
private final static String TAG = "PictureInPicture";
public static final String NAME = "PictureInPicture";
private static final String TAG = NAME;
static boolean isPictureInPictureSupported() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
@@ -53,6 +59,7 @@ class PictureInPictureModule
* including when the activity is not visible (paused or stopped), if the
* screen is locked or if the user has an activity pinned.
*/
@TargetApi(Build.VERSION_CODES.O)
public void enterPictureInPicture() {
if (!isPictureInPictureSupported()) {
throw new IllegalStateException("Picture-in-Picture not supported");
@@ -64,7 +71,7 @@ class PictureInPictureModule
throw new IllegalStateException("No current Activity!");
}
Log.d(TAG, "Entering Picture-in-Picture");
JitsiMeetLogger.i(TAG + " Entering Picture-in-Picture");
PictureInPictureParams.Builder builder
= new PictureInPictureParams.Builder()
@@ -99,6 +106,6 @@ class PictureInPictureModule
@Override
public String getName() {
return TAG;
return NAME;
}
}

View File

@@ -24,6 +24,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.module.annotations.ReactModule;
/**
* Module implementing a simple API to enable a proximity sensor-controlled
@@ -31,14 +32,11 @@ import com.facebook.react.bridge.UiThreadUtil;
* object it will dim the screen and disable touch controls. The functionality
* is used with the conference audio-only mode.
*/
@ReactModule(name = ProximityModule.NAME)
class ProximityModule
extends ReactContextBaseJavaModule {
/**
* The name of {@code ProximityModule} to be used in the React Native
* bridge.
*/
private static final String MODULE_NAME = "Proximity";
public static final String NAME = "Proximity";
/**
* This type of wake lock (the one activated by the proximity sensor) has
@@ -74,7 +72,7 @@ class ProximityModule
wakeLock
= powerManager.newWakeLock(
PROXIMITY_SCREEN_OFF_WAKE_LOCK,
MODULE_NAME);
"jitsi:"+NAME);
} catch (Throwable ignored) {
wakeLock = null;
}
@@ -89,7 +87,7 @@ class ProximityModule
*/
@Override
public String getName() {
return MODULE_NAME;
return NAME;
}
/**

View File

@@ -0,0 +1,200 @@
package org.jitsi.meet.sdk;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
/**
* The react-native side of Jitsi Meet's {@link ConnectionService}. Exposes
* the Java Script API.
*
* @author Pawel Domas
*/
@RequiresApi(api = Build.VERSION_CODES.O)
@ReactModule(name = RNConnectionService.NAME)
class RNConnectionService extends ReactContextBaseJavaModule {
public static final String NAME = "ConnectionService";
private static final String TAG = ConnectionService.TAG;
/**
* Handler for dealing with call state changes. We are acting as a proxy between ConnectionService
* and other modules such as {@link AudioModeModule}.
*/
private CallAudioStateListener callAudioStateListener;
/**
* Sets the audio route on all existing {@link android.telecom.Connection}s
*
* @param audioRoute the new audio route to be set. See
* {@link android.telecom.CallAudioState} constants prefixed with "ROUTE_".
*/
@RequiresApi(api = Build.VERSION_CODES.O)
static void setAudioRoute(int audioRoute) {
for (ConnectionService.ConnectionImpl c
: ConnectionService.getConnections()) {
c.setAudioRoute(audioRoute);
}
}
RNConnectionService(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* Starts a new outgoing call.
*
* @param callUUID - unique call identifier assigned by Jitsi Meet to
* a conference call.
* @param handle - a call handle which by default is Jitsi Meet room's URL.
* @param hasVideo - whether or not user starts with the video turned on.
* @param promise - the Promise instance passed by the React-native bridge,
* so that this method returns a Promise on the JS side.
*
* NOTE regarding the "missingPermission" suppress - SecurityException will
* be handled as part of the Exception try catch block and the Promise will
* be rejected.
*/
@SuppressLint("MissingPermission")
@ReactMethod
public void startCall(
String callUUID,
String handle,
boolean hasVideo,
Promise promise) {
JitsiMeetLogger.d("%s startCall UUID=%s, h=%s, v=%s",
TAG,
callUUID,
handle,
hasVideo);
ReactApplicationContext ctx = getReactApplicationContext();
Uri address = Uri.fromParts(PhoneAccount.SCHEME_SIP, handle, null);
PhoneAccountHandle accountHandle
= ConnectionService.registerPhoneAccount(
getReactApplicationContext(), address, callUUID);
Bundle extras = new Bundle();
extras.putParcelable(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
accountHandle);
extras.putInt(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
hasVideo
? VideoProfile.STATE_BIDIRECTIONAL
: VideoProfile.STATE_AUDIO_ONLY);
ConnectionService.registerStartCallPromise(callUUID, promise);
try {
TelecomManager tm
= (TelecomManager) ctx.getSystemService(
Context.TELECOM_SERVICE);
tm.placeCall(address, extras);
} catch (Exception e) {
ConnectionService.unregisterStartCallPromise(callUUID);
promise.reject(e);
}
}
/**
* Called by the JS side of things to mark the call as failed.
*
* @param callUUID - the call's UUID.
*/
@ReactMethod
public void reportCallFailed(String callUUID) {
JitsiMeetLogger.d(TAG + " reportCallFailed " + callUUID);
ConnectionService.setConnectionDisconnected(
callUUID,
new DisconnectCause(DisconnectCause.ERROR));
}
/**
* Called by the JS side of things to mark the call as disconnected.
*
* @param callUUID - the call's UUID.
*/
@ReactMethod
public void endCall(String callUUID) {
JitsiMeetLogger.d(TAG + " endCall " + callUUID);
ConnectionService.setConnectionDisconnected(
callUUID,
new DisconnectCause(DisconnectCause.LOCAL));
}
/**
* Called by the JS side of things to mark the call as active.
*
* @param callUUID - the call's UUID.
*/
@ReactMethod
public void reportConnectedOutgoingCall(String callUUID, Promise promise) {
JitsiMeetLogger.d(TAG + " reportConnectedOutgoingCall " + callUUID);
ConnectionService.setConnectionActive(callUUID);
promise.resolve(null);
}
@Override
public String getName() {
return NAME;
}
/**
* Called by the JS side to update the call's state.
*
* @param callUUID - the call's UUID.
* @param callState - the map which carries infor about the current call's
* state. See static fields in {@link ConnectionService.ConnectionImpl}
* prefixed with "KEY_" for the values supported by the Android
* implementation.
*/
@ReactMethod
public void updateCall(String callUUID, ReadableMap callState) {
ConnectionService.updateCall(callUUID, callState);
}
public CallAudioStateListener getCallAudioStateListener() {
return callAudioStateListener;
}
public void setCallAudioStateListener(CallAudioStateListener callAudioStateListener) {
this.callAudioStateListener = callAudioStateListener;
}
/**
* Handler for call state changes. {@code ConnectionServiceImpl} will call this handler when the
* call audio state changes.
*
* @param callAudioState The current call's audio state.
*/
void onCallAudioStateChange(android.telecom.CallAudioState callAudioState) {
if (callAudioStateListener != null) {
callAudioStateListener.onCallAudioStateChange(callAudioState);
}
}
interface CallAudioStateListener {
void onCallAudioStateChange(android.telecom.CallAudioState callAudioState);
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* 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.support.annotation.Nullable;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class ReactContextUtils {
public static boolean emitEvent(
ReactContext reactContext,
String eventName,
@Nullable Object data) {
if (reactContext == null) {
// XXX If no ReactContext is specified, emit through the
// ReactContext of ReactInstanceManager. ReactInstanceManager
// cooperates with ReactContextUtils i.e. ReactInstanceManager will
// not invoke ReactContextUtils without a ReactContext.
return ReactInstanceManagerHolder.emitEvent(eventName, data);
}
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, data);
return true;
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
* Copyright @ 2019-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,39 +17,98 @@
package org.jitsi.meet.sdk;
import android.app.Application;
import android.support.annotation.Nullable;
import android.app.Activity;
import androidx.annotation.Nullable;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.devsupport.DevInternalSettings;
import com.facebook.react.jscexecutor.JSCExecutorFactory;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.soloader.SoLoader;
import com.oney.WebRTCModule.RTCVideoViewManager;
import com.oney.WebRTCModule.WebRTCModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import org.webrtc.SoftwareVideoDecoderFactory;
import org.webrtc.SoftwareVideoEncoderFactory;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class ReactInstanceManagerHolder {
/**
* FIXME (from linter): Do not place Android context classes in static
* fields (static reference to ReactInstanceManager which has field
* mApplicationContext pointing to Context); this is a memory leak (and
* also breaks Instant Run).
*
* React Native bridge. The instance manager allows embedding applications
* to create multiple root views off the same JavaScript bundle.
*/
private static ReactInstanceManager reactInstanceManager;
private static List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new AndroidSettingsModule(reactContext),
new AppInfoModule(reactContext),
new AudioModeModule(reactContext),
new ExternalAPIModule(reactContext),
new LocaleDetector(reactContext),
new PictureInPictureModule(reactContext),
new ProximityModule(reactContext),
new WiFiStatsModule(reactContext),
new org.jitsi.meet.sdk.dropbox.Dropbox(reactContext),
new org.jitsi.meet.sdk.invite.InviteModule(reactContext),
new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext)
private static List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> nativeModules
= new ArrayList<>(Arrays.<NativeModule>asList(
new AndroidSettingsModule(reactContext),
new AppInfoModule(reactContext),
new AudioModeModule(reactContext),
new DropboxModule(reactContext),
new ExternalAPIModule(reactContext),
new JavaScriptSandboxModule(reactContext),
new LocaleDetector(reactContext),
new LogBridgeModule(reactContext),
new PictureInPictureModule(reactContext),
new ProximityModule(reactContext),
new WiFiStatsModule(reactContext),
new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext)));
if (AudioModeModule.useConnectionService()) {
nativeModules.add(new RNConnectionService(reactContext));
}
// Initialize the WebRTC module by hand, since we want to override some
// initialization options.
WebRTCModule.Options options = new WebRTCModule.Options();
AudioDeviceModule adm = JavaAudioDeviceModule.builder(reactContext)
.createAudioDeviceModule();
VideoDecoderFactory videoDecoderFactory = new SoftwareVideoDecoderFactory();
VideoEncoderFactory videoEncoderFactory = new SoftwareVideoEncoderFactory();
options.setAudioDeviceModule(adm);
options.setVideoDecoderFactory(videoDecoderFactory);
options.setVideoEncoderFactory(videoEncoderFactory);
nativeModules.add(new WebRTCModule(reactContext, options));
try {
Class<?> amplitudeModuleClass = Class.forName("org.jitsi.meet.sdk.AmplitudeModule");
Constructor constructor = amplitudeModuleClass.getConstructor(ReactApplicationContext.class);
nativeModules.add((NativeModule)constructor.newInstance(reactContext));
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
return nativeModules;
}
private static List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
// WebRTC, see createNativeModules for details.
new RTCVideoViewManager()
);
}
@@ -58,7 +118,7 @@ class ReactInstanceManagerHolder {
* @param eventName {@code String} containing the event name.
* @param data {@code Object} optional ancillary data for the event.
*/
public static boolean emitEvent(
static void emitEvent(
String eventName,
@Nullable Object data) {
ReactInstanceManager reactInstanceManager
@@ -68,15 +128,12 @@ class ReactInstanceManagerHolder {
ReactContext reactContext
= reactInstanceManager.getCurrentReactContext();
return
reactContext != null
&& ReactContextUtils.emitEvent(
reactContext,
eventName,
data);
if (reactContext != null) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, data);
}
}
return false;
}
/**
@@ -99,6 +156,18 @@ class ReactInstanceManagerHolder {
? reactContext.getNativeModule(nativeModuleClass) : null;
}
/**
* Gets the current {@link Activity} linked to React Native.
*
* @return An activity attached to React Native.
*/
static Activity getCurrentActivity() {
ReactContext reactContext
= reactInstanceManager != null
? reactInstanceManager.getCurrentReactContext() : null;
return reactContext != null ? reactContext.getCurrentActivity() : null;
}
static ReactInstanceManager getReactInstanceManager() {
return reactInstanceManager;
}
@@ -109,40 +178,71 @@ class ReactInstanceManagerHolder {
* time. All {@code ReactRootView} instances will be tied to the one and
* only {@code ReactInstanceManager}.
*
* @param application {@code Application} instance which is running.
* @param activity {@code Activity} current running Activity.
*/
static void initReactInstanceManager(Application application) {
static void initReactInstanceManager(Activity activity) {
if (reactInstanceManager != null) {
return;
}
SoLoader.init(activity, /* native exopackage */ false);
List<ReactPackage> packages
= new ArrayList<>(Arrays.asList(
new com.BV.LinearGradient.LinearGradientPackage(),
new com.calendarevents.CalendarEventsPackage(),
new com.corbt.keepawake.KCKeepAwakePackage(),
new com.facebook.react.shell.MainReactPackage(),
new com.horcrux.svg.SvgPackage(),
new com.ocetnik.timer.BackgroundTimerPackage(),
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(),
new com.reactnativecommunity.webview.RNCWebViewPackage(),
new com.rnimmersive.RNImmersivePackage(),
new com.zmxv.RNSound.RNSoundPackage(),
new ReactPackageAdapter() {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return ReactInstanceManagerHolder.createNativeModules(reactContext);
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return ReactInstanceManagerHolder.createViewManagers(reactContext);
}
}));
try {
Class<?> googlePackageClass = Class.forName("co.apptailor.googlesignin.RNGoogleSigninPackage");
Constructor constructor = googlePackageClass.getConstructor();
packages.add((ReactPackage)constructor.newInstance());
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
// Keep on using JSC, the jury is out on Hermes.
JSCExecutorFactory jsFactory
= new JSCExecutorFactory("", "");
reactInstanceManager
= ReactInstanceManager.builder()
.setApplication(application)
.setApplication(activity.getApplication())
.setCurrentActivity(activity)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index.android")
.addPackage(new co.apptailor.googlesignin.RNGoogleSigninPackage())
.addPackage(new com.BV.LinearGradient.LinearGradientPackage())
.addPackage(new com.calendarevents.CalendarEventsPackage())
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
.addPackage(new com.dylanvann.fastimage.FastImageViewPackage())
.addPackage(new com.facebook.react.shell.MainReactPackage())
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
.addPackage(new com.rnimmersive.RNImmersivePackage())
.addPackage(new com.zmxv.RNSound.RNSoundPackage())
.addPackage(new ReactPackageAdapter() {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return
ReactInstanceManagerHolder.createNativeModules(
reactContext);
}
})
.setJavaScriptExecutorFactory(jsFactory)
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// Disable delta updates on Android, they have caused trouble.
DevInternalSettings devSettings
= (DevInternalSettings)reactInstanceManager.getDevSupportManager().getDevSettings();
if (devSettings != null) {
devSettings.setBundleDeltasEnabled(false);
}
// Register our uncaught exception handler.
JitsiMeetUncaughtExceptionHandler.register();
}
}

View File

@@ -17,7 +17,6 @@
package org.jitsi.meet.sdk;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

View File

@@ -19,13 +19,14 @@ package org.jitsi.meet.sdk;
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import com.facebook.react.bridge.Promise;
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;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -43,19 +44,16 @@ import java.util.concurrent.Executors;
* Gathers rssi, signal in percentage, timestamp and the addresses of the wifi
* device.
*/
@ReactModule(name = WiFiStatsModule.NAME)
class WiFiStatsModule
extends ReactContextBaseJavaModule {
/**
* The name of {@code WiFiStatsModule} to be used in the React Native
* bridge.
*/
private static final String MODULE_NAME = "WiFiStats";
public static final String NAME = "WiFiStats";
/**
* The {@code Log} tag {@code WiFiStatsModule} is to log messages with.
*/
static final String TAG = MODULE_NAME;
static final String TAG = NAME;
/**
* The scale used for the signal value. A level of the signal, given in the
@@ -87,7 +85,7 @@ class WiFiStatsModule
*/
@Override
public String getName() {
return MODULE_NAME;
return NAME;
}
/**
@@ -146,8 +144,7 @@ class WiFiStatsModule
JSONObject result = new JSONObject();
result.put("rssi", rssi)
.put("signal", signalLevel)
.put("timestamp",
String.valueOf(System.currentTimeMillis()));
.put("timestamp", System.currentTimeMillis());
JSONArray addresses = new JSONArray();
@@ -187,17 +184,15 @@ class WiFiStatsModule
}
} catch (SocketException e) {
Log.wtf(TAG,
"Unable to NetworkInterface.getNetworkInterfaces()"
);
JitsiMeetLogger.e(e, TAG + " Unable to NetworkInterface.getNetworkInterfaces()");
}
result.put("addresses", addresses);
promise.resolve(result.toString());
Log.d(TAG, "WiFi stats: " + result.toString());
JitsiMeetLogger.d(TAG + " WiFi stats: " + result.toString());
} catch (Throwable e) {
Log.e(TAG, "Failed to obtain wifi stats", e);
JitsiMeetLogger.e(e, TAG + " Failed to obtain wifi stats");
promise.reject(
new Exception("Failed to obtain wifi stats"));
}

View File

@@ -16,7 +16,7 @@
package org.jitsi.meet.sdk.incoming_call;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
public class IncomingCallInfo {
/**

View File

@@ -18,7 +18,7 @@ package org.jitsi.meet.sdk.incoming_call;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ReadableMap;
@@ -50,7 +50,7 @@ public class IncomingCallView
* by/associated with the specified {@code name}.
*/
@Override
public void onExternalAPIEvent(String name, ReadableMap data) {
protected void onExternalAPIEvent(String name, ReadableMap data) {
onExternalAPIEvent(LISTENER_METHODS, name, data);
}

Some files were not shown because too many files have changed in this diff Show More