diff --git a/android/app/build.gradle b/android/app/build.gradle index 2712c4b31e..1218faa67d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -139,6 +139,7 @@ if (project.hasProperty('JITSI_SIGNING') } dependencies { + compile project(':react-native-immersive') compile project(':react-native-keep-awake') compile project(':react-native-vector-icons') compile project(':react-native-webrtc') diff --git a/android/app/src/main/java/org/jitsi/meet/MainApplication.java b/android/app/src/main/java/org/jitsi/meet/MainApplication.java index 0a2b2c45e2..c27d2adf7a 100644 --- a/android/app/src/main/java/org/jitsi/meet/MainApplication.java +++ b/android/app/src/main/java/org/jitsi/meet/MainApplication.java @@ -30,6 +30,7 @@ public class MainApplication extends Application implements ReactApplication { new com.facebook.react.shell.MainReactPackage(), new com.oblador.vectoricons.VectorIconsPackage(), new com.oney.WebRTCModule.WebRTCModulePackage(), + new com.rnimmersive.RNImmersivePackage(), new org.jitsi.meet.audiomode.AudioModePackage() ); } diff --git a/android/settings.gradle b/android/settings.gradle index ed5415526e..318023f815 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ rootProject.name = 'jitsi-meet-react' +include ':react-native-immersive' +project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android') include ':app' include ':react-native-keep-awake' diff --git a/package.json b/package.json index f0e9aee5e8..027279a6fb 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,11 @@ "bootstrap": "3.1.1", "i18next": "3.4.4", "i18next-xhr-backend": "1.1.0", + "jQuery-Impromptu": "trentrichardson/jQuery-Impromptu#v6.0.0", "jitsi-meet-logger": "jitsi/jitsi-meet-logger", "jquery": "~2.1.1", "jquery-contextmenu": "*", "jquery-i18next": "1.1.0", - "jQuery-Impromptu": "trentrichardson/jQuery-Impromptu#v6.0.0", "jquery-ui": "1.10.5", "jssha": "1.5.0", "jws": "*", @@ -35,6 +35,7 @@ "react": "15.4.2", "react-dom": "15.4.2", "react-native": "0.41.2", + "react-native-immersive": "0.0.4", "react-native-keep-awake": "^2.0.2", "react-native-prompt": "^1.0.0", "react-native-vector-icons": "^4.0.0", diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js index d316796a27..b9b3436aea 100644 --- a/react/features/app/components/App.native.js +++ b/react/features/app/components/App.native.js @@ -4,6 +4,7 @@ import { Linking } from 'react-native'; import { Platform } from '../../base/react'; import '../../audio-mode'; +import '../../full-screen'; import '../../wake-lock'; import { AbstractApp } from './AbstractApp'; diff --git a/react/features/full-screen/index.js b/react/features/full-screen/index.js new file mode 100644 index 0000000000..d436892893 --- /dev/null +++ b/react/features/full-screen/index.js @@ -0,0 +1 @@ +import './middleware'; diff --git a/react/features/full-screen/middleware.js b/react/features/full-screen/middleware.js new file mode 100644 index 0000000000..a29f4c1d0d --- /dev/null +++ b/react/features/full-screen/middleware.js @@ -0,0 +1,76 @@ +import { StatusBar } from 'react-native'; +import { Immersive } from 'react-native-immersive'; + +import { + CONFERENCE_FAILED, + CONFERENCE_LEFT, + CONFERENCE_WILL_JOIN +} from '../base/conference'; +import { Platform } from '../base/react'; +import { MiddlewareRegistry } from '../base/redux'; + +/** + * Middleware that captures conference actions and activates or deactivates the + * full screen mode. On iOS it hides the status bar, and on Android it uses the + * immersive mode: + * https://developer.android.com/training/system-ui/immersive.html + * In immersive mode the status and navigation bars are hidden and thus the + * entire screen will be covered by our application. + * + * @param {Store} store - Redux store. + * @returns {Function} + */ +MiddlewareRegistry.register(store => next => action => { + let useFullScreen; + + switch (action.type) { + case CONFERENCE_WILL_JOIN: { + const state = store.getState()['features/base/conference']; + + useFullScreen = !state.audioOnly; + break; + } + + case CONFERENCE_FAILED: + case CONFERENCE_LEFT: + useFullScreen = false; + break; + + default: + useFullScreen = null; + break; + } + + if (useFullScreen !== null) { + setFullScreen(useFullScreen) + .catch(err => { + console.warn(`Error setting full screen mode: ${err}`); + }); + } + + return next(action); +}); + +/** + * Activates/deactivates the full screen mode. On iOS it will hide the status + * bar and On Android this will turn on immersive mode. + * + * @param {boolean} enabled - True to set full screen mode, false to + * deactivate it. + * @returns {Promise} + */ +function setFullScreen(enabled) { + // XXX The Immersive module is only implemented on Android and throws on + // other platforms. + if (Platform.OS === 'android') { + if (enabled) { + return Immersive.on(); + } + + return Immersive.off(); + } + + StatusBar.setHidden(enabled, 'slide'); + + return Promise.resolve(); +}