Apply proper rotation to buttons and video in landscape.

fork-5.53.8
Alex Hart 2021-01-29 16:22:01 -04:00 zatwierdzone przez Greyson Parrelli
rodzic e6e8786d86
commit 2678a00781
19 zmienionych plików z 326 dodań i 35 usunięć

Wyświetl plik

@ -338,7 +338,7 @@ dependencies {
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation 'org.signal:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:2.9.0'
implementation 'org.signal:ringrtc-android:2.9.2'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'

Wyświetl plik

@ -27,9 +27,7 @@ import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Rational;
import android.view.View;
import android.view.Window;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import androidx.annotation.NonNull;
@ -37,8 +35,6 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProviders;
import androidx.transition.Transition;
import androidx.transition.TransitionListenerAdapter;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
@ -47,6 +43,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.TooltipPopup;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsListUpdatePopupWindow;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState;
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil;
import org.thoughtcrime.securesms.components.webrtc.WebRtcAudioOutput;
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallView;
@ -65,7 +62,6 @@ import org.thoughtcrime.securesms.util.EllapsedTimeFormatter;
import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
@ -85,6 +81,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE";
private CallParticipantsListUpdatePopupWindow participantUpdateWindow;
private DeviceOrientationMonitor deviceOrientationMonitor;
private FullscreenHelper fullscreenHelper;
private WebRtcCallView callScreen;
@ -240,7 +237,12 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
}
private void initializeViewModel() {
viewModel = ViewModelProviders.of(this).get(WebRtcCallViewModel.class);
deviceOrientationMonitor = new DeviceOrientationMonitor(this);
getLifecycle().addObserver(deviceOrientationMonitor);
WebRtcCallViewModel.Factory factory = new WebRtcCallViewModel.Factory(deviceOrientationMonitor);
viewModel = ViewModelProviders.of(this, factory).get(WebRtcCallViewModel.class);
viewModel.setIsInPipMode(isInPipMode());
viewModel.getMicrophoneEnabled().observe(this, callScreen::setMicEnabled);
viewModel.getWebRtcControls().observe(this, callScreen::setWebRtcControls);
@ -262,6 +264,25 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
}
}
});
viewModel.getOrientation().observe(this, orientation -> {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_ORIENTATION_CHANGED)
.putExtra(WebRtcCallService.EXTRA_ORIENTATION_DEGREES, orientation.getDegrees());
startService(intent);
switch (orientation) {
case LANDSCAPE_LEFT_EDGE:
callScreen.rotateControls(90);
break;
case LANDSCAPE_RIGHT_EDGE:
callScreen.rotateControls(-90);
break;
case PORTRAIT_BOTTOM_EDGE:
callScreen.rotateControls(0);
}
});
}
private void handleViewModelEvent(@NonNull WebRtcCallViewModel.Event event) {

Wyświetl plik

@ -0,0 +1,104 @@
package org.thoughtcrime.securesms.components.sensors;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import org.thoughtcrime.securesms.util.ServiceUtil;
public final class DeviceOrientationMonitor implements DefaultLifecycleObserver {
private static final float MAGNITUDE_MAXIMUM = 1.5f;
private static final float MAGNITUDE_MINIMUM = 0.75f;
private static final float LANDSCAPE_PITCH_MINIMUM = -0.5f;
private static final float LANDSCAPE_PITCH_MAXIMUM = 0.5f;
private final SensorManager sensorManager;
private final EventListener eventListener = new EventListener();
private final float[] accelerometerReading = new float[3];
private final float[] magnetometerReading = new float[3];
private final float[] rotationMatrix = new float[9];
private final float[] orientationAngles = new float[3];
private final MutableLiveData<Orientation> orientation = new MutableLiveData<>();
public DeviceOrientationMonitor(@NonNull Context context) {
this.sensorManager = ServiceUtil.getSensorManager(context);
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometer != null) {
sensorManager.registerListener(eventListener,
accelerometer,
SensorManager.SENSOR_DELAY_NORMAL,
SensorManager.SENSOR_DELAY_UI);
}
Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (magneticField != null) {
sensorManager.registerListener(eventListener,
magneticField,
SensorManager.SENSOR_DELAY_NORMAL,
SensorManager.SENSOR_DELAY_UI);
}
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
sensorManager.unregisterListener(eventListener);
}
public LiveData<Orientation> getOrientation() {
return Transformations.distinctUntilChanged(orientation);
}
private void updateOrientationAngles() {
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading);
SensorManager.getOrientation(rotationMatrix, orientationAngles);
float pitch = orientationAngles[1];
float roll = orientationAngles[2];
float mag = (float) Math.sqrt(Math.pow(pitch, 2) + Math.pow(roll, 2));
if (mag > MAGNITUDE_MAXIMUM || mag < MAGNITUDE_MINIMUM) {
return;
}
if (pitch > LANDSCAPE_PITCH_MINIMUM && pitch < LANDSCAPE_PITCH_MAXIMUM) {
orientation.setValue(roll > 0 ? Orientation.LANDSCAPE_RIGHT_EDGE : Orientation.LANDSCAPE_LEFT_EDGE);
} else {
orientation.setValue(Orientation.PORTRAIT_BOTTOM_EDGE);
}
}
private final class EventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.length);
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.length);
}
updateOrientationAngles();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}

