mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-21 20:45:29 +03:00
add grid view for calls. make own video movable
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
7a2b908c98
commit
b8e4c4da56
10 changed files with 603 additions and 365 deletions
|
@ -10,6 +10,7 @@ Types of changes can be: Added/Changed/Deprecated/Removed/Fixed/Security
|
|||
- open files inside app (jpg, .png, .gif, .mp3, .mp4, .mov, .wav, .txt, .md)
|
||||
- other data types are opened with external apps if they are able to handle it
|
||||
- edit profile information and privacy settings
|
||||
- add grid view for calls, make own video movable
|
||||
|
||||
### Changed
|
||||
- improve conversation list design and dark/light theming (@AndyScherzinger)
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package com.nextcloud.talk.adapters;
|
||||
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.MediaStream;
|
||||
|
||||
public class ParticipantDisplayItem {
|
||||
private String userId;
|
||||
private String session;
|
||||
private String nick;
|
||||
private String urlForAvatar;
|
||||
private MediaStream mediaStream;
|
||||
private String streamType;
|
||||
private boolean streamEnabled;
|
||||
private EglBase rootEglBase;
|
||||
private boolean isAudioEnabled;
|
||||
|
||||
public ParticipantDisplayItem(String userId, String session, String nick, String urlForAvatar, MediaStream mediaStream, String streamType, boolean streamEnabled, EglBase rootEglBase) {
|
||||
this.userId = userId;
|
||||
this.session = session;
|
||||
this.nick = nick;
|
||||
this.urlForAvatar = urlForAvatar;
|
||||
this.mediaStream = mediaStream;
|
||||
this.streamType = streamType;
|
||||
this.streamEnabled = streamEnabled;
|
||||
this.rootEglBase = rootEglBase;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public void setSession(String session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public String getNick() {
|
||||
return nick;
|
||||
}
|
||||
|
||||
public void setNick(String nick) {
|
||||
this.nick = nick;
|
||||
}
|
||||
|
||||
public String getUrlForAvatar() {
|
||||
return urlForAvatar;
|
||||
}
|
||||
|
||||
public void setUrlForAvatar(String urlForAvatar) {
|
||||
this.urlForAvatar = urlForAvatar;
|
||||
}
|
||||
|
||||
public MediaStream getMediaStream() {
|
||||
return mediaStream;
|
||||
}
|
||||
|
||||
public void setMediaStream(MediaStream mediaStream) {
|
||||
this.mediaStream = mediaStream;
|
||||
}
|
||||
|
||||
public String getStreamType() {
|
||||
return streamType;
|
||||
}
|
||||
|
||||
public void setStreamType(String streamType) {
|
||||
this.streamType = streamType;
|
||||
}
|
||||
|
||||
public boolean isStreamEnabled() {
|
||||
return streamEnabled;
|
||||
}
|
||||
|
||||
public void setStreamEnabled(boolean streamEnabled) {
|
||||
this.streamEnabled = streamEnabled;
|
||||
}
|
||||
|
||||
public EglBase getRootEglBase() {
|
||||
return rootEglBase;
|
||||
}
|
||||
|
||||
public void setRootEglBase(EglBase rootEglBase) {
|
||||
this.rootEglBase = rootEglBase;
|
||||
}
|
||||
|
||||
public boolean isAudioEnabled() {
|
||||
return isAudioEnabled;
|
||||
}
|
||||
|
||||
public void setAudioEnabled(boolean audioEnabled) {
|
||||
isAudioEnabled = audioEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParticipantSession{" +
|
||||
"userId='" + userId + '\'' +
|
||||
", session='" + session + '\'' +
|
||||
", nick='" + nick + '\'' +
|
||||
", urlForAvatar='" + urlForAvatar + '\'' +
|
||||
", mediaStream=" + mediaStream +
|
||||
", streamType='" + streamType + '\'' +
|
||||
", streamEnabled=" + streamEnabled +
|
||||
", rootEglBase=" + rootEglBase +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
package com.nextcloud.talk.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
|
||||
import org.webrtc.MediaStream;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.webrtc.SurfaceViewRenderer;
|
||||
import org.webrtc.VideoTrack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public class ParticipantsAdapter extends BaseAdapter {
|
||||
|
||||
private static final String TAG = "ParticipantsAdapter";
|
||||
|
||||
private final Context mContext;
|
||||
private final ArrayList<ParticipantDisplayItem> participantDisplayItems;
|
||||
private final RelativeLayout gridViewWrapper;
|
||||
private final LinearLayout callInfosLinearLayout;
|
||||
private final int columns;
|
||||
private final boolean isVoiceOnlyCall;
|
||||
|
||||
public ParticipantsAdapter(Context mContext,
|
||||
Map<String, ParticipantDisplayItem> participantDisplayItems,
|
||||
RelativeLayout gridViewWrapper,
|
||||
LinearLayout linearLayout,
|
||||
int columns,
|
||||
boolean isVoiceOnlyCall) {
|
||||
this.mContext = mContext;
|
||||
this.gridViewWrapper = gridViewWrapper;
|
||||
this.callInfosLinearLayout = linearLayout;
|
||||
this.columns = columns;
|
||||
this.isVoiceOnlyCall = isVoiceOnlyCall;
|
||||
|
||||
this.participantDisplayItems = new ArrayList<>();
|
||||
this.participantDisplayItems.addAll(participantDisplayItems.values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return participantDisplayItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParticipantDisplayItem getItem(int position) {
|
||||
return participantDisplayItems.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ParticipantDisplayItem participantDisplayItem = getItem(position);
|
||||
|
||||
SurfaceViewRenderer surfaceViewRenderer;
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(mContext).inflate(R.layout.call_item, parent, false);
|
||||
convertView.setVisibility(View.VISIBLE);
|
||||
|
||||
surfaceViewRenderer = convertView.findViewById(R.id.surface_view);
|
||||
try {
|
||||
surfaceViewRenderer.setMirror(false);
|
||||
surfaceViewRenderer.init(participantDisplayItem.getRootEglBase().getEglBaseContext(), null);
|
||||
surfaceViewRenderer.setZOrderMediaOverlay(false);
|
||||
// disabled because it causes some devices to crash
|
||||
surfaceViewRenderer.setEnableHardwareScaler(false);
|
||||
surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "error while initializing surfaceViewRenderer", e);
|
||||
}
|
||||
} else {
|
||||
surfaceViewRenderer = convertView.findViewById(R.id.surface_view);
|
||||
}
|
||||
|
||||
ViewGroup.LayoutParams layoutParams = convertView.getLayoutParams();
|
||||
layoutParams.height = scaleGridViewItemHeight();
|
||||
convertView.setLayoutParams(layoutParams);
|
||||
|
||||
|
||||
TextView nickTextView = convertView.findViewById(R.id.peer_nick_text_view);
|
||||
SimpleDraweeView imageView = convertView.findViewById(R.id.avatarImageView);
|
||||
|
||||
MediaStream mediaStream = participantDisplayItem.getMediaStream();
|
||||
if (hasVideoStream(participantDisplayItem, mediaStream)) {
|
||||
VideoTrack videoTrack = mediaStream.videoTracks.get(0);
|
||||
videoTrack.addSink(surfaceViewRenderer);
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.VISIBLE);
|
||||
nickTextView.setVisibility(View.GONE);
|
||||
} else {
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.INVISIBLE);
|
||||
nickTextView.setVisibility(View.VISIBLE);
|
||||
nickTextView.setText(participantDisplayItem.getNick());
|
||||
|
||||
imageView.setController(null);
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(imageView.getController())
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(participantDisplayItem.getUrlForAvatar(), null))
|
||||
.build();
|
||||
imageView.setController(draweeController);
|
||||
}
|
||||
|
||||
ImageView audioOffView = convertView.findViewById(R.id.remote_audio_off);
|
||||
if (!participantDisplayItem.isAudioEnabled()) {
|
||||
audioOffView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
audioOffView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private boolean hasVideoStream(ParticipantDisplayItem participantDisplayItem, MediaStream mediaStream) {
|
||||
return mediaStream != null && mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0 && participantDisplayItem.isStreamEnabled();
|
||||
}
|
||||
|
||||
private int scaleGridViewItemHeight() {
|
||||
int headerHeight = 0;
|
||||
if (callInfosLinearLayout.getVisibility() == View.VISIBLE && isVoiceOnlyCall) {
|
||||
headerHeight = callInfosLinearLayout.getHeight();
|
||||
}
|
||||
int itemHeight = (gridViewWrapper.getHeight() - headerHeight) / getRowsCount(getCount());
|
||||
return itemHeight;
|
||||
}
|
||||
|
||||
private int getRowsCount(int items) {
|
||||
int rows = (int) Math.ceil((double) items / (double) columns);
|
||||
if (rows == 0) {
|
||||
rows = 1;
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
}
|
|
@ -34,12 +34,15 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
@ -51,11 +54,11 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.activities.MagicCallActivity;
|
||||
import com.nextcloud.talk.adapters.ParticipantDisplayItem;
|
||||
import com.nextcloud.talk.adapters.ParticipantsAdapter;
|
||||
import com.nextcloud.talk.api.NcApi;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.controllers.base.BaseController;
|
||||
|
@ -143,6 +146,7 @@ import javax.inject.Inject;
|
|||
import autodagger.AutoInjector;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.OnItemClick;
|
||||
import butterknife.OnLongClick;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
|
@ -180,8 +184,8 @@ public class CallController extends BaseController {
|
|||
SurfaceViewRenderer pipVideoView;
|
||||
@BindView(R.id.controllerCallLayout)
|
||||
RelativeLayout controllerCallLayout;
|
||||
@BindView(R.id.remote_renderers_layout)
|
||||
LinearLayout remoteRenderersLayout;
|
||||
@BindView(R.id.gridview)
|
||||
GridView gridView;
|
||||
|
||||
@BindView(R.id.callControlsLinearLayout)
|
||||
LinearLayout callControls;
|
||||
|
@ -201,6 +205,9 @@ public class CallController extends BaseController {
|
|||
@BindView(R.id.callConversationNameTextView)
|
||||
TextView callConversationNameTextView;
|
||||
|
||||
@BindView(R.id.selfVideoView)
|
||||
FrameLayout selfVideoView;
|
||||
|
||||
@BindView(R.id.callStateRelativeLayoutView)
|
||||
RelativeLayout callStateView;
|
||||
|
||||
|
@ -264,7 +271,6 @@ public class CallController extends BaseController {
|
|||
// push to talk
|
||||
private boolean isPTTActive = false;
|
||||
private PulseAnimation pulseAnimation;
|
||||
private View.OnClickListener videoOnClickListener;
|
||||
|
||||
private String baseUrl;
|
||||
private String roomId;
|
||||
|
@ -286,6 +292,9 @@ public class CallController extends BaseController {
|
|||
|
||||
private MediaPlayer mediaPlayer;
|
||||
|
||||
private Map<String, ParticipantDisplayItem> participantDisplayItems;
|
||||
private ParticipantsAdapter participantsAdapter;
|
||||
|
||||
@Parcel
|
||||
public enum CallStatus {
|
||||
CONNECTING, CALLING_TIMEOUT, JOINED, IN_CONVERSATION, RECONNECTING, OFFLINE, LEAVING, PUBLISHER_FAILED
|
||||
|
@ -345,19 +354,18 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
protected void onViewBound(@NonNull View view) {
|
||||
super.onViewBound(view);
|
||||
|
||||
microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener());
|
||||
videoOnClickListener = new VideoClickListener();
|
||||
|
||||
pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
|
||||
.setDuration(310)
|
||||
.setRepeatCount(PulseAnimation.INFINITE)
|
||||
.setRepeatMode(PulseAnimation.REVERSE);
|
||||
|
||||
setPipVideoViewDimensions();
|
||||
|
||||
try {
|
||||
cache.evictAll();
|
||||
|
@ -368,7 +376,7 @@ public class CallController extends BaseController {
|
|||
callControls.setZ(100.0f);
|
||||
basicInitialization();
|
||||
initViews();
|
||||
|
||||
initPipView();
|
||||
initiateCall();
|
||||
}
|
||||
|
||||
|
@ -467,7 +475,11 @@ public class CallController extends BaseController {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void initViews() {
|
||||
participantDisplayItems = new HashMap<>();
|
||||
|
||||
if (isVoiceOnlyCall) {
|
||||
callControlEnableSpeaker.setVisibility(View.VISIBLE);
|
||||
cameraSwitchButton.setVisibility(View.GONE);
|
||||
|
@ -476,7 +488,7 @@ public class CallController extends BaseController {
|
|||
|
||||
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.addRule(RelativeLayout.BELOW, R.id.callInfosLinearLayout);
|
||||
remoteRenderersLayout.setLayoutParams(params);
|
||||
gridView.setLayoutParams(params);
|
||||
} else {
|
||||
callControlEnableSpeaker.setVisibility(View.GONE);
|
||||
if (cameraEnumerator.getDeviceNames().length < 2) {
|
||||
|
@ -488,7 +500,77 @@ public class CallController extends BaseController {
|
|||
// disabled because it causes some devices to crash
|
||||
pipVideoView.setEnableHardwareScaler(false);
|
||||
pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
||||
|
||||
pipVideoView.setOnTouchListener(new SelfVideoTouchListener());
|
||||
|
||||
}
|
||||
|
||||
gridView.setOnTouchListener(new View.OnTouchListener() {
|
||||
public boolean onTouch(View v, MotionEvent me) {
|
||||
int action = me.getActionMasked();
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
showCallControls();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
initGridAdapter();
|
||||
}
|
||||
|
||||
private void initGridAdapter() {
|
||||
GridView gridView = conversationView.findViewById(R.id.gridview);
|
||||
|
||||
int columns;
|
||||
int participantsInGrid = participantDisplayItems.size();
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
if (participantsInGrid > 8) {
|
||||
columns = 3;
|
||||
} else if (participantsInGrid > 2) {
|
||||
columns = 2;
|
||||
} else {
|
||||
columns = 1;
|
||||
}
|
||||
} else {
|
||||
if (participantsInGrid > 8) {
|
||||
columns = 4;
|
||||
} else if (participantsInGrid > 2) {
|
||||
columns = 3;
|
||||
} else if (participantsInGrid > 1) {
|
||||
columns = 2;
|
||||
} else {
|
||||
columns = 1;
|
||||
}
|
||||
}
|
||||
|
||||
gridView.setNumColumns(columns);
|
||||
|
||||
RelativeLayout gridViewWrapper = conversationView.findViewById(R.id.conversationRelativeLayoutView);
|
||||
gridViewWrapper.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
gridViewWrapper.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
int height = gridViewWrapper.getMeasuredHeight();
|
||||
gridView.setMinimumHeight(height);
|
||||
}
|
||||
});
|
||||
|
||||
LinearLayout callInfosLinearLayout = conversationView.findViewById(R.id.callInfosLinearLayout);
|
||||
callInfosLinearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
callInfosLinearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
participantsAdapter = new ParticipantsAdapter(
|
||||
this.getActivity(),
|
||||
participantDisplayItems,
|
||||
gridViewWrapper,
|
||||
callInfosLinearLayout,
|
||||
columns,
|
||||
isVoiceOnlyCall);
|
||||
gridView.setAdapter(participantsAdapter);
|
||||
}
|
||||
|
||||
|
||||
|
@ -534,7 +616,7 @@ public class CallController extends BaseController {
|
|||
fetchSignalingSettings();
|
||||
}
|
||||
} else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(),
|
||||
PERMISSIONS_CALL)) {
|
||||
PERMISSIONS_CALL)) {
|
||||
checkIfSomeAreApproved();
|
||||
}
|
||||
|
||||
|
@ -744,7 +826,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
} else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(),
|
||||
PERMISSIONS_MICROPHONE)) {
|
||||
PERMISSIONS_MICROPHONE)) {
|
||||
// Microphone permission is permanently denied so we cannot request it normally.
|
||||
|
||||
OpenAppDetailsDialogFragment.show(
|
||||
|
@ -787,7 +869,7 @@ public class CallController extends BaseController {
|
|||
|
||||
toggleMedia(videoOn, true);
|
||||
} else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(),
|
||||
PERMISSIONS_CAMERA)) {
|
||||
PERMISSIONS_CAMERA)) {
|
||||
// Camera permission is permanently denied so we cannot request it normally.
|
||||
OpenAppDetailsDialogFragment.show(
|
||||
R.string.nc_camera_permission_permanently_denied,
|
||||
|
@ -803,7 +885,7 @@ public class CallController extends BaseController {
|
|||
|
||||
}
|
||||
|
||||
@OnClick({R.id.call_control_switch_camera, R.id.pip_video_view})
|
||||
@OnClick({R.id.call_control_switch_camera})
|
||||
public void switchCamera() {
|
||||
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
|
||||
if (cameraVideoCapturer != null) {
|
||||
|
@ -1046,7 +1128,7 @@ public class CallController extends BaseController {
|
|||
if (!conversationUser.getUserId().equals("?")) {
|
||||
try {
|
||||
userUtils.createOrUpdateUser(null, null, null, null, null, null, null,
|
||||
conversationUser.getId(), null, null, LoganSquare.serialize(externalSignalingServer))
|
||||
conversationUser.getId(), null, null, LoganSquare.serialize(externalSignalingServer))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
} catch (IOException exception) {
|
||||
|
@ -1059,11 +1141,11 @@ public class CallController extends BaseController {
|
|||
i++) {
|
||||
iceServer = signalingSettingsOverall.getOcs().getSettings().getStunServers().get(i);
|
||||
if (TextUtils.isEmpty(iceServer.getUsername()) || TextUtils.isEmpty(iceServer
|
||||
.getCredential())) {
|
||||
.getCredential())) {
|
||||
iceServers.add(new PeerConnection.IceServer(iceServer.getUrl()));
|
||||
} else {
|
||||
iceServers.add(new PeerConnection.IceServer(iceServer.getUrl(),
|
||||
iceServer.getUsername(), iceServer.getCredential()));
|
||||
iceServer.getUsername(), iceServer.getCredential()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1074,11 +1156,11 @@ public class CallController extends BaseController {
|
|||
iceServer = signalingSettingsOverall.getOcs().getSettings().getTurnServers().get(i);
|
||||
for (int j = 0; j < iceServer.getUrls().size(); j++) {
|
||||
if (TextUtils.isEmpty(iceServer.getUsername()) || TextUtils.isEmpty(iceServer
|
||||
.getCredential())) {
|
||||
.getCredential())) {
|
||||
iceServers.add(new PeerConnection.IceServer(iceServer.getUrls().get(j)));
|
||||
} else {
|
||||
iceServers.add(new PeerConnection.IceServer(iceServer.getUrls().get(j),
|
||||
iceServer.getUsername(), iceServer.getCredential()));
|
||||
iceServer.getUsername(), iceServer.getCredential()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1154,7 +1236,7 @@ public class CallController extends BaseController {
|
|||
|
||||
if (TextUtils.isEmpty(callSession)) {
|
||||
ncApi.joinRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(baseUrl,
|
||||
roomToken), conversationPassword)
|
||||
roomToken), conversationPassword)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.retry(3)
|
||||
|
@ -1207,7 +1289,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
ncApi.joinCall(credentials,
|
||||
ApiUtils.getUrlForCall(baseUrl, roomToken), inCallFlag)
|
||||
ApiUtils.getUrlForCall(baseUrl, roomToken), inCallFlag)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.retry(3)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
@ -1381,7 +1463,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick({R.id.pip_video_view, R.id.remote_renderers_layout})
|
||||
@OnItemClick({R.id.gridview})
|
||||
public void showCallControls() {
|
||||
animateCallControls(true, 0);
|
||||
}
|
||||
|
@ -1414,10 +1496,10 @@ public class CallController extends BaseController {
|
|||
processUsersInRoom((List<HashMap<String, Object>>) signaling.getMessageWrapper());
|
||||
} else if ("message".equals(messageType)) {
|
||||
NCSignalingMessage ncSignalingMessage = LoganSquare.parse(signaling.getMessageWrapper().toString(),
|
||||
NCSignalingMessage.class);
|
||||
NCSignalingMessage.class);
|
||||
processMessage(ncSignalingMessage);
|
||||
} else {
|
||||
Log.d(TAG, "Something went very very wrong");
|
||||
Log.e(TAG, "unexpected message type when receiving signaling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1425,7 +1507,7 @@ public class CallController extends BaseController {
|
|||
if (ncSignalingMessage.getRoomType().equals("video") || ncSignalingMessage.getRoomType().equals("screen")) {
|
||||
MagicPeerConnectionWrapper magicPeerConnectionWrapper =
|
||||
getPeerConnectionWrapperForSessionIdAndType(ncSignalingMessage.getFrom(),
|
||||
ncSignalingMessage.getRoomType(), false);
|
||||
ncSignalingMessage.getRoomType(), false);
|
||||
|
||||
String type = null;
|
||||
if (ncSignalingMessage.getPayload() != null && ncSignalingMessage.getPayload().getType() != null) {
|
||||
|
@ -1446,7 +1528,7 @@ public class CallController extends BaseController {
|
|||
|
||||
String sessionDescriptionStringWithPreferredCodec = MagicWebRTCUtils.preferCodec
|
||||
(ncSignalingMessage.getPayload().getSdp(),
|
||||
"H264", false);
|
||||
"H264", false);
|
||||
|
||||
sessionDescriptionWithPreferredCodec = new SessionDescription(
|
||||
SessionDescription.Type.fromCanonicalForm(type),
|
||||
|
@ -1454,13 +1536,13 @@ public class CallController extends BaseController {
|
|||
|
||||
if (magicPeerConnectionWrapper.getPeerConnection() != null) {
|
||||
magicPeerConnectionWrapper.getPeerConnection().setRemoteDescription(magicPeerConnectionWrapper
|
||||
.getMagicSdpObserver(), sessionDescriptionWithPreferredCodec);
|
||||
.getMagicSdpObserver(), sessionDescriptionWithPreferredCodec);
|
||||
}
|
||||
break;
|
||||
case "candidate":
|
||||
NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate();
|
||||
IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(),
|
||||
ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate());
|
||||
ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate());
|
||||
magicPeerConnectionWrapper.addCandidate(iceCandidate);
|
||||
break;
|
||||
case "endOfCandidates":
|
||||
|
@ -1471,7 +1553,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Something went very very wrong");
|
||||
Log.e(TAG, "unexpected RoomType while processing NCSignalingMessage");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1658,6 +1740,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
private void getPeersForCall() {
|
||||
Log.d(TAG, "getPeersForCall");
|
||||
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new Observer<ParticipantsOverall>() {
|
||||
|
@ -1671,15 +1754,12 @@ public class CallController extends BaseController {
|
|||
participantMap = new HashMap<>();
|
||||
for (Participant participant : participantsOverall.getOcs().getData()) {
|
||||
participantMap.put(participant.getSessionId(), participant);
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> setupAvatarForSession(participant.getSessionId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
|
||||
Log.e(TAG, "error while executing getPeersForCall", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1711,18 +1791,18 @@ public class CallController extends BaseController {
|
|||
} else {
|
||||
if (hasMCU && publisher) {
|
||||
magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
|
||||
iceServers, sdpConstraintsForMCU, sessionId, callSession, localMediaStream, true, true, type);
|
||||
iceServers, sdpConstraintsForMCU, sessionId, callSession, localMediaStream, true, true, type);
|
||||
|
||||
} else if (hasMCU) {
|
||||
magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
|
||||
iceServers, sdpConstraints, sessionId, callSession, null, false, true, type);
|
||||
iceServers, sdpConstraints, sessionId, callSession, null, false, true, type);
|
||||
} else {
|
||||
if (!"screen".equals(type)) {
|
||||
magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
|
||||
iceServers, sdpConstraints, sessionId, callSession, localMediaStream, false, false, type);
|
||||
iceServers, sdpConstraints, sessionId, callSession, localMediaStream, false, false, type);
|
||||
} else {
|
||||
magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
|
||||
iceServers, sdpConstraints, sessionId, callSession, null, false, false, type);
|
||||
iceServers, sdpConstraints, sessionId, callSession, null, false, false, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1756,9 +1836,10 @@ public class CallController extends BaseController {
|
|||
magicPeerConnectionWrapper = magicPeerConnectionWrappers.get(i);
|
||||
if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
|
||||
if (magicPeerConnectionWrapper.getVideoStreamType().equals("screen") || !justScreen) {
|
||||
MagicPeerConnectionWrapper finalMagicPeerConnectionWrapper = magicPeerConnectionWrapper;
|
||||
getActivity().runOnUiThread(() -> removeMediaStream(sessionId + "+" +
|
||||
finalMagicPeerConnectionWrapper.getVideoStreamType()));
|
||||
|
||||
|
||||
// TODO runOnUiThread not necessary???
|
||||
getActivity().runOnUiThread(() -> removeMediaStream(sessionId));
|
||||
deleteMagicPeerConnection(magicPeerConnectionWrapper);
|
||||
}
|
||||
}
|
||||
|
@ -1767,15 +1848,9 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
private void removeMediaStream(String sessionId) {
|
||||
if (remoteRenderersLayout != null && remoteRenderersLayout.getChildCount() > 0) {
|
||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
|
||||
if (relativeLayout != null) {
|
||||
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
|
||||
surfaceViewRenderer.release();
|
||||
remoteRenderersLayout.removeView(relativeLayout);
|
||||
remoteRenderersLayout.invalidate();
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "removeMediaStream");
|
||||
participantDisplayItems.remove(sessionId);
|
||||
initGridAdapter();
|
||||
|
||||
if (callControls != null) {
|
||||
callControls.setZ(100.0f);
|
||||
|
@ -1785,63 +1860,76 @@ public class CallController extends BaseController {
|
|||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
|
||||
powerManagerUtils.setOrientation(Objects.requireNonNull(getResources()).getConfiguration().orientation);
|
||||
|
||||
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
remoteRenderersLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
remoteRenderersLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
}
|
||||
|
||||
setPipVideoViewDimensions();
|
||||
initGridAdapter();
|
||||
initPipView();
|
||||
}
|
||||
|
||||
private void setPipVideoViewDimensions() {
|
||||
private void initPipView() {
|
||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) pipVideoView.getLayoutParams();
|
||||
|
||||
DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
|
||||
int screenWidthPx = displayMetrics.widthPixels;
|
||||
|
||||
int screenWidthDp = (int) DisplayUtils.convertPixelToDp(screenWidthPx, getApplicationContext());
|
||||
|
||||
float newXafterRotate = 0;
|
||||
float newYafterRotate;
|
||||
if (callInfosLinearLayout.getVisibility() == View.VISIBLE) {
|
||||
newYafterRotate = 250;
|
||||
} else {
|
||||
newYafterRotate = 20;
|
||||
}
|
||||
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
remoteRenderersLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
layoutParams.height = (int) getResources().getDimension(R.dimen.large_preview_dimension);
|
||||
layoutParams.width = FrameLayout.LayoutParams.WRAP_CONTENT;
|
||||
pipVideoView.setLayoutParams(layoutParams);
|
||||
newXafterRotate = (float) (screenWidthDp - getResources().getDimension(R.dimen.large_preview_dimension) * 0.8);
|
||||
|
||||
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
remoteRenderersLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.width = (int) getResources().getDimension(R.dimen.large_preview_dimension);
|
||||
pipVideoView.setLayoutParams(layoutParams);
|
||||
newXafterRotate = (float) (screenWidthDp - getResources().getDimension(R.dimen.large_preview_dimension) * 0.5);
|
||||
}
|
||||
pipVideoView.setLayoutParams(layoutParams);
|
||||
|
||||
int newXafterRotatePx = (int) DisplayUtils.convertDpToPixel(newXafterRotate, getApplicationContext());
|
||||
selfVideoView.setY(newYafterRotate);
|
||||
selfVideoView.setX(newXafterRotatePx);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) {
|
||||
String sessionId = peerConnectionEvent.getSessionId();
|
||||
|
||||
if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType
|
||||
.PEER_CLOSED)) {
|
||||
endPeerConnection(peerConnectionEvent.getSessionId(), peerConnectionEvent.getVideoStreamType().equals("screen"));
|
||||
.PEER_CLOSED)) {
|
||||
endPeerConnection(sessionId, peerConnectionEvent.getVideoStreamType().equals("screen"));
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.SENSOR_FAR) ||
|
||||
.PeerConnectionEventType.SENSOR_FAR) ||
|
||||
peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.SENSOR_NEAR)) {
|
||||
.PeerConnectionEventType.SENSOR_NEAR)) {
|
||||
|
||||
if (!isVoiceOnlyCall) {
|
||||
boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.SENSOR_FAR) && videoOn;
|
||||
.PeerConnectionEventType.SENSOR_FAR) && videoOn;
|
||||
if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) &&
|
||||
(currentCallStatus.equals(CallStatus.CONNECTING) || isConnectionEstablished()) && videoOn
|
||||
&& enableVideo != localVideoTrack.enabled()) {
|
||||
toggleMedia(enableVideo, true);
|
||||
}
|
||||
}
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.NICK_CHANGE)) {
|
||||
gotNick(peerConnectionEvent.getSessionId(), peerConnectionEvent.getNick(), peerConnectionEvent.getVideoStreamType());
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) {
|
||||
gotAudioOrVideoChange(true, peerConnectionEvent.getSessionId() + "+" + peerConnectionEvent.getVideoStreamType(),
|
||||
peerConnectionEvent.getChangeValue());
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||
.PeerConnectionEventType.AUDIO_CHANGE)) {
|
||||
gotAudioOrVideoChange(false, peerConnectionEvent.getSessionId() + "+" + peerConnectionEvent.getVideoStreamType(),
|
||||
peerConnectionEvent.getChangeValue());
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.NICK_CHANGE)) {
|
||||
participantDisplayItems.get(sessionId).setNick(peerConnectionEvent.getNick());
|
||||
participantsAdapter.notifyDataSetChanged();
|
||||
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) {
|
||||
participantDisplayItems.get(sessionId).setStreamEnabled(peerConnectionEvent.getChangeValue());
|
||||
participantsAdapter.notifyDataSetChanged();
|
||||
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.AUDIO_CHANGE)) {
|
||||
participantDisplayItems.get(sessionId).setAudioEnabled(peerConnectionEvent.getChangeValue());
|
||||
participantsAdapter.notifyDataSetChanged();
|
||||
|
||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED)) {
|
||||
currentCallStatus = CallStatus.PUBLISHER_FAILED;
|
||||
webSocketClient.clearResumeId();
|
||||
|
@ -1894,11 +1982,20 @@ public class CallController extends BaseController {
|
|||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onMessageEvent(MediaStreamEvent mediaStreamEvent) {
|
||||
if (mediaStreamEvent.getMediaStream() != null) {
|
||||
setupVideoStreamForLayout(mediaStreamEvent.getMediaStream(), mediaStreamEvent.getSession(),
|
||||
mediaStreamEvent.getMediaStream().videoTracks != null
|
||||
&& mediaStreamEvent.getMediaStream().videoTracks.size() > 0, mediaStreamEvent.getVideoStreamType());
|
||||
boolean hasAtLeastOneVideoStream = mediaStreamEvent.getMediaStream().videoTracks != null
|
||||
&& mediaStreamEvent.getMediaStream().videoTracks.size() > 0;
|
||||
|
||||
setupVideoStreamForLayout(
|
||||
mediaStreamEvent.getMediaStream(),
|
||||
mediaStreamEvent.getSession(),
|
||||
hasAtLeastOneVideoStream,
|
||||
mediaStreamEvent.getVideoStreamType());
|
||||
} else {
|
||||
setupVideoStreamForLayout(null, mediaStreamEvent.getSession(), false, mediaStreamEvent.getVideoStreamType());
|
||||
setupVideoStreamForLayout(
|
||||
null,
|
||||
mediaStreamEvent.getSession(),
|
||||
false,
|
||||
mediaStreamEvent.getVideoStreamType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1949,7 +2046,7 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
ncApi.sendSignalingMessages(credentials, ApiUtils.getUrlForSignaling(baseUrl, urlToken),
|
||||
strings.toString())
|
||||
strings.toString())
|
||||
.retry(3)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new Observer<SignalingOverall>() {
|
||||
|
@ -1965,7 +2062,7 @@ public class CallController extends BaseController {
|
|||
try {
|
||||
receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1973,6 +2070,7 @@ public class CallController extends BaseController {
|
|||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1991,161 +2089,49 @@ public class CallController extends BaseController {
|
|||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
EffortlessPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults,
|
||||
this);
|
||||
this);
|
||||
}
|
||||
|
||||
private void setupAvatarForSession(String session) {
|
||||
if (remoteRenderersLayout != null) {
|
||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+video");
|
||||
if (relativeLayout != null) {
|
||||
SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
|
||||
|
||||
String userId;
|
||||
String displayName;
|
||||
|
||||
if (hasMCU) {
|
||||
userId = webSocketClient.getUserIdForSession(session);
|
||||
displayName = getPeerConnectionWrapperForSessionIdAndType(session, "video", false).getNick();
|
||||
} else {
|
||||
userId = participantMap.get(session).getUserId();
|
||||
displayName = getPeerConnectionWrapperForSessionIdAndType(session, "video", false).getNick();
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(userId) || !TextUtils.isEmpty(displayName)) {
|
||||
|
||||
if (getActivity() != null) {
|
||||
avatarImageView.setController(null);
|
||||
|
||||
String urlForAvatar;
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
urlForAvatar = ApiUtils.getUrlForAvatarWithName(baseUrl,
|
||||
userId,
|
||||
R.dimen.avatar_size_big);
|
||||
} else {
|
||||
urlForAvatar = ApiUtils.getUrlForAvatarWithNameForGuests(baseUrl,
|
||||
displayName,
|
||||
R.dimen.avatar_size_big);
|
||||
}
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(avatarImageView.getController())
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(urlForAvatar, null))
|
||||
.build();
|
||||
avatarImageView.setController(draweeController);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean enable, String videoStreamType) {
|
||||
boolean isInitialLayoutSetupForPeer = false;
|
||||
if (remoteRenderersLayout.findViewWithTag(session) == null) {
|
||||
setupNewPeerLayout(session, videoStreamType);
|
||||
isInitialLayoutSetupForPeer = true;
|
||||
}
|
||||
|
||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+" + videoStreamType);
|
||||
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
|
||||
SimpleDraweeView imageView = relativeLayout.findViewById(R.id.avatarImageView);
|
||||
|
||||
if (mediaStream != null && mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0 && enable) {
|
||||
VideoTrack videoTrack = mediaStream.videoTracks.get(0);
|
||||
|
||||
videoTrack.addSink(surfaceViewRenderer);
|
||||
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.VISIBLE);
|
||||
private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean videoStreamEnabled, String videoStreamType) {
|
||||
String nick;
|
||||
if (hasExternalSignalingServer) {
|
||||
nick = webSocketClient.getDisplayNameForSession(session);
|
||||
} else {
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.INVISIBLE);
|
||||
|
||||
if (isInitialLayoutSetupForPeer && isVoiceOnlyCall) {
|
||||
gotAudioOrVideoChange(true, session, false);
|
||||
}
|
||||
nick = getPeerConnectionWrapperForSessionIdAndType(session, videoStreamType, false).getNick();
|
||||
}
|
||||
|
||||
String userId;
|
||||
if (hasMCU) {
|
||||
userId = webSocketClient.getUserIdForSession(session);
|
||||
} else {
|
||||
userId = participantMap.get(session).getUserId();
|
||||
}
|
||||
|
||||
String urlForAvatar;
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
urlForAvatar = ApiUtils.getUrlForAvatarWithName(baseUrl,
|
||||
userId,
|
||||
R.dimen.avatar_size_big);
|
||||
} else {
|
||||
urlForAvatar = ApiUtils.getUrlForAvatarWithNameForGuests(baseUrl,
|
||||
nick,
|
||||
R.dimen.avatar_size_big);
|
||||
}
|
||||
|
||||
ParticipantDisplayItem participantDisplayItem = new ParticipantDisplayItem(userId,
|
||||
session,
|
||||
nick,
|
||||
urlForAvatar,
|
||||
mediaStream,
|
||||
videoStreamType,
|
||||
videoStreamEnabled,
|
||||
rootEglBase);
|
||||
participantDisplayItems.put(session, participantDisplayItem);
|
||||
|
||||
initGridAdapter();
|
||||
callControls.setZ(100.0f);
|
||||
}
|
||||
|
||||
private void gotAudioOrVideoChange(boolean video, String sessionId, boolean change) {
|
||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
|
||||
if (relativeLayout != null) {
|
||||
ImageView imageView;
|
||||
SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
|
||||
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
|
||||
|
||||
if (video) {
|
||||
imageView = relativeLayout.findViewById(R.id.remote_video_off);
|
||||
|
||||
if (change) {
|
||||
avatarImageView.setVisibility(View.INVISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
avatarImageView.setVisibility(View.VISIBLE);
|
||||
surfaceViewRenderer.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
} else {
|
||||
imageView = relativeLayout.findViewById(R.id.remote_audio_off);
|
||||
}
|
||||
|
||||
if (change && imageView.getVisibility() != View.INVISIBLE) {
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
} else if (!change && imageView.getVisibility() != View.VISIBLE) {
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupNewPeerLayout(String session, String type) {
|
||||
if (remoteRenderersLayout.findViewWithTag(session + "+" + type) == null && getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
RelativeLayout relativeLayout = (RelativeLayout)
|
||||
getActivity().getLayoutInflater().inflate(R.layout.call_item, remoteRenderersLayout,
|
||||
false);
|
||||
relativeLayout.setTag(session + "+" + type);
|
||||
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id
|
||||
.surface_view);
|
||||
|
||||
surfaceViewRenderer.setMirror(false);
|
||||
surfaceViewRenderer.init(rootEglBase.getEglBaseContext(), null);
|
||||
surfaceViewRenderer.setZOrderMediaOverlay(false);
|
||||
// disabled because it causes some devices to crash
|
||||
surfaceViewRenderer.setEnableHardwareScaler(false);
|
||||
surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
||||
surfaceViewRenderer.setOnClickListener(videoOnClickListener);
|
||||
remoteRenderersLayout.addView(relativeLayout);
|
||||
if (hasExternalSignalingServer) {
|
||||
gotNick(session, webSocketClient.getDisplayNameForSession(session), type);
|
||||
} else {
|
||||
gotNick(session, getPeerConnectionWrapperForSessionIdAndType(session, type, false).getNick(), type);
|
||||
}
|
||||
|
||||
if ("video".equals(type)) {
|
||||
setupAvatarForSession(session);
|
||||
}
|
||||
|
||||
callControls.setZ(100.0f);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void gotNick(String sessionId, String nick, String type) {
|
||||
String remoteRendererTag = sessionId + "+" + type;
|
||||
|
||||
if (controllerCallLayout != null) {
|
||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(remoteRendererTag);
|
||||
TextView textView = relativeLayout.findViewById(R.id.peer_nick_text_view);
|
||||
if (!textView.getText().equals(nick)) {
|
||||
textView.setText(nick);
|
||||
|
||||
if (getActivity() != null && type.equals("video")) {
|
||||
getActivity().runOnUiThread(() -> setupAvatarForSession(sessionId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.callStateRelativeLayoutView)
|
||||
public void onConnectingViewClick() {
|
||||
if (currentCallStatus.equals(CallStatus.CALLING_TIMEOUT)) {
|
||||
|
@ -2180,8 +2166,8 @@ public class CallController extends BaseController {
|
|||
callStateView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (progressBar.getVisibility() != View.VISIBLE) {
|
||||
|
@ -2206,8 +2192,8 @@ public class CallController extends BaseController {
|
|||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp);
|
||||
|
@ -2225,8 +2211,8 @@ public class CallController extends BaseController {
|
|||
if (callStateView.getVisibility() != View.VISIBLE) {
|
||||
callStateView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
if (progressBar.getVisibility() != View.VISIBLE) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
@ -2258,9 +2244,9 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
if (remoteRenderersLayout != null) {
|
||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
if (gridView != null) {
|
||||
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2296,9 +2282,9 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
if (remoteRenderersLayout != null) {
|
||||
if (remoteRenderersLayout.getVisibility() != View.VISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.VISIBLE);
|
||||
if (gridView != null) {
|
||||
if (gridView.getVisibility() != View.VISIBLE) {
|
||||
gridView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2322,9 +2308,9 @@ public class CallController extends BaseController {
|
|||
}
|
||||
|
||||
|
||||
if (remoteRenderersLayout != null) {
|
||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
if (gridView != null) {
|
||||
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2349,7 +2335,7 @@ public class CallController extends BaseController {
|
|||
callVoiceOrVideoTextView.setText(getDescriptionForCallType());
|
||||
callStateTextView.setText(R.string.nc_leaving_call);
|
||||
callStateView.setVisibility(View.VISIBLE);
|
||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
||||
gridView.setVisibility(View.INVISIBLE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
errorImageView.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -2362,7 +2348,7 @@ public class CallController extends BaseController {
|
|||
|
||||
private String getDescriptionForCallType() {
|
||||
String appName = getResources().getString(R.string.nc_app_name);
|
||||
if (isVoiceOnlyCall){
|
||||
if (isVoiceOnlyCall) {
|
||||
return String.format(getResources().getString(R.string.nc_call_voice), appName);
|
||||
} else {
|
||||
return String.format(getResources().getString(R.string.nc_call_video), appName);
|
||||
|
@ -2374,18 +2360,20 @@ public class CallController extends BaseController {
|
|||
Uri ringtoneUri;
|
||||
if (isIncomingCallFromNotification) {
|
||||
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
|
||||
"/raw/librem_by_feandesign_call");
|
||||
"/raw/librem_by_feandesign_call");
|
||||
} else {
|
||||
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/raw" +
|
||||
"/tr110_1_kap8_3_freiton1");
|
||||
"/tr110_1_kap8_3_freiton1");
|
||||
}
|
||||
if (getActivity() != null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(Objects.requireNonNull(getActivity()), ringtoneUri);
|
||||
mediaPlayer.setLooping(true);
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
|
||||
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(
|
||||
AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||
.build();
|
||||
mediaPlayer.setAudioAttributes(audioAttributes);
|
||||
|
||||
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
|
||||
|
@ -2438,35 +2426,37 @@ public class CallController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
private class VideoClickListener implements View.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showCallControls();
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(NetworkEvent networkEvent) {
|
||||
if (networkEvent.getNetworkConnectionEvent()
|
||||
.equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)) {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
} else if (networkEvent.getNetworkConnectionEvent()
|
||||
.equals(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)) {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(NetworkEvent networkEvent) {
|
||||
if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)) {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
private class SelfVideoTouchListener implements View.OnTouchListener {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
long duration = event.getEventTime() - event.getDownTime();
|
||||
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
||||
float newY = event.getRawY() - selfVideoView.getHeight() / (float) 2;
|
||||
float newX = event.getRawX() - selfVideoView.getWidth() / (float) 2;
|
||||
selfVideoView.setY(newY);
|
||||
selfVideoView.setX(newX);
|
||||
} else if (event.getActionMasked() == MotionEvent.ACTION_UP && duration < 100) {
|
||||
switchCamera();
|
||||
}
|
||||
|
||||
/*if (!hasMCU) {
|
||||
setCallState(CallStatus.RECONNECTING);
|
||||
hangupNetworkCalls(false);
|
||||
}*/
|
||||
|
||||
} else if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)) {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
/* if (!hasMCU) {
|
||||
setCallState(CallStatus.OFFLINE);
|
||||
hangup(false);
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,9 +52,7 @@ import android.util.TypedValue;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
@ -63,15 +61,12 @@ import androidx.annotation.DrawableRes;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.XmlRes;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.AppCompatDrawableManager;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
|
@ -95,7 +90,6 @@ import com.nextcloud.talk.R;
|
|||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.events.UserMentionClickEvent;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||
import com.nextcloud.talk.utils.text.Spans;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
@ -108,17 +102,6 @@ import java.util.Map;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.XmlRes;
|
||||
import androidx.appcompat.widget.AppCompatDrawableManager;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
|
||||
public class DisplayUtils {
|
||||
|
||||
private static final String TAG = "DisplayUtils";
|
||||
|
@ -239,6 +222,10 @@ public class DisplayUtils {
|
|||
context.getResources().getDisplayMetrics()) + 0.5f);
|
||||
}
|
||||
|
||||
public static float convertPixelToDp(float px, Context context) {
|
||||
return px / context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
// Solution inspired by https://stackoverflow.com/questions/34936590/why-isnt-my-vector-drawable-scaling-as-expected
|
||||
public static void useCompatVectorIfNeeded() {
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
|
|
|
@ -50,6 +50,7 @@ import java.util.List;
|
|||
@AutoInjector(NextcloudTalkApplication.class)
|
||||
public class MagicPeerConnectionWrapper {
|
||||
private static String TAG = "MagicPeerConnectionWrapper";
|
||||
|
||||
private List<IceCandidate> iceCandidates = new ArrayList<>();
|
||||
private PeerConnection peerConnection;
|
||||
private String sessionId;
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
~ Nextcloud Talk application
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Marcel Hibbe
|
||||
~ @author Andy Scherzinger
|
||||
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
|
@ -25,43 +27,8 @@
|
|||
android:id="@+id/relative_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/peer_nick_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:layout_centerHorizontal="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/remote_audio_off"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_below="@id/peer_nick_text_view"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@string/nc_remote_audio_off"
|
||||
android:src="@drawable/ic_mic_off_white_24px"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/remote_video_off"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_below="@id/peer_nick_text_view"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_toEndOf="@id/remote_audio_off"
|
||||
android:contentDescription="@string/nc_remote_video_off"
|
||||
android:src="@drawable/ic_videocam_off_white_24px"
|
||||
android:visibility="invisible" />
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/avatarImageView"
|
||||
|
@ -76,4 +43,25 @@
|
|||
android:layout_height="match_parent"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/peer_nick_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/remote_audio_off"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toEndOf="@id/peer_nick_text_view"
|
||||
android:src="@drawable/ic_mic_off_white_24px"
|
||||
android:contentDescription="@string/nc_remote_audio_off"
|
||||
android:visibility="invisible" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -45,13 +45,39 @@
|
|||
android:layout_weight="1"
|
||||
tools:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/remote_renderers_layout"
|
||||
<GridView
|
||||
android:id="@+id/gridview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
||||
android:gravity="center"
|
||||
android:stretchMode="columnWidth"
|
||||
android:numColumns="2"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/selfVideoView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/pip_video_view"
|
||||
android:layout_width="@dimen/large_preview_dimension"
|
||||
android:layout_height="150dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="16dp"
|
||||
android:visibility="invisible"
|
||||
android:clickable="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/call_control_switch_camera"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:placeholderImage="@drawable/ic_switch_video_white_24px"
|
||||
app:roundAsCircle="true" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/callInfosLinearLayout"
|
||||
|
@ -83,35 +109,11 @@
|
|||
android:ellipsize="marquee"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="28sp"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Marsellus Wallace" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_below="@id/callInfosLinearLayout">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/pip_video_view"
|
||||
android:layout_width="@dimen/large_preview_dimension"
|
||||
android:layout_height="150dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="16dp"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/call_control_switch_camera"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:placeholderImage="@drawable/ic_switch_video_white_24px"
|
||||
app:roundAsCircle="true" />
|
||||
</FrameLayout>
|
||||
|
||||
<View android:id="@+id/verticalCenter"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
|
@ -137,7 +139,7 @@
|
|||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:layout_alignBottom="@id/linearWrapperLayout"
|
||||
android:layout_marginBottom="10dp">
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/callControlToggleChat"
|
||||
|
|
|
@ -101,7 +101,8 @@
|
|||
android:ellipsize="marquee"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="28sp"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Victor Gregorius Magnus" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -285,7 +285,6 @@
|
|||
<string name="nc_formatted_message_you">You: %1$s</string>
|
||||
<string name="nc_message_read">Message read</string>
|
||||
<string name="nc_message_sent">Message sent</string>
|
||||
<string name="nc_remote_video_off">Remote video off</string>
|
||||
<string name="nc_remote_audio_off">Remote audio off</string>
|
||||
<string name="nc_add_attachment">Add attachment</string>
|
||||
|
||||
|
|
Loading…
Reference in a new issue