Compare commits

...

9 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
e368c76c70 ios: set version to 19.5.1 2020-01-09 14:52:46 +00:00
Saúl Ibarra Corretgé
1502cee6cc android: unmute microphone on the ConnectionService handler
This shouldn't be needed, as ConnectionService should take care of it, but we
suspect some devices don't do it since we got reports of people not hearing
users, and the problem went away when CS was disabled.
2020-01-09 14:39:11 +00:00
Saúl Ibarra Corretgé
932b34c24c android: set version to 19.5.1 2020-01-09 11:31:00 +00:00
Saúl Ibarra Corretgé
0c8589779d deps: react-native-webrtc@1.75.3
Fixes datachannels not working.
2020-01-09 11:30:20 +00:00
Saúl Ibarra Corretgé
30108b3c06 android: handle ConnectionService failures more resiliently
Fallback to the non-ConnectionService case for any error. Also, handle errors
when registering the phone account; Pixel C devices throw UnsupportedException.
2020-01-09 11:29:56 +00:00
Saúl Ibarra Corretgé
3cb5d4ae60 android: handle exception when unregistering account
Pixel C devices have been seen crashing here, oh well.
2020-01-09 11:29:07 +00:00
Saúl Ibarra Corretgé
41af049193 android,ios: add store screenshots
While Fastlane recommends automagic screenshots, we cannot really do that since
we require a specific setup for a video call and so on.
2019-12-17 10:55:07 +01:00
Saúl Ibarra Corretgé
dede23f5b4 ios: fix SDK build after dropping iOS 10
Since we only support iOS 11, 32 bit architectures must not be built.
2019-12-13 13:04:00 +01:00
Bettenbuk Zoltan
c669075265 feat: add swipe handler to entire bottom sheet 2019-12-12 17:15:50 +01:00
55 changed files with 167 additions and 74 deletions

6
.gitignore vendored
View File

@@ -61,14 +61,8 @@ buck-out/
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Build artifacts
*.jsbundle

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -20,5 +20,5 @@
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.5.0
appVersion=19.5.1
sdkVersion=2.5.0

View File

@@ -17,6 +17,7 @@
package org.jitsi.meet.sdk;
import android.content.Context;
import android.media.AudioManager;
import android.os.Build;
import android.telecom.CallAudioState;
import androidx.annotation.RequiresApi;
@@ -38,6 +39,11 @@ class AudioDeviceHandlerConnectionService implements
private final static String TAG = AudioDeviceHandlerConnectionService.class.getSimpleName();
/**
* {@link AudioManager} instance used to interact with the Android audio subsystem.
*/
private AudioManager audioManager;
/**
* Reference to the main {@code AudioModeModule}.
*/
@@ -134,6 +140,8 @@ class AudioDeviceHandlerConnectionService implements
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
module = audioModeModule;
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (rcs != null) {
rcs.setCallAudioStateListener(this);
@@ -160,6 +168,16 @@ class AudioDeviceHandlerConnectionService implements
@Override
public boolean setMode(int mode) {
if (mode != AudioModeModule.DEFAULT) {
// This shouldn't be needed when using ConnectionService, but some devices have been
// observed not doing it.
try {
audioManager.setMicrophoneMute(false);
} catch (Throwable tr) {
JitsiMeetLogger.w(tr, TAG + " Failed to unmute the microphone");
}
}
return true;
}
}

View File