Wyświetl plik

@ -0,0 +1,29 @@
package org.thoughtcrime.securesms.components.sensors;
import androidx.annotation.NonNull;
public enum Orientation {
PORTRAIT_BOTTOM_EDGE(0),
LANDSCAPE_LEFT_EDGE(90),
LANDSCAPE_RIGHT_EDGE(270);
private final int degrees;
Orientation(int degrees) {
this.degrees = degrees;
}
public int getDegrees() {
return degrees;
}
public static @NonNull Orientation fromDegrees(int degrees) {
for (Orientation orientation : Orientation.values()) {
if (orientation.degrees == degrees) {
return orientation;
}
}
return PORTRAIT_BOTTOM_EDGE;
}
}

Wyświetl plik

@ -0,0 +1,24 @@
package org.thoughtcrime.securesms.components.webrtc;
import androidx.annotation.NonNull;
import org.webrtc.VideoFrame;
import org.webrtc.VideoSink;
public final class OrientationAwareVideoSink implements VideoSink {
private final VideoSink delegate;
public OrientationAwareVideoSink(@NonNull VideoSink delegate) {
this.delegate = delegate;
}
@Override
public void onFrame(VideoFrame videoFrame) {
if (videoFrame.getRotatedHeight() < videoFrame.getRotatedWidth()) {
delegate.onFrame(new VideoFrame(videoFrame.getBuffer(), 270, videoFrame.getTimestampNs()));
} else {
delegate.onFrame(videoFrame);
}
}
}

Wyświetl plik

@ -120,6 +120,7 @@ public class WebRtcCallView extends FrameLayout {
private final Set<View> topViews = new HashSet<>();
private final Set<View> visibleViewSet = new HashSet<>();
private final Set<View> adjustableMarginsSet = new HashSet<>();
private final Set<View> rotatableControls = new HashSet<>();
private WebRtcControls controls = WebRtcControls.NONE;
private final Runnable fadeOutRunnable = () -> {
@ -251,6 +252,16 @@ public class WebRtcCallView extends FrameLayout {
controlsListener.onCancelStartCall();
}
});
rotatableControls.add(hangup);
rotatableControls.add(answer);
rotatableControls.add(answerWithAudio);
rotatableControls.add(audioToggle);
rotatableControls.add(micToggle);
rotatableControls.add(videoToggle);
rotatableControls.add(cameraDirectionToggle);
rotatableControls.add(decline);
rotatableControls.add(smallLocalRender.findViewById(R.id.call_participant_mic_muted));
}
@Override
@ -288,6 +299,12 @@ public class WebRtcCallView extends FrameLayout {
cancelFadeOut();
}
public void rotateControls(int degrees) {
for (View view : rotatableControls) {
view.animate().rotation(degrees);
}
}
public void setControlsListener(@Nullable ControlsListener controlsListener) {
this.controlsListener = controlsListener;
}

Wyświetl plik

@ -10,9 +10,12 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.CallParticipant;
@ -31,23 +34,25 @@ import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class WebRtcCallViewModel extends ViewModel {
private final MutableLiveData<Boolean> microphoneEnabled = new MutableLiveData<>(true);
private final MutableLiveData<Boolean> isInPipMode = new MutableLiveData<>(false);
private final MutableLiveData<WebRtcControls> webRtcControls = new MutableLiveData<>(WebRtcControls.NONE);
private final LiveData<WebRtcControls> realWebRtcControls = LiveDataUtil.combineLatest(isInPipMode, webRtcControls, this::getRealWebRtcControls);
private final SingleLiveEvent<Event> events = new SingleLiveEvent<Event>();
private final MutableLiveData<Long> elapsed = new MutableLiveData<>(-1L);
private final MutableLiveData<LiveRecipient> liveRecipient = new MutableLiveData<>(Recipient.UNKNOWN.live());
private final MutableLiveData<CallParticipantsState> participantsState = new MutableLiveData<>(CallParticipantsState.STARTING_STATE);
private final SingleLiveEvent<CallParticipantListUpdate> callParticipantListUpdate = new SingleLiveEvent<>();
private final MutableLiveData<Collection<RecipientId>> identityChangedRecipients = new MutableLiveData<>(Collections.emptyList());
private final LiveData<SafetyNumberChangeEvent> safetyNumberChangeEvent = LiveDataUtil.combineLatest(isInPipMode, identityChangedRecipients, SafetyNumberChangeEvent::new);
private final LiveData<Recipient> groupRecipient = LiveDataUtil.filter(Transformations.switchMap(liveRecipient, LiveRecipient::getLiveData), Recipient::isActiveGroup);
private final LiveData<List<GroupMemberEntry.FullMember>> groupMembers = LiveDataUtil.skip(Transformations.switchMap(groupRecipient, r -> Transformations.distinctUntilChanged(new LiveGroup(r.requireGroupId()).getFullMembers())), 1);
private final LiveData<Boolean> shouldShowSpeakerHint = Transformations.map(participantsState, this::shouldShowSpeakerHint);
private final MutableLiveData<Boolean> microphoneEnabled = new MutableLiveData<>(true);
private final MutableLiveData<Boolean> isInPipMode = new MutableLiveData<>(false);
private final MutableLiveData<WebRtcControls> webRtcControls = new MutableLiveData<>(WebRtcControls.NONE);
private final LiveData<WebRtcControls> realWebRtcControls = LiveDataUtil.combineLatest(isInPipMode, webRtcControls, this::getRealWebRtcControls);
private final SingleLiveEvent<Event> events = new SingleLiveEvent<Event>();
private final MutableLiveData<Long> elapsed = new MutableLiveData<>(-1L);
private final MutableLiveData<LiveRecipient> liveRecipient = new MutableLiveData<>(Recipient.UNKNOWN.live());
private final MutableLiveData<CallParticipantsState> participantsState = new MutableLiveData<>(CallParticipantsState.STARTING_STATE);
private final SingleLiveEvent<CallParticipantListUpdate> callParticipantListUpdate = new SingleLiveEvent<>();
private final MutableLiveData<Collection<RecipientId>> identityChangedRecipients = new MutableLiveData<>(Collections.emptyList());
private final LiveData<SafetyNumberChangeEvent> safetyNumberChangeEvent = LiveDataUtil.combineLatest(isInPipMode, identityChangedRecipients, SafetyNumberChangeEvent::new);
private final LiveData<Recipient> groupRecipient = LiveDataUtil.filter(Transformations.switchMap(liveRecipient, LiveRecipient::getLiveData), Recipient::isActiveGroup);
private final LiveData<List<GroupMemberEntry.FullMember>> groupMembers = LiveDataUtil.skip(Transformations.switchMap(groupRecipient, r -> Transformations.distinctUntilChanged(new LiveGroup(r.requireGroupId()).getFullMembers())), 1);
private final LiveData<Boolean> shouldShowSpeakerHint = Transformations.map(participantsState, this::shouldShowSpeakerHint);
private final LiveData<Orientation> orientation;
private boolean canDisplayTooltipIfNeeded = true;
private boolean hasEnabledLocalVideo = false;
@ -61,6 +66,20 @@ public class WebRtcCallViewModel extends ViewModel {
private final WebRtcCallRepository repository = new WebRtcCallRepository(ApplicationDependencies.getApplication());
private WebRtcCallViewModel(@NonNull DeviceOrientationMonitor deviceOrientationMonitor) {
orientation = LiveDataUtil.combineLatest(deviceOrientationMonitor.getOrientation(), webRtcControls, (deviceOrientation, controls) -> {
if (controls.canRotateControls()) {
return deviceOrientation;
} else {
return Orientation.PORTRAIT_BOTTOM_EDGE;
}
});
}
public LiveData<Orientation> getOrientation() {
return Transformations.distinctUntilChanged(orientation);
}
public LiveData<Boolean> getMicrophoneEnabled() {
return Transformations.distinctUntilChanged(microphoneEnabled);
}
@ -394,4 +413,18 @@ public class WebRtcCallViewModel extends ViewModel {
return recipientIds;
}
}
public static class Factory implements ViewModelProvider.Factory {
private final DeviceOrientationMonitor deviceOrientationMonitor;
public Factory(@NonNull DeviceOrientationMonitor deviceOrientationMonitor) {
this.deviceOrientationMonitor = deviceOrientationMonitor;
}
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return Objects.requireNonNull(modelClass.cast(new WebRtcCallViewModel(deviceOrientationMonitor)));
}
}
}

Wyświetl plik

@ -51,6 +51,10 @@ public final class WebRtcControls {
this.participantLimit = participantLimit;
}
boolean canRotateControls() {
return !isGroupCall();
}
boolean displayErrorControls() {
return isError();
}

Wyświetl plik

@ -46,6 +46,7 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
@NonNull private CameraState.Direction activeDirection;
private boolean enabled;
private boolean isInitialized;
private int orientation;
public Camera(@NonNull Context context,
@NonNull CameraEventListener cameraEventListener,
@ -81,6 +82,7 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
capturer.initialize(SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", eglBase.getEglBaseContext()),
context,
observer);
capturer.setOrientation(orientation);
isInitialized = true;
}
}
@ -99,6 +101,15 @@ public class Camera implements CameraControl, CameraVideoCapturer.CameraSwitchHa
capturer.switchCamera(this);
}
@Override
public void setOrientation(@Nullable Integer orientation) {
this.orientation = orientation;
if (isInitialized && capturer != null) {
capturer.setOrientation(orientation);
}
}
@Override
public void setEnabled(boolean enabled) {
Log.i(TAG, "setEnabled(): " + enabled);

Wyświetl plik

@ -34,6 +34,7 @@ import org.signal.zkgroup.VerificationFailedException;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -42,7 +43,6 @@ import org.thoughtcrime.securesms.events.GroupCallPeekEvent;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@ -141,6 +141,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
public static final String EXTRA_GROUP_CALL_UPDATE_GROUP = "group_call_update_group";
public static final String EXTRA_GROUP_CALL_ERA_ID = "era_id";
public static final String EXTRA_RECIPIENT_IDS = "recipient_ids";
public static final String EXTRA_ORIENTATION_DEGREES = "orientation_degrees";
public static final String ACTION_PRE_JOIN_CALL = "CALL_PRE_JOIN";
public static final String ACTION_CANCEL_PRE_JOIN_CALL = "CANCEL_PRE_JOIN_CALL";
@ -198,6 +199,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
public static final String ACTION_HTTP_FAILURE = "HTTP_FAILURE";
public static final String ACTION_SEND_OPAQUE_MESSAGE = "SEND_OPAQUE_MESSAGE";
public static final String ACTION_RECEIVE_OPAQUE_MESSAGE = "RECEIVE_OPAQUE_MESSAGE";
public static final String ACTION_ORIENTATION_CHANGED = "ORIENTATION_CHANGED";
public static final String ACTION_GROUP_LOCAL_DEVICE_STATE_CHANGED = "GROUP_LOCAL_DEVICE_CHANGE";
public static final String ACTION_GROUP_REMOTE_DEVICE_STATE_CHANGED = "GROUP_REMOTE_DEVICE_CHANGE";

Wyświetl plik

@ -350,6 +350,11 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
return terminateGroupCall(currentState);
}
@Override
protected @NonNull WebRtcServiceState handleOrientationChanged(@NonNull WebRtcServiceState currentState, int orientationDegrees) {
return currentState;
}
public synchronized @NonNull WebRtcServiceState terminateGroupCall(@NonNull WebRtcServiceState currentState) {
return terminateGroupCall(currentState, true);
}

