kopia lustrzana https://github.com/ryukoposting/Signal-Android
Apply proper rotation to buttons and video in landscape.
rodzic
e6e8786d86
commit
2678a00781
|
@ -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'
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,10 @@ public final class WebRtcControls {
|
|||
this.participantLimit = participantLimit;
|
||||
}
|
||||
|
||||
boolean canRotateControls() {
|
||||
return !isGroupCall();
|
||||
}
|
||||
|
||||
boolean displayErrorControls() {
|
||||
return isError();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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'],
|
||||
|
|
Ładowanie…
Reference in New Issue