@@ -89,9 +89,17 @@ class RNConnectionService extends ReactContextBaseJavaModule {
ReactApplicationContext ctx = getReactApplicationContext();
Uri address = Uri.fromParts(PhoneAccount.SCHEME_SIP, handle, null);
PhoneAccountHandle accountHandle
= ConnectionService.registerPhoneAccount(
getReactApplicationContext(), address, callUUID);
PhoneAccountHandle accountHandle;
try {
accountHandle
= ConnectionService.registerPhoneAccount(getReactApplicationContext(), address, callUUID);
} catch (Throwable tr) {
JitsiMeetLogger.e(tr, TAG + " error in startCall");
promise.reject(tr);
return;
}
Bundle extras = new Bundle();
extras.putParcelable(
@@ -110,17 +118,18 @@ class RNConnectionService extends ReactContextBaseJavaModule {
try {
tm = (TelecomManager) ctx.getSystemService(Context.TELECOM_SERVICE);
tm.placeCall(address, extras);
} catch (Exception e) {
JitsiMeetLogger.e(e, TAG + " error in startCall");
} catch (Throwable tr) {
JitsiMeetLogger.e(tr, TAG + " error in startCall");
if (tm != null) {
tm.unregisterPhoneAccount(accountHandle);
try {
tm.unregisterPhoneAccount(accountHandle);
} catch (Throwable tr1) {
// UnsupportedOperationException: System does not support feature android.software.connectionservice
// was observed here. Ignore.
}
}
ConnectionService.unregisterStartCallPromise(callUUID);
if (e instanceof SecurityException) {
promise.reject("SECURITY_ERROR", "Required permissions not granted.");
} else {
promise.reject(e);
}
promise.reject(tr);
}
}

View File

@@ -274,7 +274,7 @@ PODS:
- React
- react-native-netinfo (4.1.5):
- React
- react-native-webrtc (1.75.2):
- react-native-webrtc (1.75.3):
- React
- react-native-webview (7.4.1):
- React
@@ -534,7 +534,7 @@ SPEC CHECKSUMS:
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-webrtc: f6783727706d8bec5fb302b76eda60c33dfe3191
react-native-webrtc: 86d841823e66d68cc1f86712db1c2956056bf0c2
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
React-RCTActionSheet: 94671eef55b01a93be735605822ef712d5ea208e
React-RCTAnimation: 524ae33e73de9c0fe6501a7a4bda8e01d26499d9

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>19.5.0</string>
<string>19.5.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>19.5.0</string>
<string>19.5.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>19.5.0</string>
<string>19.5.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

View File

@@ -77,7 +77,7 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 8&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;i386 x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;# Step 4. Create universal binaries for embedded frameworks&#10;#for SUB_FRAMEWORK in $( ls &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks&quot; ); do&#10;#BINARY_NAME=&quot;${SUB_FRAMEWORK%.*}&quot;&#10;#lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot;&#10;#done&#10;&#10;# Step 5. Convenience step to copy the framework to the project&apos;s directory&#10;echo &quot;Copying to project dir&quot;&#10;yes | cp -Rf &quot;${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}&quot; &quot;${PROJECT_DIR}&quot;&#10;&#10;fi&#10;">
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 8&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;fi&#10;&#10;# Step 4. Convenience step to copy the framework to the project&amp;apos;s directory&#10;echo &quot;Copying to project dir&amp;quot&quot;&#10;yes | cp -Rf ${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME} ${PROJECT_DIR}&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"

11
package-lock.json generated
View File

@@ -14872,11 +14872,6 @@
}
}
},
"react-native-swipe-gestures": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.4.tgz",
"integrity": "sha512-C/vz0KPHNyqHk3uF4Cz/jzd/0N8z34ZgsjAZUh/RsXPH2FtJJf3Fw73pQDWJSoCMtvVadlztb8xQ+/aEQrll7w=="
},
"react-native-swipeout": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
@@ -14893,9 +14888,9 @@
"integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
},
"react-native-webrtc": {
"version": "1.75.2",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.75.2.tgz",
"integrity": "sha512-mdEukmHNhiyVIiwdooxk4kVXWG83OOENFV9YIkC7dtGU/sOdL81vDzynqd6Af9YbGMeOr0xdpFuEGsc1OFnKZg==",
"version": "1.75.3",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.75.3.tgz",
"integrity": "sha512-WIQu7jpH4osb4IMdjkpr62UYwt9kHIU4vWvvTHMxSqkGZwMGpTyFW/E+Y0T7If1azAvhq3GBuQjI3npxIXGbSQ==",
"requires": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",

View File

@@ -78,10 +78,9 @@
"react-native-sound": "0.11.0",
"react-native-svg": "9.7.1",
"react-native-svg-transformer": "0.13.0",
"react-native-swipe-gestures": "1.0.4",
"react-native-swipeout": "2.3.6",
"react-native-watch-connectivity": "0.2.0",
"react-native-webrtc": "1.75.2",
"react-native-webrtc": "1.75.3",
"react-native-webview": "7.4.1",
"react-redux": "7.1.0",
"react-textarea-autosize": "7.1.0",

View File

@@ -1,7 +1,7 @@
// @flow
import React, { PureComponent, type Node } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
import { ColorSchemeRegistry } from '../../../color-scheme';
import { SlidingView } from '../../../react';
@@ -10,6 +10,16 @@ import { StyleType } from '../../../styles';
import { bottomSheetStyles as styles } from './styles';
/**
* Minimal distance that needs to be moved by the finger to consider it a swipe.
*/
const GESTURE_DISTANCE_THRESHOLD = 5;
/**
* The minimal speed needed to be achieved by the finger to consider it as a swipe.
*/
const GESTURE_SPEED_THRESHOLD = 0.2;
/**
* The type of {@code BottomSheet}'s React {@code Component} prop types.
*/
@@ -31,6 +41,11 @@ type Props = {
*/
onCancel: ?Function,
/**
* Callback to be attached to the custom swipe event of the BottomSheet.
*/
onSwipe?: Function,
/**
* Function to render a bottom sheet header element, if necessary.
*/
@@ -41,6 +56,23 @@ type Props = {
* A component emulating Android's BottomSheet.
*/
class BottomSheet extends PureComponent<Props> {
panResponder: Object;
/**
* Instantiates a new component.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
onPanResponderRelease: this._onGestureEnd.bind(this)
});
}
/**
* Implements React's {@link Component#render()}.
*
@@ -66,7 +98,8 @@ class BottomSheet extends PureComponent<Props> {
style = { [
styles.sheetItemContainer,
_styles.sheet
] }>
] }
{ ...this.panResponder.panHandlers }>
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false }
@@ -78,6 +111,48 @@ class BottomSheet extends PureComponent<Props> {
</SlidingView>
);
}
/**
* Callback to handle a gesture end event.
*
* @param {Object} evt - The native gesture event.
* @param {Object} gestureState - The gesture state.
* @returns {void}
*/
_onGestureEnd(evt, gestureState) {
const verticalSwipe = Math.abs(gestureState.vy) > Math.abs(gestureState.vx)
&& Math.abs(gestureState.vy) > GESTURE_SPEED_THRESHOLD;
if (verticalSwipe) {
const direction = gestureState.vy > 0 ? 'down' : 'up';
const { onCancel, onSwipe } = this.props;
let isSwipeHandled = false;
if (onSwipe) {
isSwipeHandled = onSwipe(direction);
}
if (direction === 'down' && !isSwipeHandled) {
// Swipe down is a special gesture that can be used to close the
// BottomSheet, so if the swipe is not handled by the parent
// component, we consider it as a request to close.
onCancel && onCancel();
}
}
}
/**
* Returns true if the pan responder should activate, false otherwise.
*
* @param {Object} evt - The native gesture event.
* @param {Object} gestureState - The gesture state.
* @returns {boolean}
*/
_onShouldSetResponder({ nativeEvent }, gestureState) {
return nativeEvent.touches.length === 1
&& Math.abs(gestureState.dx) > GESTURE_DISTANCE_THRESHOLD
&& Math.abs(gestureState.dy) > GESTURE_DISTANCE_THRESHOLD;
}
}
/**

View File

@@ -194,16 +194,14 @@ function _conferenceJoined({ getState }, next, action) {
_updateCallIntegrationMuted(action.conference, getState());
}
})
.catch(error => {
// Currently this error code is emitted only by Android.
.catch(() => {
// Currently errors here are only emitted by Android.
//
if (error.code === 'CONNECTION_NOT_FOUND_ERROR') {
// Some Samsung devices will fail to fully engage ConnectionService if no SIM card
// was ever installed on the device. We could check for it, but it would require
// the CALL_PHONE permission, which is not something we want to do, so fallback to
// not using ConnectionService.
_handleConnectionServiceFailure(getState());
}
// Some Samsung devices will fail to fully engage ConnectionService if no SIM card
// was ever installed on the device. We could check for it, but it would require
// the CALL_PHONE permission, which is not something we want to do, so fallback to
// not using ConnectionService.
_handleConnectionServiceFailure(getState());
});
}
@@ -304,9 +302,11 @@ function _conferenceWillJoin({ dispatch, getState }, next, action) {
{ text: 'OK' }
],
{ cancelable: false });
} else if (error.code === 'SECURITY_ERROR') {
} else {
// Some devices fail because the CALL_PHONE permission is not granted, which is
// nonsense, because it's not needed for self-managed connections.
// Some other devices fail because ConnectionService is not supported.
// Be that as it may, fallback to non-ConnectionService audio device handling.
_handleConnectionServiceFailure(state);
}

View File

@@ -1,9 +1,8 @@
// @flow
import React, { PureComponent } from 'react';
import { Platform, TouchableOpacity } from 'react-native';
import { Platform, TouchableOpacity, View } from 'react-native';
import Collapsible from 'react-native-collapsible';
import GestureRecognizer, { swipeDirections } from 'react-native-swipe-gestures';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
@@ -59,6 +58,11 @@ type Props = {
type State = {
/**
* True if the bottom scheet is scrolled to the top.
*/
scrolledToTop: boolean,
/**
* True if the 'more' button set needas to be rendered.
*/
@@ -88,6 +92,7 @@ class OverflowMenu extends PureComponent<Props, State> {
super(props);
this.state = {
scrolledToTop: true,
showMore: false
};
@@ -117,6 +122,7 @@ class OverflowMenu extends PureComponent<Props, State> {
return (
<BottomSheet
onCancel = { this._onCancel }
onSwipe = { this._onSwipe }
renderHeader = { this._renderMenuExpandToggle }>
<AudioRouteButton { ...buttonProps } />
<ToggleCameraButton { ...buttonProps } />
@@ -152,12 +158,7 @@ class OverflowMenu extends PureComponent<Props, State> {
*/
_renderMenuExpandToggle() {
return (
<GestureRecognizer
config = {{
velocityThreshold: 0.1,
directionalOffsetThreshold: 30
}}
onSwipe = { this._onSwipe }
<View
style = { [
this.props._bottomSheetStyles.sheet,
styles.expandMenuContainer
@@ -166,7 +167,7 @@ class OverflowMenu extends PureComponent<Props, State> {
{ /* $FlowFixMeProps */ }
<IconDragHandle style = { this.props._bottomSheetStyles.expandIcon } />
</TouchableOpacity>
</GestureRecognizer>
</View>
);
}
@@ -188,34 +189,31 @@ class OverflowMenu extends PureComponent<Props, State> {
return false;
}
_onSwipe: (string) => void;
_onSwipe: string => void;
/**
* Callback to be invoked when a swipe gesture is detected on the menu.
* Callback to be invoked when swipe gesture is detected on the menu. Returns true
* if the swipe gesture is handled by the menu, false otherwise.
*
* @param {string} gestureName - The name of the swipe gesture.
* @returns {void}
* @param {string} direction - Direction of 'up' or 'down'.
* @returns {boolean}
*/
_onSwipe(gestureName) {
_onSwipe(direction) {
const { showMore } = this.state;
switch (gestureName) {
case swipeDirections.SWIPE_UP:
switch (direction) {
case 'up':
!showMore && this.setState({
showMore: true
});
break;
case swipeDirections.SWIPE_DOWN:
if (showMore) {
// If the menu is expanded, we collapse it.
this.setState({
showMore: false
});
} else {
// If the menu is not expanded, we close the menu
this._onCancel();
}
break;
return !showMore;
case 'down':
showMore && this.setState({
showMore: false
});
return showMore;
}
}

View File

@@ -60,6 +60,11 @@ const styles = {
flexDirection: 'column'
},
sheetGestureRecognizer: {
alignItems: 'stretch',
flexDirection: 'column'
},
/**
* The style of the toolbar.
*/