Wyświetl plik

@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.components.webrtc.OrientationAwareVideoSink;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.events.CallParticipant;
@ -88,8 +88,8 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
webRtcInteractor.getCallManager().proceed(activePeer.getCallId(),
context,
videoState.requireEglBase(),
videoState.requireLocalSink(),
callParticipant.getVideoSink(),
new OrientationAwareVideoSink(videoState.requireLocalSink()),
new OrientationAwareVideoSink(callParticipant.getVideoSink()),
videoState.requireCamera(),
iceServers,
hideIp,

Wyświetl plik

@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.components.webrtc.OrientationAwareVideoSink;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.events.CallParticipant;
@ -114,8 +114,8 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
webRtcInteractor.getCallManager().proceed(activePeer.getCallId(),
context,
videoState.requireEglBase(),
videoState.requireLocalSink(),
callParticipant.getVideoSink(),
new OrientationAwareVideoSink(videoState.requireLocalSink()),
new OrientationAwareVideoSink(callParticipant.getVideoSink()),
videoState.requireCamera(),
iceServers,
isAlwaysTurn,

Wyświetl plik

@ -13,12 +13,14 @@ import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.ringrtc.CallState;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraState;
import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
@ -82,6 +84,7 @@ import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_LOCAL_
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_MESSAGE_SENT_ERROR;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_MESSAGE_SENT_SUCCESS;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_NETWORK_CHANGE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_ORIENTATION_CHANGED;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_OUTGOING_CALL;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_PRE_JOIN_CALL;
import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_RECEIVED_OFFER_EXPIRED;
@ -135,6 +138,7 @@ import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIc
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIceServers;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getNullableRemotePeerFromMap;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getOfferMessageType;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getOrientationDegrees;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRemotePeer;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getRemotePeerFromMap;
@ -220,6 +224,7 @@ public abstract class WebRtcActionProcessor {
case ACTION_CAMERA_SWITCH_COMPLETED: return handleCameraSwitchCompleted(currentState, getCameraState(intent));
case ACTION_NETWORK_CHANGE: return handleNetworkChanged(currentState, getAvailable(intent));
case ACTION_BANDWIDTH_MODE_UPDATE: return handleBandwidthModeUpdate(currentState);
case ACTION_ORIENTATION_CHANGED: return handleOrientationChanged(currentState, getOrientationDegrees(intent));
// End Call Actions
case ACTION_ENDED_REMOTE_HANGUP:
@ -626,6 +631,18 @@ public abstract class WebRtcActionProcessor {
return currentState;
}
protected @NonNull WebRtcServiceState handleOrientationChanged(@NonNull WebRtcServiceState currentState, int orientationDegrees) {
Camera camera = currentState.getVideoState().getCamera();
if (camera != null) {
camera.setOrientation(orientationDegrees);
}
return currentState.builder()
.changeLocalDeviceState()
.setOrientation(Orientation.fromDegrees(orientationDegrees))
.build();
}
//endregion Local device
//region End call

Wyświetl plik

@ -47,6 +47,7 @@ import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_O
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_SDP;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_TYPE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OPAQUE_MESSAGE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ORIENTATION_DEGREES;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_DEVICE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_IDENTITY_KEY;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_REMOTE_PEER_KEY;
@ -141,6 +142,10 @@ public final class WebRtcIntentParser {
return intent.getBooleanExtra(EXTRA_AVAILABLE, false);
}
public static int getOrientationDegrees(@NonNull Intent intent) {
return intent.getIntExtra(EXTRA_ORIENTATION_DEGREES, 0);
}
public static @NonNull ArrayList<IceCandidateParcel> getIceCandidates(@NonNull Intent intent) {
return Objects.requireNonNull(intent.getParcelableArrayListExtra(EXTRA_ICE_CANDIDATES));
}

Wyświetl plik

@ -5,6 +5,7 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.components.webrtc.OrientationAwareVideoSink;
import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraEventListener;
import org.thoughtcrime.securesms.ringrtc.CameraState;
@ -14,6 +15,7 @@ import org.thoughtcrime.securesms.util.Util;
import org.webrtc.CapturerObserver;
import org.webrtc.EglBase;
import org.webrtc.VideoFrame;
import org.webrtc.VideoSink;
/**
* Helper for initializing, reinitializing, and deinitializing the camera and it's related
@ -34,6 +36,8 @@ public final class WebRtcVideoUtil {
BroadcastVideoSink localSink = new BroadcastVideoSink(eglBase);
Camera camera = new Camera(context, cameraEventListener, eglBase, CameraState.Direction.FRONT);
camera.setOrientation(currentState.getLocalDeviceState().getOrientation().getDegrees());
builder.changeVideoState()
.eglBase(eglBase)
.localSink(localSink)
@ -63,6 +67,8 @@ public final class WebRtcVideoUtil {
currentState.getVideoState().requireEglBase(),
currentState.getLocalDeviceState().getCameraState().getActiveDirection());
camera.setOrientation(currentState.getLocalDeviceState().getOrientation().getDegrees());
builder.changeVideoState()
.camera(camera)
.commit()
@ -97,8 +103,8 @@ public final class WebRtcVideoUtil {
}
public static @NonNull WebRtcServiceState initializeVanityCamera(@NonNull WebRtcServiceState currentState) {
Camera camera = currentState.getVideoState().requireCamera();
BroadcastVideoSink sink = currentState.getVideoState().requireLocalSink();
Camera camera = currentState.getVideoState().requireCamera();
VideoSink sink = new OrientationAwareVideoSink(currentState.getVideoState().requireLocalSink());
if (camera.hasCapturer()) {
camera.initCapturer(new CapturerObserver() {

Wyświetl plik

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.service.webrtc.state;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.ringrtc.CameraState;
/**
@ -11,19 +12,21 @@ public final class LocalDeviceState {
CameraState cameraState;
boolean microphoneEnabled;
boolean bluetoothAvailable;
Orientation orientation;
LocalDeviceState() {
this(CameraState.UNKNOWN, true, false);
this(CameraState.UNKNOWN, true, false, Orientation.PORTRAIT_BOTTOM_EDGE);
}
LocalDeviceState(@NonNull LocalDeviceState toCopy) {
this(toCopy.cameraState, toCopy.microphoneEnabled, toCopy.bluetoothAvailable);
this(toCopy.cameraState, toCopy.microphoneEnabled, toCopy.bluetoothAvailable, toCopy.orientation);
}
LocalDeviceState(@NonNull CameraState cameraState, boolean microphoneEnabled, boolean bluetoothAvailable) {
LocalDeviceState(@NonNull CameraState cameraState, boolean microphoneEnabled, boolean bluetoothAvailable, @NonNull Orientation orientation) {
this.cameraState = cameraState;
this.microphoneEnabled = microphoneEnabled;
this.bluetoothAvailable = bluetoothAvailable;
this.orientation = orientation;
}
public @NonNull CameraState getCameraState() {
@ -37,4 +40,8 @@ public final class LocalDeviceState {
public boolean isBluetoothAvailable() {
return bluetoothAvailable;
}
public @NonNull Orientation getOrientation() {
return orientation;
}
}

Wyświetl plik

@ -6,6 +6,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.OptionalLong;
import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.CallParticipantId;
@ -99,6 +100,11 @@ public class WebRtcServiceStateBuilder {
toBuild.bluetoothAvailable = available;
return this;
}
public @NonNull LocalDeviceStateBuilder setOrientation(@NonNull Orientation orientation) {
toBuild.orientation = orientation;
return this;
}
}
public class CallSetupStateBuilder {

Wyświetl plik

@ -411,8 +411,8 @@ dependencyVerification {
['org.signal:argon2:13.1',
'0f686ccff0d4842bfcc74d92e8dc780a5f159b9376e37a1189fabbcdac458bef'],
['org.signal:ringrtc-android:2.9.0',
'058ff7dc0c01c1c0db363e7396e357bdcfc6f9a3ddc313c2abae032e979d691f'],
['org.signal:ringrtc-android:2.9.2',
'baf77e1f314dce89278af205637d607dbf4607651dee02384f111f43fea29cf6'],
['org.signal:zkgroup-android:0.7.0',
'52b172565bd01526e93ebf1796b834bdc449d4fe3422c1b827e49cb8d4f13fbd'],