mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-25 06:25:40 +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)
|
- 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
|
- other data types are opened with external apps if they are able to handle it
|
||||||
- edit profile information and privacy settings
|
- edit profile information and privacy settings
|
||||||
|
- add grid view for calls, make own video movable
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- improve conversation list design and dark/light theming (@AndyScherzinger)
|
- 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.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.GridView;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
@ -51,11 +54,11 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.bluelinelabs.logansquare.LoganSquare;
|
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.facebook.drawee.view.SimpleDraweeView;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.activities.MagicCallActivity;
|
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.api.NcApi;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.base.BaseController;
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
|
@ -143,6 +146,7 @@ import javax.inject.Inject;
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.OnClick;
|
import butterknife.OnClick;
|
||||||
|
import butterknife.OnItemClick;
|
||||||
import butterknife.OnLongClick;
|
import butterknife.OnLongClick;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Observer;
|
import io.reactivex.Observer;
|
||||||
|
@ -180,8 +184,8 @@ public class CallController extends BaseController {
|
||||||
SurfaceViewRenderer pipVideoView;
|
SurfaceViewRenderer pipVideoView;
|
||||||
@BindView(R.id.controllerCallLayout)
|
@BindView(R.id.controllerCallLayout)
|
||||||
RelativeLayout controllerCallLayout;
|
RelativeLayout controllerCallLayout;
|
||||||
@BindView(R.id.remote_renderers_layout)
|
@BindView(R.id.gridview)
|
||||||
LinearLayout remoteRenderersLayout;
|
GridView gridView;
|
||||||
|
|
||||||
@BindView(R.id.callControlsLinearLayout)
|
@BindView(R.id.callControlsLinearLayout)
|
||||||
LinearLayout callControls;
|
LinearLayout callControls;
|
||||||
|
@ -201,6 +205,9 @@ public class CallController extends BaseController {
|
||||||
@BindView(R.id.callConversationNameTextView)
|
@BindView(R.id.callConversationNameTextView)
|
||||||
TextView callConversationNameTextView;
|
TextView callConversationNameTextView;
|
||||||
|
|
||||||
|
@BindView(R.id.selfVideoView)
|
||||||
|
FrameLayout selfVideoView;
|
||||||
|
|
||||||
@BindView(R.id.callStateRelativeLayoutView)
|
@BindView(R.id.callStateRelativeLayoutView)
|
||||||
RelativeLayout callStateView;
|
RelativeLayout callStateView;
|
||||||
|
|
||||||
|
@ -264,7 +271,6 @@ public class CallController extends BaseController {
|
||||||
// push to talk
|
// push to talk
|
||||||
private boolean isPTTActive = false;
|
private boolean isPTTActive = false;
|
||||||
private PulseAnimation pulseAnimation;
|
private PulseAnimation pulseAnimation;
|
||||||
private View.OnClickListener videoOnClickListener;
|
|
||||||
|
|
||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
private String roomId;
|
private String roomId;
|
||||||
|
@ -286,6 +292,9 @@ public class CallController extends BaseController {
|
||||||
|
|
||||||
private MediaPlayer mediaPlayer;
|
private MediaPlayer mediaPlayer;
|
||||||
|
|
||||||
|
private Map<String, ParticipantDisplayItem> participantDisplayItems;
|
||||||
|
private ParticipantsAdapter participantsAdapter;
|
||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
public enum CallStatus {
|
public enum CallStatus {
|
||||||
CONNECTING, CALLING_TIMEOUT, JOINED, IN_CONVERSATION, RECONNECTING, OFFLINE, LEAVING, PUBLISHER_FAILED
|
CONNECTING, CALLING_TIMEOUT, JOINED, IN_CONVERSATION, RECONNECTING, OFFLINE, LEAVING, PUBLISHER_FAILED
|
||||||
|
@ -345,19 +354,18 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@Override
|
@Override
|
||||||
protected void onViewBound(@NonNull View view) {
|
protected void onViewBound(@NonNull View view) {
|
||||||
super.onViewBound(view);
|
super.onViewBound(view);
|
||||||
|
|
||||||
microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener());
|
microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener());
|
||||||
videoOnClickListener = new VideoClickListener();
|
|
||||||
|
|
||||||
pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
|
pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
|
||||||
.setDuration(310)
|
.setDuration(310)
|
||||||
.setRepeatCount(PulseAnimation.INFINITE)
|
.setRepeatCount(PulseAnimation.INFINITE)
|
||||||
.setRepeatMode(PulseAnimation.REVERSE);
|
.setRepeatMode(PulseAnimation.REVERSE);
|
||||||
|
|
||||||
setPipVideoViewDimensions();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cache.evictAll();
|
cache.evictAll();
|
||||||
|
@ -368,7 +376,7 @@ public class CallController extends BaseController {
|
||||||
callControls.setZ(100.0f);
|
callControls.setZ(100.0f);
|
||||||
basicInitialization();
|
basicInitialization();
|
||||||
initViews();
|
initViews();
|
||||||
|
initPipView();
|
||||||
initiateCall();
|
initiateCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +475,11 @@ public class CallController extends BaseController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private void initViews() {
|
private void initViews() {
|
||||||
|
participantDisplayItems = new HashMap<>();
|
||||||
|
|
||||||
if (isVoiceOnlyCall) {
|
if (isVoiceOnlyCall) {
|
||||||
callControlEnableSpeaker.setVisibility(View.VISIBLE);
|
callControlEnableSpeaker.setVisibility(View.VISIBLE);
|
||||||
cameraSwitchButton.setVisibility(View.GONE);
|
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);
|
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
params.addRule(RelativeLayout.BELOW, R.id.callInfosLinearLayout);
|
params.addRule(RelativeLayout.BELOW, R.id.callInfosLinearLayout);
|
||||||
remoteRenderersLayout.setLayoutParams(params);
|
gridView.setLayoutParams(params);
|
||||||
} else {
|
} else {
|
||||||
callControlEnableSpeaker.setVisibility(View.GONE);
|
callControlEnableSpeaker.setVisibility(View.GONE);
|
||||||
if (cameraEnumerator.getDeviceNames().length < 2) {
|
if (cameraEnumerator.getDeviceNames().length < 2) {
|
||||||
|
@ -488,7 +500,77 @@ public class CallController extends BaseController {
|
||||||
// disabled because it causes some devices to crash
|
// disabled because it causes some devices to crash
|
||||||
pipVideoView.setEnableHardwareScaler(false);
|
pipVideoView.setEnableHardwareScaler(false);
|
||||||
pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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() {
|
public void switchCamera() {
|
||||||
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
|
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
|
||||||
if (cameraVideoCapturer != null) {
|
if (cameraVideoCapturer != null) {
|
||||||
|
@ -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() {
|
public void showCallControls() {
|
||||||
animateCallControls(true, 0);
|
animateCallControls(true, 0);
|
||||||
}
|
}
|
||||||
|
@ -1417,7 +1499,7 @@ public class CallController extends BaseController {
|
||||||
NCSignalingMessage.class);
|
NCSignalingMessage.class);
|
||||||
processMessage(ncSignalingMessage);
|
processMessage(ncSignalingMessage);
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Something went very very wrong");
|
Log.e(TAG, "unexpected message type when receiving signaling message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1471,7 +1553,7 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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() {
|
private void getPeersForCall() {
|
||||||
|
Log.d(TAG, "getPeersForCall");
|
||||||
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken))
|
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe(new Observer<ParticipantsOverall>() {
|
.subscribe(new Observer<ParticipantsOverall>() {
|
||||||
|
@ -1671,15 +1754,12 @@ public class CallController extends BaseController {
|
||||||
participantMap = new HashMap<>();
|
participantMap = new HashMap<>();
|
||||||
for (Participant participant : participantsOverall.getOcs().getData()) {
|
for (Participant participant : participantsOverall.getOcs().getData()) {
|
||||||
participantMap.put(participant.getSessionId(), participant);
|
participantMap.put(participant.getSessionId(), participant);
|
||||||
if (getActivity() != null) {
|
|
||||||
getActivity().runOnUiThread(() -> setupAvatarForSession(participant.getSessionId()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable e) {
|
public void onError(Throwable e) {
|
||||||
|
Log.e(TAG, "error while executing getPeersForCall", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1756,9 +1836,10 @@ public class CallController extends BaseController {
|
||||||
magicPeerConnectionWrapper = magicPeerConnectionWrappers.get(i);
|
magicPeerConnectionWrapper = magicPeerConnectionWrappers.get(i);
|
||||||
if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
|
if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
|
||||||
if (magicPeerConnectionWrapper.getVideoStreamType().equals("screen") || !justScreen) {
|
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);
|
deleteMagicPeerConnection(magicPeerConnectionWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1767,15 +1848,9 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeMediaStream(String sessionId) {
|
private void removeMediaStream(String sessionId) {
|
||||||
if (remoteRenderersLayout != null && remoteRenderersLayout.getChildCount() > 0) {
|
Log.d(TAG, "removeMediaStream");
|
||||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
|
participantDisplayItems.remove(sessionId);
|
||||||
if (relativeLayout != null) {
|
initGridAdapter();
|
||||||
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
|
|
||||||
surfaceViewRenderer.release();
|
|
||||||
remoteRenderersLayout.removeView(relativeLayout);
|
|
||||||
remoteRenderersLayout.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callControls != null) {
|
if (callControls != null) {
|
||||||
callControls.setZ(100.0f);
|
callControls.setZ(100.0f);
|
||||||
|
@ -1785,38 +1860,50 @@ public class CallController extends BaseController {
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
|
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
|
||||||
powerManagerUtils.setOrientation(Objects.requireNonNull(getResources()).getConfiguration().orientation);
|
powerManagerUtils.setOrientation(Objects.requireNonNull(getResources()).getConfiguration().orientation);
|
||||||
|
initGridAdapter();
|
||||||
|
initPipView();
|
||||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
||||||
remoteRenderersLayout.setOrientation(LinearLayout.HORIZONTAL);
|
|
||||||
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
||||||
remoteRenderersLayout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPipVideoViewDimensions();
|
private void initPipView() {
|
||||||
}
|
|
||||||
|
|
||||||
private void setPipVideoViewDimensions() {
|
|
||||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) pipVideoView.getLayoutParams();
|
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) {
|
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
remoteRenderersLayout.setOrientation(LinearLayout.HORIZONTAL);
|
|
||||||
layoutParams.height = (int) getResources().getDimension(R.dimen.large_preview_dimension);
|
layoutParams.height = (int) getResources().getDimension(R.dimen.large_preview_dimension);
|
||||||
layoutParams.width = FrameLayout.LayoutParams.WRAP_CONTENT;
|
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) {
|
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
remoteRenderersLayout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT;
|
layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT;
|
||||||
layoutParams.width = (int) getResources().getDimension(R.dimen.large_preview_dimension);
|
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)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) {
|
public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) {
|
||||||
|
String sessionId = peerConnectionEvent.getSessionId();
|
||||||
|
|
||||||
if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType
|
if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType
|
||||||
.PEER_CLOSED)) {
|
.PEER_CLOSED)) {
|
||||||
endPeerConnection(peerConnectionEvent.getSessionId(), peerConnectionEvent.getVideoStreamType().equals("screen"));
|
endPeerConnection(sessionId, peerConnectionEvent.getVideoStreamType().equals("screen"));
|
||||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||||
.PeerConnectionEventType.SENSOR_FAR) ||
|
.PeerConnectionEventType.SENSOR_FAR) ||
|
||||||
peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
||||||
|
@ -1831,17 +1918,18 @@ public class CallController extends BaseController {
|
||||||
toggleMedia(enableVideo, true);
|
toggleMedia(enableVideo, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.NICK_CHANGE)) {
|
||||||
.PeerConnectionEventType.NICK_CHANGE)) {
|
participantDisplayItems.get(sessionId).setNick(peerConnectionEvent.getNick());
|
||||||
gotNick(peerConnectionEvent.getSessionId(), peerConnectionEvent.getNick(), peerConnectionEvent.getVideoStreamType());
|
participantsAdapter.notifyDataSetChanged();
|
||||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
|
||||||
.PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) {
|
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) {
|
||||||
gotAudioOrVideoChange(true, peerConnectionEvent.getSessionId() + "+" + peerConnectionEvent.getVideoStreamType(),
|
participantDisplayItems.get(sessionId).setStreamEnabled(peerConnectionEvent.getChangeValue());
|
||||||
peerConnectionEvent.getChangeValue());
|
participantsAdapter.notifyDataSetChanged();
|
||||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
|
|
||||||
.PeerConnectionEventType.AUDIO_CHANGE)) {
|
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.AUDIO_CHANGE)) {
|
||||||
gotAudioOrVideoChange(false, peerConnectionEvent.getSessionId() + "+" + peerConnectionEvent.getVideoStreamType(),
|
participantDisplayItems.get(sessionId).setAudioEnabled(peerConnectionEvent.getChangeValue());
|
||||||
peerConnectionEvent.getChangeValue());
|
participantsAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED)) {
|
} else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED)) {
|
||||||
currentCallStatus = CallStatus.PUBLISHER_FAILED;
|
currentCallStatus = CallStatus.PUBLISHER_FAILED;
|
||||||
webSocketClient.clearResumeId();
|
webSocketClient.clearResumeId();
|
||||||
|
@ -1894,11 +1982,20 @@ public class CallController extends BaseController {
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
public void onMessageEvent(MediaStreamEvent mediaStreamEvent) {
|
public void onMessageEvent(MediaStreamEvent mediaStreamEvent) {
|
||||||
if (mediaStreamEvent.getMediaStream() != null) {
|
if (mediaStreamEvent.getMediaStream() != null) {
|
||||||
setupVideoStreamForLayout(mediaStreamEvent.getMediaStream(), mediaStreamEvent.getSession(),
|
boolean hasAtLeastOneVideoStream = mediaStreamEvent.getMediaStream().videoTracks != null
|
||||||
mediaStreamEvent.getMediaStream().videoTracks != null
|
&& mediaStreamEvent.getMediaStream().videoTracks.size() > 0;
|
||||||
&& mediaStreamEvent.getMediaStream().videoTracks.size() > 0, mediaStreamEvent.getVideoStreamType());
|
|
||||||
|
setupVideoStreamForLayout(
|
||||||
|
mediaStreamEvent.getMediaStream(),
|
||||||
|
mediaStreamEvent.getSession(),
|
||||||
|
hasAtLeastOneVideoStream,
|
||||||
|
mediaStreamEvent.getVideoStreamType());
|
||||||
} else {
|
} else {
|
||||||
setupVideoStreamForLayout(null, mediaStreamEvent.getSession(), false, mediaStreamEvent.getVideoStreamType());
|
setupVideoStreamForLayout(
|
||||||
|
null,
|
||||||
|
mediaStreamEvent.getSession(),
|
||||||
|
false,
|
||||||
|
mediaStreamEvent.getVideoStreamType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1965,7 +2062,7 @@ public class CallController extends BaseController {
|
||||||
try {
|
try {
|
||||||
receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
|
receivedSignalingMessage(signalingOverall.getOcs().getSignalings().get(i));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
Log.e(TAG, "", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1973,6 +2070,7 @@ public class CallController extends BaseController {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable e) {
|
public void onError(Throwable e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1994,27 +2092,20 @@ public class CallController extends BaseController {
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupAvatarForSession(String session) {
|
private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean videoStreamEnabled, String videoStreamType) {
|
||||||
if (remoteRenderersLayout != null) {
|
String nick;
|
||||||
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+video");
|
if (hasExternalSignalingServer) {
|
||||||
if (relativeLayout != null) {
|
nick = webSocketClient.getDisplayNameForSession(session);
|
||||||
SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
|
|
||||||
|
|
||||||
String userId;
|
|
||||||
String displayName;
|
|
||||||
|
|
||||||
if (hasMCU) {
|
|
||||||
userId = webSocketClient.getUserIdForSession(session);
|
|
||||||
displayName = getPeerConnectionWrapperForSessionIdAndType(session, "video", false).getNick();
|
|
||||||
} else {
|
} else {
|
||||||
userId = participantMap.get(session).getUserId();
|
nick = getPeerConnectionWrapperForSessionIdAndType(session, videoStreamType, false).getNick();
|
||||||
displayName = getPeerConnectionWrapperForSessionIdAndType(session, "video", false).getNick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(userId) || !TextUtils.isEmpty(displayName)) {
|
String userId;
|
||||||
|
if (hasMCU) {
|
||||||
if (getActivity() != null) {
|
userId = webSocketClient.getUserIdForSession(session);
|
||||||
avatarImageView.setController(null);
|
} else {
|
||||||
|
userId = participantMap.get(session).getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
String urlForAvatar;
|
String urlForAvatar;
|
||||||
if (!TextUtils.isEmpty(userId)) {
|
if (!TextUtils.isEmpty(userId)) {
|
||||||
|
@ -2023,129 +2114,24 @@ public class CallController extends BaseController {
|
||||||
R.dimen.avatar_size_big);
|
R.dimen.avatar_size_big);
|
||||||
} else {
|
} else {
|
||||||
urlForAvatar = ApiUtils.getUrlForAvatarWithNameForGuests(baseUrl,
|
urlForAvatar = ApiUtils.getUrlForAvatarWithNameForGuests(baseUrl,
|
||||||
displayName,
|
nick,
|
||||||
R.dimen.avatar_size_big);
|
R.dimen.avatar_size_big);
|
||||||
}
|
}
|
||||||
|
|
||||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
ParticipantDisplayItem participantDisplayItem = new ParticipantDisplayItem(userId,
|
||||||
.setOldController(avatarImageView.getController())
|
session,
|
||||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(urlForAvatar, null))
|
nick,
|
||||||
.build();
|
urlForAvatar,
|
||||||
avatarImageView.setController(draweeController);
|
mediaStream,
|
||||||
}
|
videoStreamType,
|
||||||
}
|
videoStreamEnabled,
|
||||||
}
|
rootEglBase);
|
||||||
}
|
participantDisplayItems.put(session, participantDisplayItem);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
imageView.setVisibility(View.VISIBLE);
|
|
||||||
surfaceViewRenderer.setVisibility(View.INVISIBLE);
|
|
||||||
|
|
||||||
if (isInitialLayoutSetupForPeer && isVoiceOnlyCall) {
|
|
||||||
gotAudioOrVideoChange(true, session, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
initGridAdapter();
|
||||||
callControls.setZ(100.0f);
|
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)
|
@OnClick(R.id.callStateRelativeLayoutView)
|
||||||
public void onConnectingViewClick() {
|
public void onConnectingViewClick() {
|
||||||
if (currentCallStatus.equals(CallStatus.CALLING_TIMEOUT)) {
|
if (currentCallStatus.equals(CallStatus.CALLING_TIMEOUT)) {
|
||||||
|
@ -2180,8 +2166,8 @@ public class CallController extends BaseController {
|
||||||
callStateView.setVisibility(View.VISIBLE);
|
callStateView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progressBar.getVisibility() != View.VISIBLE) {
|
if (progressBar.getVisibility() != View.VISIBLE) {
|
||||||
|
@ -2206,8 +2192,8 @@ public class CallController extends BaseController {
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp);
|
errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp);
|
||||||
|
@ -2225,8 +2211,8 @@ public class CallController extends BaseController {
|
||||||
if (callStateView.getVisibility() != View.VISIBLE) {
|
if (callStateView.getVisibility() != View.VISIBLE) {
|
||||||
callStateView.setVisibility(View.VISIBLE);
|
callStateView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
if (progressBar.getVisibility() != View.VISIBLE) {
|
if (progressBar.getVisibility() != View.VISIBLE) {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
|
@ -2258,9 +2244,9 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteRenderersLayout != null) {
|
if (gridView != null) {
|
||||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2296,9 +2282,9 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteRenderersLayout != null) {
|
if (gridView != null) {
|
||||||
if (remoteRenderersLayout.getVisibility() != View.VISIBLE) {
|
if (gridView.getVisibility() != View.VISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.VISIBLE);
|
gridView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2322,9 +2308,9 @@ public class CallController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (remoteRenderersLayout != null) {
|
if (gridView != null) {
|
||||||
if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
|
if (gridView.getVisibility() != View.INVISIBLE) {
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2349,7 +2335,7 @@ public class CallController extends BaseController {
|
||||||
callVoiceOrVideoTextView.setText(getDescriptionForCallType());
|
callVoiceOrVideoTextView.setText(getDescriptionForCallType());
|
||||||
callStateTextView.setText(R.string.nc_leaving_call);
|
callStateTextView.setText(R.string.nc_leaving_call);
|
||||||
callStateView.setVisibility(View.VISIBLE);
|
callStateView.setVisibility(View.VISIBLE);
|
||||||
remoteRenderersLayout.setVisibility(View.INVISIBLE);
|
gridView.setVisibility(View.INVISIBLE);
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
errorImageView.setVisibility(View.GONE);
|
errorImageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -2384,8 +2370,10 @@ public class CallController extends BaseController {
|
||||||
try {
|
try {
|
||||||
mediaPlayer.setDataSource(Objects.requireNonNull(getActivity()), ringtoneUri);
|
mediaPlayer.setDataSource(Objects.requireNonNull(getActivity()), ringtoneUri);
|
||||||
mediaPlayer.setLooping(true);
|
mediaPlayer.setLooping(true);
|
||||||
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
|
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(
|
||||||
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
|
AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||||
|
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||||
|
.build();
|
||||||
mediaPlayer.setAudioAttributes(audioAttributes);
|
mediaPlayer.setAudioAttributes(audioAttributes);
|
||||||
|
|
||||||
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
|
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)
|
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||||
public void onMessageEvent(NetworkEvent networkEvent) {
|
public void onMessageEvent(NetworkEvent networkEvent) {
|
||||||
if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)) {
|
if (networkEvent.getNetworkConnectionEvent()
|
||||||
|
.equals(NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED)) {
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
handler.removeCallbacksAndMessages(null);
|
handler.removeCallbacksAndMessages(null);
|
||||||
}
|
}
|
||||||
|
} else if (networkEvent.getNetworkConnectionEvent()
|
||||||
/*if (!hasMCU) {
|
.equals(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)) {
|
||||||
setCallState(CallStatus.RECONNECTING);
|
|
||||||
hangupNetworkCalls(false);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} else if (networkEvent.getNetworkConnectionEvent().equals(NetworkEvent.NetworkConnectionEvent.NETWORK_DISCONNECTED)) {
|
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
handler.removeCallbacksAndMessages(null);
|
handler.removeCallbacksAndMessages(null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* if (!hasMCU) {
|
private class SelfVideoTouchListener implements View.OnTouchListener {
|
||||||
setCallState(CallStatus.OFFLINE);
|
|
||||||
hangup(false);
|
@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();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,7 @@ import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
|
@ -63,15 +61,12 @@ import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.XmlRes;
|
import androidx.annotation.XmlRes;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
|
||||||
import androidx.appcompat.widget.AppCompatDrawableManager;
|
import androidx.appcompat.widget.AppCompatDrawableManager;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.content.res.ResourcesCompat;
|
|
||||||
import androidx.core.graphics.ColorUtils;
|
import androidx.core.graphics.ColorUtils;
|
||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
import androidx.emoji.text.EmojiCompat;
|
import androidx.emoji.text.EmojiCompat;
|
||||||
import androidx.viewpager.widget.ViewPager;
|
|
||||||
|
|
||||||
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
||||||
import com.facebook.common.references.CloseableReference;
|
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.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.events.UserMentionClickEvent;
|
import com.nextcloud.talk.events.UserMentionClickEvent;
|
||||||
import com.nextcloud.talk.models.database.UserEntity;
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
|
||||||
import com.nextcloud.talk.utils.text.Spans;
|
import com.nextcloud.talk.utils.text.Spans;
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
@ -108,17 +102,6 @@ import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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 {
|
public class DisplayUtils {
|
||||||
|
|
||||||
private static final String TAG = "DisplayUtils";
|
private static final String TAG = "DisplayUtils";
|
||||||
|
@ -239,6 +222,10 @@ public class DisplayUtils {
|
||||||
context.getResources().getDisplayMetrics()) + 0.5f);
|
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
|
// Solution inspired by https://stackoverflow.com/questions/34936590/why-isnt-my-vector-drawable-scaling-as-expected
|
||||||
public static void useCompatVectorIfNeeded() {
|
public static void useCompatVectorIfNeeded() {
|
||||||
if (Build.VERSION.SDK_INT < 23) {
|
if (Build.VERSION.SDK_INT < 23) {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import java.util.List;
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class MagicPeerConnectionWrapper {
|
public class MagicPeerConnectionWrapper {
|
||||||
private static String TAG = "MagicPeerConnectionWrapper";
|
private static String TAG = "MagicPeerConnectionWrapper";
|
||||||
|
|
||||||
private List<IceCandidate> iceCandidates = new ArrayList<>();
|
private List<IceCandidate> iceCandidates = new ArrayList<>();
|
||||||
private PeerConnection peerConnection;
|
private PeerConnection peerConnection;
|
||||||
private String sessionId;
|
private String sessionId;
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
~ Nextcloud Talk application
|
~ Nextcloud Talk application
|
||||||
~
|
~
|
||||||
~ @author Mario Danic
|
~ @author Mario Danic
|
||||||
|
~ @author Marcel Hibbe
|
||||||
~ @author Andy Scherzinger
|
~ @author Andy Scherzinger
|
||||||
|
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||||
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||||
~
|
~
|
||||||
|
@ -25,43 +27,8 @@
|
||||||
android:id="@+id/relative_layout"
|
android:id="@+id/relative_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:orientation="vertical"
|
||||||
android:orientation="vertical">
|
android:gravity="center">
|
||||||
|
|
||||||
<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" />
|
|
||||||
|
|
||||||
<com.facebook.drawee.view.SimpleDraweeView
|
<com.facebook.drawee.view.SimpleDraweeView
|
||||||
android:id="@+id/avatarImageView"
|
android:id="@+id/avatarImageView"
|
||||||
|
@ -76,4 +43,25 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="invisible" />
|
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>
|
</RelativeLayout>
|
||||||
|
|
|
@ -45,13 +45,39 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<LinearLayout
|
<GridView
|
||||||
android:id="@+id/remote_renderers_layout"
|
android:id="@+id/gridview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:animateLayoutChanges="true"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:stretchMode="columnWidth"
|
||||||
</LinearLayout>
|
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
|
<LinearLayout
|
||||||
android:id="@+id/callInfosLinearLayout"
|
android:id="@+id/callInfosLinearLayout"
|
||||||
|
@ -83,35 +109,11 @@
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="28sp"
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
tools:text="Marsellus Wallace" />
|
tools:text="Marsellus Wallace" />
|
||||||
</LinearLayout>
|
</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"
|
<View android:id="@+id/verticalCenter"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
@ -137,7 +139,7 @@
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:layout_alignBottom="@id/linearWrapperLayout"
|
android:layout_alignBottom="@id/linearWrapperLayout"
|
||||||
android:layout_marginBottom="10dp">
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
<com.facebook.drawee.view.SimpleDraweeView
|
<com.facebook.drawee.view.SimpleDraweeView
|
||||||
android:id="@+id/callControlToggleChat"
|
android:id="@+id/callControlToggleChat"
|
||||||
|
|
|
@ -101,7 +101,8 @@
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="28sp"
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
tools:text="Victor Gregorius Magnus" />
|
tools:text="Victor Gregorius Magnus" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -285,7 +285,6 @@
|
||||||
<string name="nc_formatted_message_you">You: %1$s</string>
|
<string name="nc_formatted_message_you">You: %1$s</string>
|
||||||
<string name="nc_message_read">Message read</string>
|
<string name="nc_message_read">Message read</string>
|
||||||
<string name="nc_message_sent">Message sent</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_remote_audio_off">Remote audio off</string>
|
||||||
<string name="nc_add_attachment">Add attachment</string>
|
<string name="nc_add_attachment">Add attachment</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue