improve call screens, add outgoing ringtone

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2021-02-04 08:29:09 +01:00
parent fa780dd196
commit 642146de02
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
17 changed files with 583 additions and 331 deletions

View File

@ -84,5 +84,12 @@ commit automatically with `git commit -s`. You can also use git [aliases](https:
like `git config --global alias.ci 'commit -s'`. Now you can commit with like `git config --global alias.ci 'commit -s'`. Now you can commit with
`git ci` and the commit will be signed. `git ci` and the commit will be signed.
## Credits
### Ringtones
- [Ringtones by Librem](https://soundcloud.com/feandesign/sets/librem-5-sounds)
- [Telefon-Freiton in Deutschland nach DTAG 1 TR 110-1, Kap. 8.3](https://commons.wikimedia.org/wiki/File:1TR110-1_Kap8.3_Freiton1.ogg)
[dcofile]: https://github.com/nextcloud/talk-android/blob/master/contribute/developer-certificate-of-origin [dcofile]: https://github.com/nextcloud/talk-android/blob/master/contribute/developer-certificate-of-origin
[applyalicense]: https://github.com/nextcloud/talk-android/blob/master/contribute/HowToApplyALicense.md [applyalicense]: https://github.com/nextcloud/talk-android/blob/master/contribute/HowToApplyALicense.md

View File

@ -40,9 +40,6 @@ import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.ChatController import com.nextcloud.talk.controllers.ChatController
import com.nextcloud.talk.events.ConfigurationChangeEvent import com.nextcloud.talk.events.ConfigurationChangeEvent
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class MagicCallActivity : BaseActivity() { class MagicCallActivity : BaseActivity() {

View File

@ -177,8 +177,10 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/ */
@FormUrlEncoded
@POST @POST
Observable<GenericOverall> joinCall(@Nullable @Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> joinCall(@Nullable @Header("Authorization") String authorization, @Url String url,
@Field("flags") Integer inCall);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken

View File

@ -46,6 +46,10 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController; import com.facebook.drawee.interfaces.DraweeController;
@ -136,9 +140,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
@ -177,24 +178,31 @@ public class CallController extends BaseController {
@BindView(R.id.pip_video_view) @BindView(R.id.pip_video_view)
SurfaceViewRenderer pipVideoView; SurfaceViewRenderer pipVideoView;
@BindView(R.id.relative_layout) @BindView(R.id.controllerCallLayout)
RelativeLayout relativeLayout; RelativeLayout controllerCallLayout;
@BindView(R.id.remote_renderers_layout) @BindView(R.id.remote_renderers_layout)
LinearLayout remoteRenderersLayout; LinearLayout remoteRenderersLayout;
@BindView(R.id.callControlsRelativeLayout) @BindView(R.id.callControlsLinearLayout)
RelativeLayout callControls; LinearLayout callControls;
@BindView(R.id.call_control_microphone) @BindView(R.id.call_control_microphone)
SimpleDraweeView microphoneControlButton; SimpleDraweeView microphoneControlButton;
@BindView(R.id.call_control_camera) @BindView(R.id.call_control_camera)
SimpleDraweeView cameraControlButton; SimpleDraweeView cameraControlButton;
@BindView(R.id.call_control_switch_camera) @BindView(R.id.call_control_switch_camera)
SimpleDraweeView cameraSwitchButton; SimpleDraweeView cameraSwitchButton;
@BindView(R.id.connectingTextView) @BindView(R.id.callStateTextView)
TextView connectingTextView; TextView callStateTextView;
@BindView(R.id.connectingRelativeLayoutView) @BindView(R.id.callInfosLinearLayout)
RelativeLayout connectingView; LinearLayout callInfosLinearLayout;
@BindView(R.id.callVoiceOrVideoTextView)
TextView callVoiceOrVideoTextView;
@BindView(R.id.callConversationNameTextView)
TextView callConversationNameTextView;
@BindView(R.id.callStateRelativeLayoutView)
RelativeLayout callStateView;
@BindView(R.id.conversationRelativeLayoutView) @BindView(R.id.conversationRelativeLayoutView)
RelativeLayout conversationView; RelativeLayout conversationView;
@ -202,7 +210,7 @@ public class CallController extends BaseController {
@BindView(R.id.errorImageView) @BindView(R.id.errorImageView)
ImageView errorImageView; ImageView errorImageView;
@BindView(R.id.progress_bar) @BindView(R.id.callStateProgressBar)
ProgressBar progressBar; ProgressBar progressBar;
@Inject @Inject
@ -234,6 +242,7 @@ public class CallController extends BaseController {
private CameraEnumerator cameraEnumerator; private CameraEnumerator cameraEnumerator;
private String roomToken; private String roomToken;
private UserEntity conversationUser; private UserEntity conversationUser;
private String conversationName;
private String callSession; private String callSession;
private MediaStream localMediaStream; private MediaStream localMediaStream;
private String credentials; private String credentials;
@ -247,9 +256,12 @@ public class CallController extends BaseController {
private boolean needsPing = true; private boolean needsPing = true;
private boolean isVoiceOnlyCall; private boolean isVoiceOnlyCall;
private boolean isIncomingCallFromNotification;
private Handler callControlHandler = new Handler(); private Handler callControlHandler = new Handler();
private Handler callInfosHandler = new Handler();
private Handler cameraSwitchHandler = new Handler(); private Handler cameraSwitchHandler = new Handler();
// push to talk
private boolean isPTTActive = false; private boolean isPTTActive = false;
private PulseAnimation pulseAnimation; private PulseAnimation pulseAnimation;
private View.OnClickListener videoOnClickListener; private View.OnClickListener videoOnClickListener;
@ -276,7 +288,7 @@ public class CallController extends BaseController {
@Parcel @Parcel
public enum CallStatus { public enum CallStatus {
CALLING, CALLING_TIMEOUT, ESTABLISHED, IN_CONVERSATION, RECONNECTING, OFFLINE, LEAVING, PUBLISHER_FAILED CONNECTING, CALLING_TIMEOUT, JOINED, IN_CONVERSATION, RECONNECTING, OFFLINE, LEAVING, PUBLISHER_FAILED
} }
public CallController(Bundle args) { public CallController(Bundle args) {
@ -287,8 +299,13 @@ public class CallController extends BaseController {
roomToken = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), ""); roomToken = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), "");
conversationUser = args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY()); conversationUser = args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY());
conversationPassword = args.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), ""); conversationPassword = args.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), "");
conversationName = args.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), "");
isVoiceOnlyCall = args.getBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false); isVoiceOnlyCall = args.getBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false);
if (args.containsKey(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL())) {
isIncomingCallFromNotification = args.getBoolean(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL());
}
credentials = ApiUtils.getCredentials(conversationUser.getUsername(), conversationUser.getToken()); credentials = ApiUtils.getCredentials(conversationUser.getUsername(), conversationUser.getToken());
baseUrl = args.getString(BundleKeys.INSTANCE.getKEY_MODIFIED_BASE_URL(), ""); baseUrl = args.getString(BundleKeys.INSTANCE.getKEY_MODIFIED_BASE_URL(), "");
@ -302,7 +319,7 @@ public class CallController extends BaseController {
if (args.getString("state", "").equalsIgnoreCase("resume")) { if (args.getString("state", "").equalsIgnoreCase("resume")) {
setCallState(CallStatus.IN_CONVERSATION); setCallState(CallStatus.IN_CONVERSATION);
} else { } else {
setCallState(CallStatus.CALLING); setCallState(CallStatus.CONNECTING);
} }
} }
@ -362,7 +379,7 @@ public class CallController extends BaseController {
//Create a new PeerConnectionFactory instance. //Create a new PeerConnectionFactory instance.
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory( DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(
rootEglBase.getEglBaseContext(),true,true); rootEglBase.getEglBaseContext(), true, true);
DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext()); DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());
peerConnectionFactory = PeerConnectionFactory.builder() peerConnectionFactory = PeerConnectionFactory.builder()
@ -456,7 +473,12 @@ public class CallController extends BaseController {
cameraSwitchButton.setVisibility(View.GONE); cameraSwitchButton.setVisibility(View.GONE);
cameraControlButton.setVisibility(View.GONE); cameraControlButton.setVisibility(View.GONE);
pipVideoView.setVisibility(View.GONE); pipVideoView.setVisibility(View.GONE);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, R.id.callInfosLinearLayout);
remoteRenderersLayout.setLayoutParams(params);
} else { } else {
callControlEnableSpeaker.setVisibility(View.GONE);
if (cameraEnumerator.getDeviceNames().length < 2) { if (cameraEnumerator.getDeviceNames().length < 2) {
cameraSwitchButton.setVisibility(View.GONE); cameraSwitchButton.setVisibility(View.GONE);
} }
@ -484,7 +506,7 @@ public class CallController extends BaseController {
} }
private boolean isConnectionEstablished() { private boolean isConnectionEstablished() {
return (currentCallStatus.equals(CallStatus.ESTABLISHED) || currentCallStatus.equals(CallStatus.IN_CONVERSATION)); return (currentCallStatus.equals(CallStatus.JOINED) || currentCallStatus.equals(CallStatus.IN_CONVERSATION));
} }
@AfterPermissionGranted(100) @AfterPermissionGranted(100)
@ -648,6 +670,7 @@ public class CallController extends BaseController {
boolean onMicrophoneLongClick() { boolean onMicrophoneLongClick() {
if (!audioOn) { if (!audioOn) {
callControlHandler.removeCallbacksAndMessages(null); callControlHandler.removeCallbacksAndMessages(null);
callInfosHandler.removeCallbacksAndMessages(null);
cameraSwitchHandler.removeCallbacksAndMessages(null); cameraSwitchHandler.removeCallbacksAndMessages(null);
isPTTActive = true; isPTTActive = true;
callControls.setVisibility(View.VISIBLE); callControls.setVisibility(View.VISIBLE);
@ -868,6 +891,7 @@ public class CallController extends BaseController {
if (show) { if (show) {
callControlHandler.removeCallbacksAndMessages(null); callControlHandler.removeCallbacksAndMessages(null);
callInfosHandler.removeCallbacksAndMessages(null);
cameraSwitchHandler.removeCallbacksAndMessages(null); cameraSwitchHandler.removeCallbacksAndMessages(null);
alpha = 1.0f; alpha = 1.0f;
duration = 1000; duration = 1000;
@ -875,8 +899,13 @@ public class CallController extends BaseController {
callControls.setAlpha(0.0f); callControls.setAlpha(0.0f);
callControls.setVisibility(View.VISIBLE); callControls.setVisibility(View.VISIBLE);
callInfosLinearLayout.setAlpha(0.0f);
callInfosLinearLayout.setVisibility(View.VISIBLE);
cameraSwitchButton.setAlpha(0.0f); cameraSwitchButton.setAlpha(0.0f);
cameraSwitchButton.setVisibility(View.VISIBLE); if (videoOn) {
cameraSwitchButton.setVisibility(View.VISIBLE);
}
} else { } else {
callControlHandler.postDelayed(() -> animateCallControls(false, 0), 5000); callControlHandler.postDelayed(() -> animateCallControls(false, 0), 5000);
return; return;
@ -920,6 +949,37 @@ public class CallController extends BaseController {
}); });
} }
if (callInfosLinearLayout != null) {
callInfosLinearLayout.setEnabled(false);
callInfosLinearLayout.animate()
.translationY(0)
.alpha(alpha)
.setDuration(duration)
.setStartDelay(startDelay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (callInfosLinearLayout != null) {
if (!show) {
callInfosLinearLayout.setVisibility(View.GONE);
} else {
callInfosHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!isPTTActive) {
animateCallControls(false, 0);
}
}
}, 7500);
}
callInfosLinearLayout.setEnabled(true);
}
}
});
}
if (cameraSwitchButton != null) { if (cameraSwitchButton != null) {
cameraSwitchButton.setEnabled(false); cameraSwitchButton.setEnabled(false);
cameraSwitchButton.animate() cameraSwitchButton.animate()
@ -1139,8 +1199,15 @@ public class CallController extends BaseController {
} }
private void performCall() { private void performCall() {
Integer inCallFlag;
if (isVoiceOnlyCall) {
inCallFlag = (int) Participant.ParticipantFlags.IN_CALL_WITH_AUDIO.getValue();
} else {
inCallFlag = (int) Participant.ParticipantFlags.IN_CALL_WITH_AUDIO_AND_VIDEO.getValue();
}
ncApi.joinCall(credentials, ncApi.joinCall(credentials,
ApiUtils.getUrlForCall(baseUrl, roomToken)) ApiUtils.getUrlForCall(baseUrl, roomToken), inCallFlag)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.retry(3) .retry(3)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -1153,7 +1220,7 @@ public class CallController extends BaseController {
@Override @Override
public void onNext(GenericOverall genericOverall) { public void onNext(GenericOverall genericOverall) {
if (!currentCallStatus.equals(CallStatus.LEAVING)) { if (!currentCallStatus.equals(CallStatus.LEAVING)) {
setCallState(CallStatus.ESTABLISHED); setCallState(CallStatus.JOINED);
ApplicationWideCurrentRoomHolder.getInstance().setInCall(true); ApplicationWideCurrentRoomHolder.getInstance().setInCall(true);
@ -1339,7 +1406,7 @@ public class CallController extends BaseController {
private void receivedSignalingMessage(Signaling signaling) throws IOException { private void receivedSignalingMessage(Signaling signaling) throws IOException {
String messageType = signaling.getType(); String messageType = signaling.getType();
if (!isConnectionEstablished() && !currentCallStatus.equals(CallStatus.CALLING)) { if (!isConnectionEstablished() && !currentCallStatus.equals(CallStatus.CONNECTING)) {
return; return;
} }
@ -1464,38 +1531,38 @@ public class CallController extends BaseController {
} }
private void hangupNetworkCalls(boolean shutDownView) { private void hangupNetworkCalls(boolean shutDownView) {
ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() { .subscribe(new Observer<GenericOverall>() {
@Override @Override
public void onSubscribe(Disposable d) { public void onSubscribe(Disposable d) {
} }
@Override @Override
public void onNext(GenericOverall genericOverall) { public void onNext(GenericOverall genericOverall) {
if (isMultiSession) { if (isMultiSession) {
if (shutDownView && getActivity() != null) { if (shutDownView && getActivity() != null) {
getActivity().finish(); getActivity().finish();
} else if (!shutDownView && (currentCallStatus.equals(CallStatus.RECONNECTING) || currentCallStatus.equals(CallStatus.PUBLISHER_FAILED))) { } else if (!shutDownView && (currentCallStatus.equals(CallStatus.RECONNECTING) || currentCallStatus.equals(CallStatus.PUBLISHER_FAILED))) {
initiateCall(); initiateCall();
}
} else {
leaveRoom(shutDownView);
} }
} else {
leaveRoom(shutDownView);
} }
}
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
} }
@Override @Override
public void onComplete() { public void onComplete() {
} }
}); });
} }
private void leaveRoom(boolean shutDownView) { private void leaveRoom(boolean shutDownView) {
@ -1567,7 +1634,7 @@ public class CallController extends BaseController {
// Calculate sessions that join the call // Calculate sessions that join the call
newSessions.removeAll(oldSesssions); newSessions.removeAll(oldSesssions);
if (!isConnectionEstablished() && !currentCallStatus.equals(CallStatus.CALLING)) { if (!isConnectionEstablished() && !currentCallStatus.equals(CallStatus.CONNECTING)) {
return; return;
} }
@ -1759,7 +1826,7 @@ public class CallController extends BaseController {
boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent
.PeerConnectionEventType.SENSOR_FAR) && videoOn; .PeerConnectionEventType.SENSOR_FAR) && videoOn;
if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) && if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) &&
(currentCallStatus.equals(CallStatus.CALLING) || isConnectionEstablished()) && videoOn (currentCallStatus.equals(CallStatus.CONNECTING) || isConnectionEstablished()) && videoOn
&& enableVideo != localVideoTrack.enabled()) { && enableVideo != localVideoTrack.enabled()) {
toggleMedia(enableVideo, true); toggleMedia(enableVideo, true);
} }
@ -2066,7 +2133,7 @@ public class CallController extends BaseController {
private void gotNick(String sessionId, String nick, String type) { private void gotNick(String sessionId, String nick, String type) {
String remoteRendererTag = sessionId + "+" + type; String remoteRendererTag = sessionId + "+" + type;
if (relativeLayout != null) { if (controllerCallLayout != null) {
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(remoteRendererTag); RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(remoteRendererTag);
TextView textView = relativeLayout.findViewById(R.id.peer_nick_text_view); TextView textView = relativeLayout.findViewById(R.id.peer_nick_text_view);
if (!textView.getText().equals(nick)) { if (!textView.getText().equals(nick)) {
@ -2079,7 +2146,7 @@ public class CallController extends BaseController {
} }
} }
@OnClick(R.id.connectingRelativeLayoutView) @OnClick(R.id.callStateRelativeLayoutView)
public void onConnectingViewClick() { public void onConnectingViewClick() {
if (currentCallStatus.equals(CallStatus.CALLING_TIMEOUT)) { if (currentCallStatus.equals(CallStatus.CALLING_TIMEOUT)) {
setCallState(CallStatus.RECONNECTING); setCallState(CallStatus.RECONNECTING);
@ -2097,16 +2164,24 @@ public class CallController extends BaseController {
} }
switch (callState) { switch (callState) {
case CALLING: case CONNECTING:
handler.post(() -> { handler.post(() -> {
playCallingSound(); playCallingSound();
connectingTextView.setText(R.string.nc_connecting_call); if (isIncomingCallFromNotification) {
if (connectingView.getVisibility() != View.VISIBLE) { callStateTextView.setText(R.string.nc_call_incoming);
connectingView.setVisibility(View.VISIBLE); } else {
callStateTextView.setText(R.string.nc_call_ringing);
}
callConversationNameTextView.setText(conversationName);
callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
if (callStateView.getVisibility() != View.VISIBLE) {
callStateView.setVisibility(View.VISIBLE);
} }
if (conversationView.getVisibility() != View.INVISIBLE) { if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
conversationView.setVisibility(View.INVISIBLE); remoteRenderersLayout.setVisibility(View.INVISIBLE);
} }
if (progressBar.getVisibility() != View.VISIBLE) { if (progressBar.getVisibility() != View.VISIBLE) {
@ -2121,17 +2196,18 @@ public class CallController extends BaseController {
case CALLING_TIMEOUT: case CALLING_TIMEOUT:
handler.post(() -> { handler.post(() -> {
hangup(false); hangup(false);
connectingTextView.setText(R.string.nc_call_timeout); callStateTextView.setText(R.string.nc_call_timeout);
if (connectingView.getVisibility() != View.VISIBLE) { callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
connectingView.setVisibility(View.VISIBLE); if (callStateView.getVisibility() != View.VISIBLE) {
callStateView.setVisibility(View.VISIBLE);
} }
if (progressBar.getVisibility() != View.GONE) { if (progressBar.getVisibility() != View.GONE) {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
} }
if (conversationView.getVisibility() != View.INVISIBLE) { if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
conversationView.setVisibility(View.INVISIBLE); remoteRenderersLayout.setVisibility(View.INVISIBLE);
} }
errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp); errorImageView.setImageResource(R.drawable.ic_av_timer_timer_24dp);
@ -2144,12 +2220,13 @@ public class CallController extends BaseController {
case RECONNECTING: case RECONNECTING:
handler.post(() -> { handler.post(() -> {
playCallingSound(); playCallingSound();
connectingTextView.setText(R.string.nc_call_reconnecting); callStateTextView.setText(R.string.nc_call_reconnecting);
if (connectingView.getVisibility() != View.VISIBLE) { callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
connectingView.setVisibility(View.VISIBLE); if (callStateView.getVisibility() != View.VISIBLE) {
callStateView.setVisibility(View.VISIBLE);
} }
if (conversationView.getVisibility() != View.INVISIBLE) { if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
conversationView.setVisibility(View.INVISIBLE); remoteRenderersLayout.setVisibility(View.INVISIBLE);
} }
if (progressBar.getVisibility() != View.VISIBLE) { if (progressBar.getVisibility() != View.VISIBLE) {
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
@ -2160,13 +2237,18 @@ public class CallController extends BaseController {
} }
}); });
break; break;
case ESTABLISHED: case JOINED:
handler.postDelayed(() -> setCallState(CallStatus.CALLING_TIMEOUT), 45000); handler.postDelayed(() -> setCallState(CallStatus.CALLING_TIMEOUT), 45000);
handler.post(() -> { handler.post(() -> {
if (connectingView != null) { callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
connectingTextView.setText(R.string.nc_calling); if (callStateView != null) {
if (connectingTextView.getVisibility() != View.VISIBLE) { if (isIncomingCallFromNotification) {
connectingView.setVisibility(View.VISIBLE); callStateTextView.setText(R.string.nc_call_incoming);
} else {
callStateTextView.setText(R.string.nc_call_ringing);
}
if (callStateView.getVisibility() != View.VISIBLE) {
callStateView.setVisibility(View.VISIBLE);
} }
} }
@ -2176,9 +2258,9 @@ public class CallController extends BaseController {
} }
} }
if (conversationView != null) { if (remoteRenderersLayout != null) {
if (conversationView.getVisibility() != View.INVISIBLE) { if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
conversationView.setVisibility(View.INVISIBLE); remoteRenderersLayout.setVisibility(View.INVISIBLE);
} }
} }
@ -2192,14 +2274,19 @@ public class CallController extends BaseController {
case IN_CONVERSATION: case IN_CONVERSATION:
handler.post(() -> { handler.post(() -> {
stopCallingSound(); stopCallingSound();
callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
if (!isVoiceOnlyCall) {
callInfosLinearLayout.setVisibility(View.GONE);
}
if (!isPTTActive) { if (!isPTTActive) {
animateCallControls(false, 5000); animateCallControls(false, 5000);
} }
if (connectingView != null) { if (callStateView != null) {
if (connectingView.getVisibility() != View.INVISIBLE) { if (callStateView.getVisibility() != View.INVISIBLE) {
connectingView.setVisibility(View.INVISIBLE); callStateView.setVisibility(View.INVISIBLE);
} }
} }
@ -2209,9 +2296,9 @@ public class CallController extends BaseController {
} }
} }
if (conversationView != null) { if (remoteRenderersLayout != null) {
if (conversationView.getVisibility() != View.VISIBLE) { if (remoteRenderersLayout.getVisibility() != View.VISIBLE) {
conversationView.setVisibility(View.VISIBLE); remoteRenderersLayout.setVisibility(View.VISIBLE);
} }
} }
@ -2226,18 +2313,18 @@ public class CallController extends BaseController {
handler.post(() -> { handler.post(() -> {
stopCallingSound(); stopCallingSound();
if (connectingTextView != null) { if (callStateTextView != null) {
connectingTextView.setText(R.string.nc_offline); callStateTextView.setText(R.string.nc_offline);
if (connectingView.getVisibility() != View.VISIBLE) { if (callStateView.getVisibility() != View.VISIBLE) {
connectingView.setVisibility(View.VISIBLE); callStateView.setVisibility(View.VISIBLE);
} }
} }
if (conversationView != null) { if (remoteRenderersLayout != null) {
if (conversationView.getVisibility() != View.INVISIBLE) { if (remoteRenderersLayout.getVisibility() != View.INVISIBLE) {
conversationView.setVisibility(View.INVISIBLE); remoteRenderersLayout.setVisibility(View.INVISIBLE);
} }
} }
@ -2259,9 +2346,10 @@ public class CallController extends BaseController {
handler.post(() -> { handler.post(() -> {
if (!isDestroyed() && !isBeingDestroyed()) { if (!isDestroyed() && !isBeingDestroyed()) {
stopCallingSound(); stopCallingSound();
connectingTextView.setText(R.string.nc_leaving_call); callVoiceOrVideoTextView.setText(isVoiceOnlyCall ? R.string.nc_voice_call : R.string.nc_video_call);
connectingView.setVisibility(View.VISIBLE); callStateTextView.setText(R.string.nc_leaving_call);
conversationView.setVisibility(View.INVISIBLE); callStateView.setVisibility(View.VISIBLE);
remoteRenderersLayout.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
errorImageView.setVisibility(View.GONE); errorImageView.setVisibility(View.GONE);
} }
@ -2274,7 +2362,14 @@ public class CallController extends BaseController {
private void playCallingSound() { private void playCallingSound() {
stopCallingSound(); stopCallingSound();
Uri ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/raw/librem_by_feandesign_call"); Uri ringtoneUri;
if (isIncomingCallFromNotification) {
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/raw" +
"/tr110_1_kap8_3_freiton1");
}
if (getActivity() != null) { if (getActivity() != null) {
mediaPlayer = new MediaPlayer(); mediaPlayer = new MediaPlayer();
try { try {

View File

@ -70,6 +70,7 @@ import com.nextcloud.talk.events.ConfigurationChangeEvent;
import com.nextcloud.talk.models.RingtoneSettings; import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomOverall;
import com.nextcloud.talk.models.json.conversations.RoomsOverall; import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.participants.ParticipantsOverall; import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
@ -83,6 +84,7 @@ import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.michaelevans.colorart.library.ColorArt; import org.michaelevans.colorart.library.ColorArt;
import org.parceler.Parcels; import org.parceler.Parcels;
@ -121,6 +123,9 @@ public class CallNotificationController extends BaseController {
@Inject @Inject
Context context; Context context;
@BindView(R.id.incomingCallVoiceOrVideoTextView)
TextView incomingCallVoiceOrVideoTextView;
@BindView(R.id.conversationNameTextView) @BindView(R.id.conversationNameTextView)
TextView conversationNameTextView; TextView conversationNameTextView;
@ -197,6 +202,8 @@ public class CallNotificationController extends BaseController {
private void proceedToCall() { private void proceedToCall() {
originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken()); originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken());
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle)) getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
.popChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())
@ -253,38 +260,77 @@ public class CallNotificationController extends BaseController {
} }
private void handleFromNotification() { private void handleFromNotification() {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(userBeingCalled.getBaseUrl())) boolean isConversationApiV3 = userBeingCalled.hasSpreedFeatureCapability("conversation-v3");
.subscribeOn(Schedulers.io()) if(isConversationApiV3) {
.retry(3) ncApi.getRoom(credentials, ApiUtils.getRoomV3(userBeingCalled.getBaseUrl(), roomId))
.observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io())
.subscribe(new Observer<RoomsOverall>() { .retry(3)
@Override .observeOn(AndroidSchedulers.mainThread())
public void onSubscribe(Disposable d) { .subscribe(new Observer<RoomOverall>() {
disposablesList.add(d); @Override
} public void onSubscribe(Disposable d) {
disposablesList.add(d);
}
@Override @Override
public void onNext(RoomsOverall roomsOverall) { public void onNext(@NotNull RoomOverall roomOverall) {
for (Conversation conversation : roomsOverall.getOcs().getData()) { currentConversation = roomOverall.getOcs().data;
if (roomId.equals(conversation.getRoomId()) || roomId.equals(conversation.token)) { runAllThings();
currentConversation = conversation;
runAllThings(); boolean hasCallFlags = userBeingCalled.hasSpreedFeatureCapability("conversation-call-flags");
break; if (hasCallFlags) {
if (isInCallWithVideo(currentConversation.callFlag)){
incomingCallVoiceOrVideoTextView.setText(R.string.nc_video_call);
} else {
incomingCallVoiceOrVideoTextView.setText(R.string.nc_voice_call);
}
} }
} }
} @Override
public void onError(Throwable e) {
@Override }
public void onError(Throwable e) {
} @Override
public void onComplete() {
@Override }
public void onComplete() { });
} else {
ncApi.getRoom(credentials, ApiUtils.getRoom(userBeingCalled.getBaseUrl(), roomId))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(Disposable d) {
disposablesList.add(d);
}
} @SuppressLint("LongLogTag")
}); @Override
public void onNext(@NotNull RoomOverall roomOverall) {
currentConversation = roomOverall.getOcs().data;
runAllThings();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
private boolean isInCallWithVideo(int callFlag) {
return (Participant.ParticipantFlags.IN_CALL_WITH_VIDEO.getValue() == callFlag
|| Participant.ParticipantFlags.IN_CALL_WITH_AUDIO_AND_VIDEO.getValue() == callFlag);
} }
private void runAllThings() { private void runAllThings() {
@ -321,73 +367,14 @@ public class CallNotificationController extends BaseController {
} }
if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) { if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri(); playRingtoneSound();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null && getActivity() != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getActivity(), ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
} }
if (DoNotDisturbUtils.INSTANCE.shouldVibrate(appPreferences.getShouldVibrateSetting())) { if (DoNotDisturbUtils.INSTANCE.shouldVibrate(appPreferences.getShouldVibrateSetting())) {
vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE); vibrate();
if (vibrator != null) {
long[] vibratePattern = new long[]{0, 400, 800, 600, 800, 800, 800, 1000};
int[] amplitudes = new int[]{0, 255, 0, 255, 0, 255, 0, 255};
VibrationEffect vibrationEffect;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (vibrator.hasAmplitudeControl()) {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, amplitudes, -1);
//vibrator.vibrate(vibrationEffect);
} else {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, -1);
//vibrator.vibrate(vibrationEffect);
}
} else {
//vibrator.vibrate(vibratePattern, -1);
}
}
handler.postDelayed(() -> {
if (vibrator != null) {
vibrator.cancel();
}
}, 10000);
} }
} }
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) { public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) avatarImageView.getLayoutParams(); ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) avatarImageView.getLayoutParams();
@ -509,4 +496,71 @@ public class CallNotificationController extends BaseController {
} }
} }
} }
@SuppressLint("LongLogTag")
private void playRingtoneSound() {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null && getActivity() != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getActivity(), ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
}
private void vibrate() {
vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
long[] vibratePattern = new long[]{0, 400, 800, 600, 800, 800, 800, 1000};
int[] amplitudes = new int[]{0, 255, 0, 255, 0, 255, 0, 255};
VibrationEffect vibrationEffect;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (vibrator.hasAmplitudeControl()) {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, amplitudes, -1);
//vibrator.vibrate(vibrationEffect);
} else {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, -1);
//vibrator.vibrate(vibrationEffect);
}
} else {
//vibrator.vibrate(vibratePattern, -1);
}
}
handler.postDelayed(() -> {
if (vibrator != null) {
vibrator.cancel();
}
}, 10000);
}
} }

View File

@ -1395,41 +1395,34 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
private fun startACall(isVoiceOnlyCall: Boolean) { private fun startACall(isVoiceOnlyCall: Boolean) {
isLeavingForConversation = true isLeavingForConversation = true
if (!isVoiceOnlyCall) { val callIntent = getIntentForCall(isVoiceOnlyCall)
val videoCallIntent = getIntentForCall(false) if (callIntent != null) {
if (videoCallIntent != null) { startActivity(callIntent)
startActivity(videoCallIntent)
}
} else {
val voiceCallIntent = getIntentForCall(true)
if (voiceCallIntent != null) {
startActivity(voiceCallIntent)
}
} }
} }
private fun getIntentForCall(isVoiceOnlyCall: Boolean): Intent? { private fun getIntentForCall(isVoiceOnlyCall: Boolean): Intent? {
if (currentConversation != null) { currentConversation?.let {
val bundle = Bundle() val bundle = Bundle()
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken) bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
bundle.putString(BundleKeys.KEY_ROOM_ID, roomId) bundle.putString(BundleKeys.KEY_ROOM_ID, roomId)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser) bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser)
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, roomPassword) bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, roomPassword)
bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, conversationUser?.baseUrl) bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, conversationUser?.baseUrl)
bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, it.displayName)
if (isVoiceOnlyCall) { if (isVoiceOnlyCall) {
bundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true) bundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true)
} }
if (activity != null) { return if (activity != null) {
val callIntent = Intent(activity, MagicCallActivity::class.java) val callIntent = Intent(activity, MagicCallActivity::class.java)
callIntent.putExtras(bundle) callIntent.putExtras(bundle)
callIntent
return callIntent
} else { } else {
return null null
} }
} else { } ?:run {
return null return null
} }
} }

View File

@ -94,6 +94,8 @@ public class Conversation {
public Long lobbyTimer; public Long lobbyTimer;
@JsonField(name = "lastReadMessage") @JsonField(name = "lastReadMessage")
public int lastReadMessage; public int lastReadMessage;
@JsonField(name = "callFlag")
public int callFlag;
public boolean isPublic() { public boolean isPublic() {
return (ConversationType.ROOM_PUBLIC_CALL.equals(type)); return (ConversationType.ROOM_PUBLIC_CALL.equals(type));

View File

@ -127,6 +127,10 @@ public class ApiUtils {
return baseUrl + ocsApiVersion + spreedApiVersion + "/room/" + token; return baseUrl + ocsApiVersion + spreedApiVersion + "/room/" + token;
} }
public static String getRoomV3(String baseUrl, String token) {
return baseUrl + ocsApiVersion + "/apps/spreed/api/v3" + "/room/" + token;
}
public static RetrofitBucket getRetrofitBucketForCreateRoom(String baseUrl, String roomType, public static RetrofitBucket getRetrofitBucketForCreateRoom(String baseUrl, String roomType,
@Nullable String invite, @Nullable String invite,
@Nullable String conversationName) { @Nullable String conversationName) {

View File

@ -0,0 +1,29 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#FFFFFF"
android:pathData="M6.667,4C4.089,4 2,6.105 2,8.7v11.282c0,2.597 2.09,4.701 4.667,4.701 1.716,0.01 12.083,0.003 17.057,0 1.115,0.842 1.807,1.748 3.057,3.206a0.93,0.93 0,0 0,0.561 0.103,0.969 0.969,0 0,0 0.445,-0.187c0.302,-0.223 0.466,-0.603 0.427,-0.988l-0.314,-2.912a4.699,4.699 0,0 0,2.1 -3.923L30,8.701C30,6.105 27.91,4 25.333,4zM10.4,12.461c1.03,0 1.867,0.842 1.867,1.88 0,1.676 -2.01,2.514 -3.187,1.33 -1.176,-1.184 -0.343,-3.21 1.32,-3.21zM16,12.461c1.03,0 1.867,0.842 1.867,1.88 0,1.676 -2.01,2.514 -3.187,1.33 -1.176,-1.184 -0.343,-3.21 1.32,-3.21zM21.6,12.461c1.03,0 1.867,0.842 1.867,1.88 0,1.676 -2.01,2.514 -3.187,1.33 -1.176,-1.184 -0.343,-3.21 1.32,-3.21z"/>
</vector>

View File

@ -26,6 +26,18 @@
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical"> 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 <ImageView
android:id="@+id/remote_audio_off" android:id="@+id/remote_audio_off"
android:layout_width="16dp" android:layout_width="16dp"
@ -47,17 +59,6 @@
android:src="@drawable/ic_videocam_off_white_24px" android:src="@drawable/ic_videocam_off_white_24px"
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_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:textColor="@android:color/white" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/avatarImageView" android:id="@+id/avatarImageView"
android:layout_width="80dp" android:layout_width="80dp"

View File

@ -19,25 +19,24 @@
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/connectingRelativeLayoutView" android:id="@+id/callStateRelativeLayoutView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content">
android:background="@color/grey950">
<ImageView <ImageView
android:id="@+id/errorImageView" android:id="@+id/errorImageView"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_above="@id/connectingTextView" android:layout_above="@id/callStateTextView"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:src="@drawable/ic_signal_wifi_off_white_24dp" android:src="@drawable/ic_signal_wifi_off_white_24dp"
android:visibility="gone" /> android:visibility="gone" />
<ProgressBar <ProgressBar
android:id="@+id/progress_bar" android:id="@+id/callStateProgressBar"
android:layout_width="@dimen/item_height" android:layout_width="@dimen/item_height"
android:layout_height="@dimen/item_height" android:layout_height="@dimen/item_height"
android:layout_above="@id/connectingTextView" android:layout_above="@id/callStateTextView"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginStart="@dimen/activity_horizontal_margin" android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_marginLeft="@dimen/activity_horizontal_margin"
@ -48,7 +47,7 @@
android:indeterminateTintMode="src_in" /> android:indeterminateTintMode="src_in" />
<TextView <TextView
android:id="@+id/connectingTextView" android:id="@+id/callStateTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"

View File

@ -3,6 +3,8 @@
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ @author Marcel Hibbe
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
~ ~
~ This program is free software: you can redistribute it and/or modify ~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by ~ it under the terms of the GNU General Public License as published by
@ -19,135 +21,176 @@
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/relative_layout" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/controllerCallLayout"
android:layout_height="match_parent"
android:background="@color/grey950"
android:fitsSystemWindows="true"
tools:context=".activities.MagicCallActivity">
<RelativeLayout
android:id="@+id/conversationRelativeLayoutView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="invisible"> android:orientation="vertical"
tools:context=".activities.MagicCallActivity">
<LinearLayout
android:id="@+id/linearWrapperLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout <RelativeLayout
android:id="@+id/remote_renderers_layout" android:id="@+id/conversationRelativeLayoutView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
android:animateLayoutChanges="true"
android:background="@color/grey950" android:background="@color/grey950"
android:orientation="vertical"> android:visibility="visible"
android:layout_weight="1"
tools:visibility="visible">
</LinearLayout> <LinearLayout
</RelativeLayout> android:id="@+id/remote_renderers_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical">
</LinearLayout>
<RelativeLayout <LinearLayout
android:id="@+id/callControlsRelativeLayout" android:id="@+id/callInfosLinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:gravity="center"
android:paddingTop="20dp">
<TextView
android:id="@+id/callVoiceOrVideoTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="@color/controller_call_incomingCallTextView"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/nc_voice_call"/>
<TextView
android:id="@+id/callConversationNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="15dp"
android:ellipsize="marquee"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="28sp"
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 xmlns:app="http://schemas.android.com/apk/res-auto"
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"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"/>
<include
layout="@layout/call_states"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/verticalCenter"
android:layout_marginTop="-50dp"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/callControlsLinearLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:animateLayoutChanges="true"
android:layout_marginTop="16dp" android:orientation="horizontal"
android:layout_marginBottom="8dp" android:background="@android:color/transparent"
android:animateLayoutChanges="true"> android:gravity="center"
android:layout_alignBottom="@id/linearWrapperLayout"
android:layout_marginBottom="10dp">
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto" <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlToggleChat" android:id="@+id/callControlToggleChat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="80dp"
android:layout_marginStart="16dp" android:layout_marginStart="40dp"
app:backgroundImage="@color/whiteHalfTransparent" android:layout_marginEnd="10dp"
app:placeholderImage="@drawable/ic_comment" app:backgroundImage="@color/call_buttons_background"
app:placeholderImage="@drawable/ic_comment_white"
app:roundAsCircle="true"
android:elevation="10dp"
/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlEnableSpeaker"
android:layout_width="60dp"
android:layout_height="80dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:backgroundImage="@color/call_buttons_background"
app:placeholderImage="@drawable/ic_volume_mute_white_24dp"
app:roundAsCircle="true" /> app:roundAsCircle="true" />
<LinearLayout <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlsLinearLayoutView" android:id="@+id/call_control_camera"
android:layout_width="match_parent" android:layout_width="60dp"
android:layout_height="wrap_content" android:layout_height="80dp"
android:layout_alignParentBottom="true" android:layout_marginStart="10dp"
android:layout_centerHorizontal="true" android:layout_marginEnd="10dp"
android:layout_marginBottom="24dp" android:alpha="0.7"
android:animateLayoutChanges="true" app:backgroundImage="@color/call_buttons_background"
android:background="@android:color/transparent" app:placeholderImage="@drawable/ic_videocam_white_24px"
android:gravity="center"> app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto" <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/call_control_microphone" android:id="@+id/call_control_microphone"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="80dp"
android:layout_marginStart="24dp" android:layout_marginStart="10dp"
android:alpha="0.7" android:layout_marginEnd="10dp"
app:backgroundImage="@color/colorPrimary" android:alpha="0.7"
app:placeholderImage="@drawable/ic_mic_off_white_24px" app:backgroundImage="@color/call_buttons_background"
app:roundAsCircle="true" /> app:placeholderImage="@drawable/ic_mic_off_white_24px"
app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto" <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/call_control_camera"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:alpha="0.7"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_videocam_white_24px"
app:roundAsCircle="true" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/callControlEnableSpeaker"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility="gone"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_volume_mute_white_24dp"
app:roundAsCircle="true" />
</LinearLayout>
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/callControlHangupView" android:id="@+id/callControlHangupView"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="80dp"
android:layout_above="@id/callControlsLinearLayoutView" android:layout_marginStart="10dp"
android:layout_centerHorizontal="true" android:layout_marginEnd="40dp"
app:backgroundImage="@color/nc_darkRed" app:backgroundImage="@color/nc_darkRed"
app:placeholderImage="@drawable/ic_call_end_white_24px" app:placeholderImage="@drawable/ic_call_end_white_24px"
app:roundAsCircle="true" /> app:roundAsCircle="true" />
</RelativeLayout> </LinearLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true">
<org.webrtc.SurfaceViewRenderer
android:id="@+id/pip_video_view"
android:layout_width="@dimen/large_preview_dimension"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="16dp"
android:visibility="invisible" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
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:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_switch_video_white_24px"
app:roundAsCircle="true" />
</FrameLayout>
<include
layout="@layout/call_states"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout> </RelativeLayout>

View File

@ -47,7 +47,8 @@
android:visibility="gone" android:visibility="gone"
app:backgroundImage="@color/nc_darkGreen" app:backgroundImage="@color/nc_darkGreen"
app:placeholderImage="@drawable/ic_call_white_24dp" app:placeholderImage="@drawable/ic_call_white_24dp"
app:roundAsCircle="true" /> app:roundAsCircle="true"
tools:visibility="visible"/>
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlHangupView" android:id="@+id/callControlHangupView"
@ -66,7 +67,8 @@
android:visibility="gone" android:visibility="gone"
app:backgroundImage="@color/nc_darkGreen" app:backgroundImage="@color/nc_darkGreen"
app:placeholderImage="@drawable/ic_videocam_white_24px" app:placeholderImage="@drawable/ic_videocam_white_24px"
app:roundAsCircle="true" /> app:roundAsCircle="true"
tools:visibility="visible"/>
</LinearLayout> </LinearLayout>
<RelativeLayout <RelativeLayout
@ -75,11 +77,11 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/incomingCallTextView" android:id="@+id/incomingCallVoiceOrVideoTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:text="@string/nc_incoming_call" android:text="@string/nc_unknown_call"
android:textAlignment="center" android:textAlignment="center"
android:textColor="@color/controller_call_incomingCallTextView" android:textColor="@color/controller_call_incomingCallTextView"
android:textSize="16sp" android:textSize="16sp"
@ -91,7 +93,7 @@
android:id="@+id/conversationNameTextView" android:id="@+id/conversationNameTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/incomingCallTextView" android:layout_below="@+id/incomingCallVoiceOrVideoTextView"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:ellipsize="marquee" android:ellipsize="marquee"
android:textAlignment="center" android:textAlignment="center"
@ -99,6 +101,16 @@
android:textSize="28sp" android:textSize="28sp"
tools:text="Victor Gregorius Magnus" /> tools:text="Victor Gregorius Magnus" />
<TextView
android:id="@+id/incomingCallDescriptionTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/nc_call_incoming"
android:textAlignment="center"
android:textColor="@color/controller_call_incomingCallTextView"
android:textSize="16sp"
android:layout_below="@+id/conversationNameTextView" />
</RelativeLayout> </RelativeLayout>
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView

View File

@ -20,24 +20,29 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bbb"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:keepScreenOn="true" android:keepScreenOn="true"
android:animateLayoutChanges="true"> android:animateLayoutChanges="true">
<include layout="@layout/lobby_view" <include layout="@layout/lobby_view"
android:visibility="gone"/> android:visibility="gone"
tools:visibility="visible"/>
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/callControlToggleChat" android:id="@+id/callControlToggleChat"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_margin="16dp" android:layout_margin="16dp"
app:backgroundImage="@color/nc_grey" android:layout_alignParentEnd="true"
app:backgroundImage="@color/call_buttons_background"
app:placeholderImage="@drawable/ic_call_black_24dp" app:placeholderImage="@drawable/ic_call_black_24dp"
app:roundAsCircle="true" app:roundAsCircle="true"
android:elevation="10dp" android:elevation="10dp"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"
/> />
<ProgressBar <ProgressBar
@ -52,7 +57,8 @@
android:indeterminate="true" android:indeterminate="true"
android:indeterminateTint="@color/colorPrimary" android:indeterminateTint="@color/colorPrimary"
android:indeterminateTintMode="src_in" android:indeterminateTintMode="src_in"
android:visibility="gone" /> android:visibility="gone"
tools:visibility="visible"/>
<View <View
android:id="@+id/separator" android:id="@+id/separator"

Binary file not shown.

View File

@ -64,4 +64,7 @@
<color name="bg_message_list_outcoming_bubble_deleted">#800082C9</color> <color name="bg_message_list_outcoming_bubble_deleted">#800082C9</color>
<color name="bg_bottom_sheet">#46ffffff</color> <color name="bg_bottom_sheet">#46ffffff</color>
<color name="call_buttons_background">#BF999999</color>
</resources> </resources>

View File

@ -184,6 +184,11 @@
<string name="nc_permissions_settings">Open settings</string> <string name="nc_permissions_settings">Open settings</string>
<!-- Call --> <!-- Call -->
<string name="nc_voice_call">Nextcloud Talk voice call</string>
<string name="nc_video_call">Nextcloud Talk video call</string>
<string name="nc_unknown_call">Nextcloud Talk call</string>
<string name="nc_call_incoming">INCOMING</string>
<string name="nc_call_ringing">RINGING</string>
<string name="nc_connecting_call">Connecting…</string> <string name="nc_connecting_call">Connecting…</string>
<string name="nc_calling">Calling…</string> <string name="nc_calling">Calling…</string>
<string name="nc_incoming_call">Incoming call from</string> <string name="nc_incoming_call">Incoming call from</string>