From 621468b81fc3a5198205b7b3a432bf0c9d83cc9c Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 19 Jun 2018 13:17:01 +0200 Subject: [PATCH] Do lots of work on call notification Signed-off-by: Mario Danic --- app/src/main/AndroidManifest.xml | 6 +- .../talk/activities/MagicCallActivity.java | 96 + .../CallController.java} | 1583 ++++++++--------- .../CallNotificationController.java | 16 +- .../talk/controllers/CallsListController.java | 4 +- .../talk/controllers/ChatController.java | 4 +- .../talk/controllers/ContactsController.java | 6 +- .../talk/controllers/base/BaseController.java | 2 +- .../bottomsheet/OperationsMenuController.java | 6 +- .../nextcloud/talk/jobs/NotificationJob.java | 24 +- .../main/res/layout/activity_magic_call.xml | 34 + app/src/main/res/layout/controller_call.xml | 144 ++ app/src/main/res/values/strings.xml | 1 + 13 files changed, 1067 insertions(+), 859 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.java rename app/src/main/java/com/nextcloud/talk/{activities/CallActivity.java => controllers/CallController.java} (84%) create mode 100644 app/src/main/res/layout/activity_magic_call.xml create mode 100644 app/src/main/res/layout/controller_call.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f1060a870..4f95aa544 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,7 +46,9 @@ tools:replace="label, icon, roundIcon, theme, name, allowBackup"> - + diff --git a/app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.java new file mode 100644 index 000000000..c00fadf11 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.java @@ -0,0 +1,96 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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 . + */ + +package com.nextcloud.talk.activities; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import com.bluelinelabs.conductor.Conductor; +import com.bluelinelabs.conductor.Router; +import com.bluelinelabs.conductor.RouterTransaction; +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; +import com.nextcloud.talk.R; +import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.controllers.CallController; +import com.nextcloud.talk.controllers.CallNotificationController; +import com.nextcloud.talk.utils.bundle.BundleKeys; + +import autodagger.AutoInjector; +import butterknife.BindView; +import butterknife.ButterKnife; + +@AutoInjector(NextcloudTalkApplication.class) +public class MagicCallActivity extends AppCompatActivity { + private static final String TAG = "MagicCallActivity"; + + @BindView(R.id.controller_container) + ViewGroup container; + + private Router router; + + private static int getSystemUiVisibility() { + int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; + flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + return flags; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject (this); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | + WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility()); + + setContentView(R.layout.activity_magic_call); + ButterKnife.bind(this); + router = Conductor.attachRouter(this, container, savedInstanceState); + router.setPopsLastView(true); + + if (!router.hasRootController()) { + if (getIntent().getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) { + router.setRoot(RouterTransaction.with(new CallNotificationController(getIntent().getExtras())) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } else { + router.setRoot(RouterTransaction.with(new CallController(getIntent().getExtras())) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } + } + } + + @Override + public void onBackPressed() { + if (!router.handleBack()) { + super.onBackPressed(); + } + } + +} diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java similarity index 84% rename from app/src/main/java/com/nextcloud/talk/activities/CallActivity.java rename to app/src/main/java/com/nextcloud/talk/controllers/CallController.java index b28eeb597..a78d7356f 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java @@ -2,7 +2,7 @@ * Nextcloud Talk application * * @author Mario Danic - * Copyright (C) 2017 Mario Danic + * Copyright (C) 2017-2018 Mario Danic * * 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 @@ -16,19 +16,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * Inspired by: - * - Google samples - * - https://github.com/vivek1794/webrtc-android-codelab (MIT licence) */ -package com.nextcloud.talk.activities; +package com.nextcloud.talk.controllers; import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.SuppressLint; -import android.content.res.Configuration; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; @@ -37,10 +32,10 @@ import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.Window; -import android.view.WindowManager; +import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -53,8 +48,8 @@ import com.bumptech.glide.request.RequestOptions; import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.MediaStreamEvent; -import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.events.SessionDescriptionSendEvent; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.call.CallOverall; @@ -112,7 +107,6 @@ import org.webrtc.VideoSource; import org.webrtc.VideoTrack; import java.io.IOException; -import java.net.CookieManager; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -125,7 +119,6 @@ import javax.inject.Inject; import autodagger.AutoInjector; import butterknife.BindView; -import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnLongClick; import eu.davidea.flipview.FlipView; @@ -140,8 +133,10 @@ import okhttp3.Cache; import pub.devrel.easypermissions.AfterPermissionGranted; @AutoInjector(NextcloudTalkApplication.class) -public class CallActivity extends AppCompatActivity { - private static final String TAG = "CallActivity"; +public class CallController extends BaseController { + + private static final String TAG = "CallController"; + private static final String[] PERMISSIONS_CALL = { android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO, @@ -162,7 +157,7 @@ public class CallActivity extends AppCompatActivity { @BindView(R.id.remote_renderers_layout) LinearLayout remoteRenderersLayout; - @BindView(R.id.call_controls) + @BindView(R.id.callControlsLinearLayoutView) LinearLayout callControls; @BindView(R.id.call_control_microphone) FlipView microphoneControlButton; @@ -170,6 +165,11 @@ public class CallActivity extends AppCompatActivity { FlipView cameraControlButton; @BindView(R.id.call_control_switch_camera) FlipView cameraSwitchButton; + @BindView(R.id.connectingRelativeLayoutView) + RelativeLayout connectingView; + + @BindView(R.id.conversationRelativeLayoutView) + RelativeLayout conversationView; @Inject NcApi ncApi; @@ -178,8 +178,6 @@ public class CallActivity extends AppCompatActivity { @Inject UserUtils userUtils; @Inject - CookieManager cookieManager; - @Inject AppPreferences appPreferences; @Inject Cache cache; @@ -216,7 +214,7 @@ public class CallActivity extends AppCompatActivity { private boolean isMultiSession = false; private boolean hasChatSupport = false; private boolean isVoiceOnlyCall = false; - + private boolean isFromNotification; private Handler handler = new Handler(); private boolean isPTTActive = false; @@ -228,58 +226,70 @@ public class CallActivity extends AppCompatActivity { private SpotlightView spotlightView; - - private static int getSystemUiVisibility() { - int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; - flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - return flags; - } - - @SuppressLint("ClickableViewAccessibility") - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + public CallController(Bundle args) { + super(args); NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this); - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | - WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | - WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility()); + roomId = args.getString(BundleKeys.KEY_ROOM_ID, ""); + roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN, ""); + userEntity = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY)); - setContentView(R.layout.activity_call); - ButterKnife.bind(this); + if (userEntity == null) { + userEntity = userUtils.getCurrentUser(); + } - microphoneControlButton.setOnTouchListener(new microphoneButtonTouchListener()); - videoOnClickListener = new videoClickListener(); + callSession = args.getString(BundleKeys.KEY_CALL_SESSION, "0"); + credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); + isVoiceOnlyCall = args.getBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false); + + if (userEntity.getUserId().equals("-1")) { + credentials = null; + } + + baseUrl = args.getString(BundleKeys.KEY_MODIFIED_BASE_URL, ""); + + if (TextUtils.isEmpty(baseUrl)) { + baseUrl = userEntity.getBaseUrl(); + } + + isFromNotification = args.containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL) && TextUtils.isEmpty + (roomToken); + } + + @Override + protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { + return inflater.inflate(R.layout.controller_call, container, false); + } + + private void createCameraEnumerator() { + if (getActivity() != null) { + boolean camera2EnumeratorIsSupported = false; + try { + camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(getActivity()); + } catch (final Throwable throwable) { + Log.w(TAG, "Camera2Enumator threw an error"); + } + + if (camera2EnumeratorIsSupported) { + cameraEnumerator = new Camera2Enumerator(getActivity()); + } else { + cameraEnumerator = new Camera1Enumerator(MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()); + } + } + } + + @Override + protected void onViewBound(@NonNull View view) { + super.onViewBound(view); + + microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener()); + videoOnClickListener = new VideoClickListener(); pulseAnimation = PulseAnimation.create().with(microphoneControlButton.getFrontImageView()) .setDuration(310) .setRepeatCount(PulseAnimation.INFINITE) .setRepeatMode(PulseAnimation.REVERSE); - roomId = getIntent().getExtras().getString(BundleKeys.KEY_ROOM_ID, ""); - roomToken = getIntent().getExtras().getString(BundleKeys.KEY_ROOM_TOKEN, ""); - userEntity = Parcels.unwrap(getIntent().getExtras().getParcelable(BundleKeys.KEY_USER_ENTITY)); - - if (userEntity == null) { - userEntity = userUtils.getCurrentUser(); - } - - callSession = getIntent().getExtras().getString(BundleKeys.KEY_CALL_SESSION, "0"); - credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); - isVoiceOnlyCall = getIntent().getExtras().getBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false); - - if (userEntity.getUserId().equals("-1")) { - credentials = null; - } - - baseUrl = getIntent().getExtras().getString(BundleKeys.KEY_MODIFIED_BASE_URL, ""); - - if (TextUtils.isEmpty(baseUrl)) { - baseUrl = userEntity.getBaseUrl(); - } try { cache.evictAll(); @@ -290,8 +300,7 @@ public class CallActivity extends AppCompatActivity { callControls.setZ(100.0f); basicInitialization(); - if (getIntent().getExtras().containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL) && TextUtils.isEmpty - (roomToken)) { + if (isFromNotification) { handleFromNotification(); } else { initViews(); @@ -299,6 +308,53 @@ public class CallActivity extends AppCompatActivity { } } + private void basicInitialization() { + rootEglBase = EglBase.create(); + createCameraEnumerator(); + + //Create a new PeerConnectionFactory instance. + PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); + peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory(); + + peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.getEglBaseContext(), + rootEglBase.getEglBaseContext()); + + //Create MediaConstraints - Will be useful for specifying video and audio constraints. + audioConstraints = new MediaConstraints(); + videoConstraints = new MediaConstraints(); + + localMediaStream = peerConnectionFactory.createLocalMediaStream("NCMS"); + + // Create and audio manager that will take care of audio routing, + // audio modes, audio device enumeration etc. + audioManager = MagicAudioManager.create(getApplicationContext()); + // Store existing audio settings and change audio mode to + // MODE_IN_COMMUNICATION for best possible VoIP performance. + Log.d(TAG, "Starting the audio manager..."); + audioManager.start(this::onAudioManagerDevicesChanged); + + iceServers = new ArrayList<>(); + + //create sdpConstraints + sdpConstraints = new MediaConstraints(); + sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); + String offerToReceiveVideoString = "true"; + + if (isVoiceOnlyCall) { + offerToReceiveVideoString = "false"; + } + + sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", + offerToReceiveVideoString)); + sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true")); + sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); + + if (!isVoiceOnlyCall) { + cameraInitialization(); + } + microphoneInitialization(); + } + private void handleFromNotification() { ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl)) .retry(3) @@ -335,6 +391,313 @@ public class CallActivity extends AppCompatActivity { }); } + private void initViews() { + if (isVoiceOnlyCall) { + cameraSwitchButton.setVisibility(View.GONE); + cameraControlButton.setVisibility(View.GONE); + pipVideoView.setVisibility(View.GONE); + } else { + if (cameraEnumerator.getDeviceNames().length < 2) { + cameraSwitchButton.setVisibility(View.GONE); + } + + // setting this to true because it's not shown by default + pipVideoView.setMirror(false); + pipVideoView.init(rootEglBase.getEglBaseContext(), null); + pipVideoView.setZOrderMediaOverlay(true); + // disabled because it causes some devices to crash + pipVideoView.setEnableHardwareScaler(false); + pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); + } + } + + + private void checkPermissions() { + if (isVoiceOnlyCall) { + onMicrophoneClick(); + } else if (getActivity() != null) { + EffortlessPermissions.requestPermissions(getActivity(), R.string.nc_permissions, + R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CALL); + } + + } + + @AfterPermissionGranted(100) + private void onPermissionsGranted() { + if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CALL)) { + if (!videoOn && !isVoiceOnlyCall) { + onCameraClick(); + } + + if (!audioOn) { + onMicrophoneClick(); + } + + if (!isVoiceOnlyCall) { + if (cameraEnumerator.getDeviceNames().length == 0) { + cameraControlButton.setVisibility(View.GONE); + } + + if (cameraEnumerator.getDeviceNames().length > 1) { + cameraSwitchButton.setVisibility(View.VISIBLE); + } + } + + if (!inCall) { + startCall(); + } + } else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(), + PERMISSIONS_CALL)) { + checkIfSomeAreApproved(); + } + + } + + private void checkIfSomeAreApproved() { + if (!isVoiceOnlyCall) { + if (cameraEnumerator.getDeviceNames().length == 0) { + cameraControlButton.setVisibility(View.GONE); + } + + if (cameraEnumerator.getDeviceNames().length > 1) { + cameraSwitchButton.setVisibility(View.VISIBLE); + } + + if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA)) { + if (!videoOn) { + onCameraClick(); + } + } else { + cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px); + cameraControlButton.setAlpha(0.7f); + cameraSwitchButton.setVisibility(View.GONE); + } + } + + if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_MICROPHONE)) { + if (!audioOn) { + onMicrophoneClick(); + } + } else { + microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px); + } + + if (!inCall) { + startCall(); + } + } + + @AfterPermissionDenied(100) + private void onPermissionsDenied() { + if (!isVoiceOnlyCall) { + if (cameraEnumerator.getDeviceNames().length == 0) { + cameraControlButton.setVisibility(View.GONE); + } else if (cameraEnumerator.getDeviceNames().length == 1) { + cameraSwitchButton.setVisibility(View.GONE); + } + } + + if (getActivity() != null && (EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA) || + EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_MICROPHONE))) { + checkIfSomeAreApproved(); + } else if (!inCall) { + startCall(); + } + } + + private void onAudioManagerDevicesChanged( + final MagicAudioManager.AudioDevice device, final Set availableDevices) { + Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", " + + "selected: " + device); + } + + private void cameraInitialization() { + videoCapturer = createCameraCapturer(cameraEnumerator); + + //Create a VideoSource instance + if (videoCapturer != null) { + videoSource = peerConnectionFactory.createVideoSource(videoCapturer); + localVideoTrack = peerConnectionFactory.createVideoTrack("NCv0", videoSource); + localMediaStream.addTrack(localVideoTrack); + localVideoTrack.setEnabled(false); + + localVideoTrack.addSink(pipVideoView); + } + + } + + private void microphoneInitialization() { + //create an AudioSource instance + audioSource = peerConnectionFactory.createAudioSource(audioConstraints); + localAudioTrack = peerConnectionFactory.createAudioTrack("NCa0", audioSource); + localAudioTrack.setEnabled(false); + localMediaStream.addTrack(localAudioTrack); + } + + private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { + final String[] deviceNames = enumerator.getDeviceNames(); + + // First, try to find front facing camera + Logging.d(TAG, "Looking for front facing cameras."); + for (String deviceName : deviceNames) { + if (enumerator.isFrontFacing(deviceName)) { + Logging.d(TAG, "Creating front facing camera capturer."); + VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null); + + if (videoCapturer != null) { + return videoCapturer; + } + } + } + + + // Front facing camera not found, try something else + Logging.d(TAG, "Looking for other cameras."); + for (String deviceName : deviceNames) { + if (!enumerator.isFrontFacing(deviceName)) { + Logging.d(TAG, "Creating other camera capturer."); + VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null); + + if (videoCapturer != null) { + pipVideoView.setMirror(false); + return videoCapturer; + } + } + } + + return null; + } + + @OnLongClick(R.id.call_control_microphone) + public boolean onMicrophoneLongClick() { + if (!audioOn) { + handler.removeCallbacksAndMessages(null); + isPTTActive = true; + callControls.setVisibility(View.VISIBLE); + } + + onMicrophoneClick(); + return true; + } + + @OnClick(R.id.call_control_microphone) + public void onMicrophoneClick() { + if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_MICROPHONE)) { + + if (getActivity() != null && !appPreferences.getPushToTalkIntroShown()) { + spotlightView = new SpotlightView.Builder(getActivity()) + .introAnimationDuration(300) + .enableRevealAnimation(true) + .performClick(false) + .fadeinTextDuration(400) + .headingTvColor(getResources().getColor(R.color.colorPrimary)) + .headingTvSize(20) + .headingTvText(getResources().getString(R.string.nc_push_to_talk)) + .subHeadingTvColor(getResources().getColor(R.color.white)) + .subHeadingTvSize(16) + .subHeadingTvText(getResources().getString(R.string.nc_push_to_talk_desc)) + .maskColor(Color.parseColor("#dc000000")) + .target(microphoneControlButton) + .lineAnimDuration(400) + .lineAndArcColor(getResources().getColor(R.color.colorPrimary)) + .enableDismissAfterShown(true) + .dismissOnBackPress(true) + .usageId("pushToTalk") + .show(); + + appPreferences.setPushToTalkIntroShown(true); + } + + if (!isPTTActive) { + audioOn = !audioOn; + + if (audioOn) { + microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px); + } else { + microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px); + } + + toggleMedia(audioOn, false); + } else { + microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px); + pulseAnimation.start(); + toggleMedia(true, false); + } + + if (isVoiceOnlyCall && !inCall) { + startCall(); + } + + } else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(), + PERMISSIONS_MICROPHONE)) { + // Microphone permission is permanently denied so we cannot request it normally. + + OpenAppDetailsDialogFragment.show( + R.string.nc_microphone_permission_permanently_denied, + R.string.nc_permissions_settings, (AppCompatActivity) getActivity()); + } else { + EffortlessPermissions.requestPermissions(getActivity(), R.string.nc_permissions_audio, + R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_MICROPHONE); + } + } + + @OnClick(R.id.call_control_hangup) + public void onHangupClick() { + if (inCall) { + hangup(false); + } else { + hangup(true); + } + } + + @OnClick(R.id.call_control_camera) + public void onCameraClick() { + if (EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA)) { + videoOn = !videoOn; + + if (videoOn) { + cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_white_24px); + if (cameraEnumerator.getDeviceNames().length > 1) { + cameraSwitchButton.setVisibility(View.VISIBLE); + } + } else { + cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px); + cameraSwitchButton.setVisibility(View.GONE); + } + + toggleMedia(videoOn, true); + } else if (getActivity() != null && EffortlessPermissions.somePermissionPermanentlyDenied(getActivity(), + PERMISSIONS_CAMERA)) { + // Camera permission is permanently denied so we cannot request it normally. + OpenAppDetailsDialogFragment.show( + R.string.nc_camera_permission_permanently_denied, + R.string.nc_permissions_settings, (AppCompatActivity) getActivity()); + } else { + if (getActivity() != null) { + EffortlessPermissions.requestPermissions(getActivity(), R.string.nc_permissions_video, + R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CAMERA); + } + } + + } + + @OnClick(R.id.call_control_switch_camera) + public void switchCamera() { + CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer; + if (cameraVideoCapturer != null) { + cameraVideoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() { + @Override + public void onCameraSwitchDone(boolean b) { + pipVideoView.setMirror(false); + } + + @Override + public void onCameraSwitchError(String s) { + + } + }); + } + } private void toggleMedia(boolean enable, boolean video) { String message; @@ -385,371 +748,6 @@ public class CallActivity extends AppCompatActivity { } } - @OnLongClick(R.id.call_control_microphone) - public boolean onMicrophoneLongClick() { - if (!audioOn) { - handler.removeCallbacksAndMessages(null); - isPTTActive = true; - callControls.setVisibility(View.VISIBLE); - } - - onMicrophoneClick(); - return true; - } - - @OnClick(R.id.call_control_microphone) - public void onMicrophoneClick() { - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { - - if (!appPreferences.getPushToTalkIntroShown()) { - spotlightView = new SpotlightView.Builder(this) - .introAnimationDuration(300) - .enableRevealAnimation(true) - .performClick(false) - .fadeinTextDuration(400) - .headingTvColor(getResources().getColor(R.color.colorPrimary)) - .headingTvSize(20) - .headingTvText(getString(R.string.nc_push_to_talk)) - .subHeadingTvColor(getResources().getColor(R.color.white)) - .subHeadingTvSize(16) - .subHeadingTvText(getString(R.string.nc_push_to_talk_desc)) - .maskColor(Color.parseColor("#dc000000")) - .target(microphoneControlButton) - .lineAnimDuration(400) - .lineAndArcColor(getResources().getColor(R.color.colorPrimary)) - .enableDismissAfterShown(true) - .dismissOnBackPress(true) - .usageId("pushToTalk") - .show(); - - appPreferences.setPushToTalkIntroShown(true); - } - - if (!isPTTActive) { - audioOn = !audioOn; - - if (audioOn) { - microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px); - } else { - microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px); - } - - toggleMedia(audioOn, false); - } else { - microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px); - pulseAnimation.start(); - toggleMedia(true, false); - } - - if (isVoiceOnlyCall && !inCall) { - startCall(); - } - - } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_MICROPHONE)) { - // Microphone permission is permanently denied so we cannot request it normally. - OpenAppDetailsDialogFragment.show( - R.string.nc_microphone_permission_permanently_denied, - R.string.nc_permissions_settings, this); - } else { - EffortlessPermissions.requestPermissions(this, R.string.nc_permissions_audio, - R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_MICROPHONE); - } - } - - @OnClick(R.id.call_control_hangup) - public void onHangupClick() { - if (inCall) { - hangup(false); - } else { - hangup(true); - } - } - - @OnClick(R.id.call_control_camera) - public void onCameraClick() { - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { - videoOn = !videoOn; - - if (videoOn) { - cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_white_24px); - if (cameraEnumerator.getDeviceNames().length > 1) { - cameraSwitchButton.setVisibility(View.VISIBLE); - } - } else { - cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px); - cameraSwitchButton.setVisibility(View.GONE); - } - - toggleMedia(videoOn, true); - } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, PERMISSIONS_CAMERA)) { - // Camera permission is permanently denied so we cannot request it normally. - OpenAppDetailsDialogFragment.show( - R.string.nc_camera_permission_permanently_denied, - R.string.nc_permissions_settings, this); - } else { - EffortlessPermissions.requestPermissions(this, R.string.nc_permissions_video, - R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CAMERA); - } - - } - - - @OnClick(R.id.call_control_switch_camera) - public void switchCamera() { - CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer; - if (cameraVideoCapturer != null) { - cameraVideoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() { - @Override - public void onCameraSwitchDone(boolean b) { - pipVideoView.setMirror(false); - } - - @Override - public void onCameraSwitchError(String s) { - - } - }); - } - } - - private void createCameraEnumerator() { - boolean camera2EnumeratorIsSupported = false; - try { - camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(this); - } catch (final Throwable throwable) { - Log.w(TAG, "Camera2Enumator threw an error"); - } - - if (camera2EnumeratorIsSupported) { - cameraEnumerator = new Camera2Enumerator(this); - } else { - cameraEnumerator = new Camera1Enumerator(MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()); - } - } - - private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { - final String[] deviceNames = enumerator.getDeviceNames(); - - // First, try to find front facing camera - Logging.d(TAG, "Looking for front facing cameras."); - for (String deviceName : deviceNames) { - if (enumerator.isFrontFacing(deviceName)) { - Logging.d(TAG, "Creating front facing camera capturer."); - VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null); - - if (videoCapturer != null) { - return videoCapturer; - } - } - } - - - // Front facing camera not found, try something else - Logging.d(TAG, "Looking for other cameras."); - for (String deviceName : deviceNames) { - if (!enumerator.isFrontFacing(deviceName)) { - Logging.d(TAG, "Creating other camera capturer."); - VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null); - - if (videoCapturer != null) { - pipVideoView.setMirror(false); - return videoCapturer; - } - } - } - - return null; - } - - public void initViews() { - if (isVoiceOnlyCall) { - cameraSwitchButton.setVisibility(View.GONE); - cameraControlButton.setVisibility(View.GONE); - pipVideoView.setVisibility(View.GONE); - } else { - if (cameraEnumerator.getDeviceNames().length < 2) { - cameraSwitchButton.setVisibility(View.GONE); - } - - // setting this to true because it's not shown by default - pipVideoView.setMirror(false); - pipVideoView.init(rootEglBase.getEglBaseContext(), null); - pipVideoView.setZOrderMediaOverlay(true); - // disabled because it causes some devices to crash - pipVideoView.setEnableHardwareScaler(false); - pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); - } - } - - private void checkPermissions() { - if (isVoiceOnlyCall) { - onMicrophoneClick(); - } else { - EffortlessPermissions.requestPermissions(this, R.string.nc_permissions, - R.string.nc_proceed, R.string.nc_empty, 100, PERMISSIONS_CALL); - } - - } - - @AfterPermissionGranted(100) - private void onPermissionsGranted() { - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CALL)) { - if (!videoOn && !isVoiceOnlyCall) { - onCameraClick(); - } - - if (!audioOn) { - onMicrophoneClick(); - } - - if (!isVoiceOnlyCall) { - if (cameraEnumerator.getDeviceNames().length == 0) { - cameraControlButton.setVisibility(View.GONE); - } - - if (cameraEnumerator.getDeviceNames().length > 1) { - cameraSwitchButton.setVisibility(View.VISIBLE); - } - } - - if (!inCall) { - startCall(); - } - } else if (EffortlessPermissions.somePermissionPermanentlyDenied(this, - PERMISSIONS_CALL)) { - checkIfSomeAreApproved(); - } - - } - - private void checkIfSomeAreApproved() { - if (!isVoiceOnlyCall) { - if (cameraEnumerator.getDeviceNames().length == 0) { - cameraControlButton.setVisibility(View.GONE); - } - - if (cameraEnumerator.getDeviceNames().length > 1) { - cameraSwitchButton.setVisibility(View.VISIBLE); - } - - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { - if (!videoOn) { - onCameraClick(); - } - } else { - cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px); - cameraControlButton.setAlpha(0.7f); - cameraSwitchButton.setVisibility(View.GONE); - } - } - - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { - if (!audioOn) { - onMicrophoneClick(); - } - } else { - microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px); - } - - if (!inCall) { - startCall(); - } - } - - @AfterPermissionDenied(100) - private void onPermissionsDenied() { - if (!isVoiceOnlyCall) { - if (cameraEnumerator.getDeviceNames().length == 0) { - cameraControlButton.setVisibility(View.GONE); - } else if (cameraEnumerator.getDeviceNames().length == 1) { - cameraSwitchButton.setVisibility(View.GONE); - } - } - - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) || - EffortlessPermissions.hasPermissions(this, PERMISSIONS_MICROPHONE)) { - checkIfSomeAreApproved(); - } else if (!inCall) { - startCall(); - } - } - - private void basicInitialization() { - rootEglBase = EglBase.create(); - createCameraEnumerator(); - - //Create a new PeerConnectionFactory instance. - PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); - peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory(); - - peerConnectionFactory.setVideoHwAccelerationOptions(rootEglBase.getEglBaseContext(), - rootEglBase.getEglBaseContext()); - - //Create MediaConstraints - Will be useful for specifying video and audio constraints. - audioConstraints = new MediaConstraints(); - videoConstraints = new MediaConstraints(); - - localMediaStream = peerConnectionFactory.createLocalMediaStream("NCMS"); - - // Create and audio manager that will take care of audio routing, - // audio modes, audio device enumeration etc. - audioManager = MagicAudioManager.create(getApplicationContext()); - // Store existing audio settings and change audio mode to - // MODE_IN_COMMUNICATION for best possible VoIP performance. - Log.d(TAG, "Starting the audio manager..."); - audioManager.start(new MagicAudioManager.AudioManagerEvents() { - @Override - public void onAudioDeviceChanged(MagicAudioManager.AudioDevice selectedAudioDevice, - Set availableAudioDevices) { - onAudioManagerDevicesChanged(selectedAudioDevice, availableAudioDevices); - } - }); - - iceServers = new ArrayList<>(); - - //create sdpConstraints - sdpConstraints = new MediaConstraints(); - sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); - String offerToReceiveVideoString = "true"; - - if (isVoiceOnlyCall) { - offerToReceiveVideoString = "false"; - } - - sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", - offerToReceiveVideoString)); - sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true")); - sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); - - if (!isVoiceOnlyCall) { - cameraInitialization(); - } - microphoneInitialization(); - } - - private void cameraInitialization() { - videoCapturer = createCameraCapturer(cameraEnumerator); - - //Create a VideoSource instance - if (videoCapturer != null) { - videoSource = peerConnectionFactory.createVideoSource(videoCapturer); - localVideoTrack = peerConnectionFactory.createVideoTrack("NCv0", videoSource); - localMediaStream.addTrack(localVideoTrack); - localVideoTrack.setEnabled(false); - - localVideoTrack.addSink(pipVideoView); - } - - } - - private void microphoneInitialization() { - //create an AudioSource instance - audioSource = peerConnectionFactory.createAudioSource(audioConstraints); - localAudioTrack = peerConnectionFactory.createAudioTrack("NCa0", audioSource); - localAudioTrack.setEnabled(false); - localMediaStream.addTrack(localAudioTrack); - } - private void startCall() { if (!isPTTActive) { animateCallControls(false, 7500); @@ -757,9 +755,73 @@ public class CallActivity extends AppCompatActivity { startPullingSignalingMessages(); } - @OnClick({R.id.pip_video_view, R.id.remote_renderers_layout}) - public void showCallControls() { - animateCallControls(true, 0); + private void animateCallControls(boolean show, long startDelay) { + if (!isPTTActive) { + float alpha; + long duration; + + if (show) { + handler.removeCallbacksAndMessages(null); + alpha = 1.0f; + duration = 1000; + if (callControls.getVisibility() != View.VISIBLE) { + callControls.setAlpha(0.0f); + callControls.setVisibility(View.VISIBLE); + } else { + handler.postDelayed(new Runnable() { + @Override + public void run() { + animateCallControls(false, 0); + + } + }, 5000); + return; + } + } else { + alpha = 0.0f; + duration = 1000; + } + + if (callControls != null) { + callControls.setEnabled(false); + callControls.animate() + .translationY(0) + .alpha(alpha) + .setDuration(duration) + .setStartDelay(startDelay) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (callControls != null) { + if (!show) { + callControls.setVisibility(View.GONE); + if (spotlightView != null && spotlightView.getVisibility() != View.GONE) { + spotlightView.setVisibility(View.GONE); + } + } else { + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (!isPTTActive) { + animateCallControls(false, 0); + } + } + }, 7500); + } + + callControls.setEnabled(true); + } + } + }); + } + } + } + + @Override + public void onDestroy() { + onHangupClick(); + super.onDestroy(); } public void startPullingSignalingMessages() { @@ -825,12 +887,6 @@ public class CallActivity extends AppCompatActivity { }); } - private void startVideoCapture() { - if (videoCapturer != null) { - videoCapturer.startCapture(1280, 720, 30); - } - } - private void checkCapabilities() { ncApi.getCapabilities(credentials, ApiUtils.getUrlForCapabilities(baseUrl)) .retry(3) @@ -926,6 +982,8 @@ public class CallActivity extends AppCompatActivity { public void onNext(GenericOverall genericOverall) { inCall = true; + connectingView.setVisibility(View.GONE); + conversationView.setVisibility(View.VISIBLE); // start pinging the call if (!hasChatSupport) { @@ -1020,6 +1078,28 @@ public class CallActivity extends AppCompatActivity { }); } + @OnClick({R.id.pip_video_view, R.id.remote_renderers_layout}) + public void showCallControls() { + animateCallControls(true, 0); + } + + private void dispose(@Nullable Disposable disposable) { + if (disposable != null && !disposable.isDisposed()) { + disposable.dispose(); + } else if (disposable == null) { + + if (pingDisposable != null && !pingDisposable.isDisposed()) { + pingDisposable.dispose(); + pingDisposable = null; + } + + if (signalingDisposable != null && !signalingDisposable.isDisposed()) { + signalingDisposable.dispose(); + signalingDisposable = null; + } + } + } + private void receivedSignalingMessage(Signaling signaling) throws IOException { String messageType = signaling.getType(); @@ -1083,12 +1163,127 @@ public class CallActivity extends AppCompatActivity { } } - // This method is called when the audio manager reports audio device change, - // e.g. from wired headset to speakerphone. - private void onAudioManagerDevicesChanged( - final MagicAudioManager.AudioDevice device, final Set availableDevices) { - Log.d(TAG, "onAudioManagerDevicesChanged: " + availableDevices + ", " - + "selected: " + device); + private void hangup(boolean dueToNetworkChange) { + + leavingCall = true; + inCall = false; + + if (videoCapturer != null) { + try { + videoCapturer.stopCapture(); + } catch (InterruptedException e) { + Log.e(TAG, "Failed to stop capturing while hanging up"); + } + videoCapturer.dispose(); + videoCapturer = null; + } + + for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) { + endPeerConnection(magicPeerConnectionWrapperList.get(i).getSessionId()); + + } + + if (pipVideoView != null) { + pipVideoView.release(); + } + + if (audioSource != null) { + audioSource.dispose(); + audioSource = null; + } + + if (audioManager != null) { + audioManager.stop(); + audioManager = null; + } + + if (videoSource != null) { + videoSource = null; + } + + if (peerConnectionFactory != null) { + peerConnectionFactory = null; + } + + localMediaStream = null; + localAudioTrack = null; + localVideoTrack = null; + + if (!dueToNetworkChange) { + hangupNetworkCalls(); + } else { + if (getActivity() != null) { + getActivity().finish(); + } + } + } + + private void hangupNetworkCalls() { + ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(GenericOverall genericOverall) { + if (isMultiSession) { + if (getActivity() != null) { + getActivity().finish(); + } + } else { + leaveRoom(); + } + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } + + private void leaveRoom() { + ncApi.leaveRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(baseUrl, roomToken)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(GenericOverall genericOverall) { + if (getActivity() != null) { + getActivity().finish(); + } + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } + + private void startVideoCapture() { + if (videoCapturer != null) { + videoCapturer.startCapture(1280, 720, 30); + } } private void processUsersInRoom(List> users) { @@ -1133,7 +1328,6 @@ public class CallActivity extends AppCompatActivity { } } - private void getPeersForCall() { ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) .subscribeOn(Schedulers.newThread()) @@ -1148,7 +1342,9 @@ public class CallActivity extends AppCompatActivity { participantMap = new HashMap<>(); for (Participant participant : participantsOverall.getOcs().getData()) { participantMap.put(participant.getSessionId(), participant); - runOnUiThread(() -> setupAvatarForSession(participant.getSessionId())); + if (getActivity() != null) { + getActivity().runOnUiThread(() -> setupAvatarForSession(participant.getSessionId())); + } } } @@ -1190,317 +1386,11 @@ public class CallActivity extends AppCompatActivity { return null; } - private void hangup(boolean dueToNetworkChange) { - - leavingCall = true; - inCall = false; - - if (videoCapturer != null) { - try { - videoCapturer.stopCapture(); - } catch (InterruptedException e) { - Log.e(TAG, "Failed to stop capturing while hanging up"); - } - videoCapturer.dispose(); - videoCapturer = null; - } - - for (int i = 0; i < magicPeerConnectionWrapperList.size(); i++) { - endPeerConnection(magicPeerConnectionWrapperList.get(i).getSessionId()); - - } - - pipVideoView.release(); - - if (audioSource != null) { - audioSource.dispose(); - audioSource = null; - } - - if (audioManager != null) { - audioManager.stop(); - audioManager = null; - } - - if (videoSource != null) { - videoSource = null; - } - - if (peerConnectionFactory != null) { - peerConnectionFactory = null; - } - - localMediaStream = null; - localAudioTrack = null; - localVideoTrack = null; - - if (!dueToNetworkChange) { - hangupNetworkCalls(); - } else { - finish(); - } - } - - private void leaveRoom() { - ncApi.leaveRoom(credentials, ApiUtils.getUrlForSettingMyselfAsActiveParticipant(baseUrl, roomToken)) - .subscribeOn(Schedulers.newThread()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(GenericOverall genericOverall) { - finish(); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - } - - private void hangupNetworkCalls() { - ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) - .subscribeOn(Schedulers.newThread()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(GenericOverall genericOverall) { - if (isMultiSession) { - finish(); - } else { - leaveRoom(); - } - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - } - - private void gotNick(String sessionId, String nick) { - RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); - if (relativeLayout != null) { - TextView textView = relativeLayout.findViewById(R.id.peer_nick_text_view); - textView.setText(nick); - } - } - - private void gotAudioOrVideoChange(boolean video, String sessionId, boolean change) { - RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); - if (relativeLayout != null) { - ImageView imageView; - ImageView 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 setupAvatarForSession(String session) { - RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session); - if (relativeLayout != null) { - ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView); - - if (participantMap.containsKey(session) && avatarImageView.getDrawable() == null) { - - int size = Math.round(getResources().getDimension(R.dimen.avatar_size_big)); - - GlideApp.with(this) - .asBitmap() - .diskCacheStrategy(DiskCacheStrategy.NONE) - .load(ApiUtils.getUrlForAvatarWithName(baseUrl, participantMap.get(session).getUserId(), R.dimen.avatar_size_big)) - .centerInside() - .override(size, size) - .apply(RequestOptions.bitmapTransform(new CircleCrop())) - .into(avatarImageView); - } - } - } - - private void setupNewPeerLayout(String session) { - if (remoteRenderersLayout.findViewWithTag(session) == null) { - runOnUiThread(() -> { - RelativeLayout relativeLayout = (RelativeLayout) - getLayoutInflater().inflate(R.layout.call_item, remoteRenderersLayout, - false); - relativeLayout.setTag(session); - 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); - gotNick(session, getPeerConnectionWrapperForSessionId(session).getNick()); - setupAvatarForSession(session); - - callControls.setZ(100.0f); - }); - } - } - - private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean enable) { - boolean isInitialLayoutSetupForPeer = false; - if (remoteRenderersLayout.findViewWithTag(session) == null) { - setupNewPeerLayout(session); - isInitialLayoutSetupForPeer = true; - } - - RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session); - SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view); - ImageView 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); - } - } - - callControls.setZ(100.0f); - } - - @Override - public void onDestroy() { - if (inCall) { - hangup(false); - } - - if (hasChatSupport) { - ApplicationWideCurrentRoomHolder.getInstance().setInCall(false); - } else { - ApplicationWideCurrentRoomHolder.getInstance().clear(); - } - //this.unregisterReceiver(networkBroadcastReceier); - rootEglBase.release(); - super.onDestroy(); - } - - private void dispose(@Nullable Disposable disposable) { - if (disposable != null && !disposable.isDisposed()) { - disposable.dispose(); - } else if (disposable == null) { - - if (pingDisposable != null && !pingDisposable.isDisposed()) { - pingDisposable.dispose(); - pingDisposable = null; - } - - if (signalingDisposable != null && !signalingDisposable.isDisposed()) { - signalingDisposable.dispose(); - signalingDisposable = null; - } - } - } - - @Override - public void onStart() { - super.onStart(); - eventBus.register(this); - if (videoOn && EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { - startVideoCapture(); - } - } - - @Override - public void onStop() { - super.onStop(); - eventBus.unregister(this); - if (videoCapturer != null && EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA)) { - try { - videoCapturer.stopCapture(); - } catch (InterruptedException e) { - Log.e(TAG, "Failed to stop the capturing process"); - } - } - } - - @Subscribe(threadMode = ThreadMode.BACKGROUND) - public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { - if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent.PeerConnectionEventType - .PEER_CLOSED)) { - endPeerConnection(peerConnectionEvent.getSessionId()); - } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.SENSOR_FAR) || - peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.SENSOR_NEAR)) { - boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.SENSOR_FAR) && videoOn; - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && inCall && videoOn - && enableVideo != localVideoTrack.enabled()) { - runOnUiThread(() -> toggleMedia(enableVideo, true)); - } - } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.NICK_CHANGE)) { - runOnUiThread(() -> gotNick(peerConnectionEvent.getSessionId(), peerConnectionEvent.getNick())); - } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.VIDEO_CHANGE) && !isVoiceOnlyCall) { - runOnUiThread(() -> gotAudioOrVideoChange(true, peerConnectionEvent.getSessionId(), - peerConnectionEvent.getChangeValue())); - } else if (peerConnectionEvent.getPeerConnectionEventType().equals(PeerConnectionEvent - .PeerConnectionEventType.AUDIO_CHANGE)) { - runOnUiThread(() -> gotAudioOrVideoChange(false, peerConnectionEvent.getSessionId(), - peerConnectionEvent.getChangeValue())); - } - } - private void endPeerConnection(String sessionId) { MagicPeerConnectionWrapper magicPeerConnectionWrapper; - if ((magicPeerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null) { - runOnUiThread(() -> removeMediaStream(sessionId)); + if ((magicPeerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null && getActivity() + != null) { + getActivity().runOnUiThread(() -> removeMediaStream(sessionId)); deleteMagicPeerConnection(magicPeerConnectionWrapper); } } @@ -1610,19 +1500,6 @@ public class CallActivity extends AppCompatActivity { }); } - @Override - public void onConfigurationChanged(Configuration newConfig) { - - // Checks the orientation of the screen - if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { - remoteRenderersLayout.setOrientation(LinearLayout.HORIZONTAL); - } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { - remoteRenderersLayout.setOrientation(LinearLayout.VERTICAL); - } - - super.onConfigurationChanged(newConfig); - } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -1632,73 +1509,135 @@ public class CallActivity extends AppCompatActivity { this); } - private void animateCallControls(boolean show, long startDelay) { - if (!isPTTActive) { - float alpha; - long duration; + private void setupAvatarForSession(String session) { + RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session); + if (relativeLayout != null) { + ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView); - if (show) { - handler.removeCallbacksAndMessages(null); - alpha = 1.0f; - duration = 1000; - if (callControls.getVisibility() != View.VISIBLE) { - callControls.setAlpha(0.0f); - callControls.setVisibility(View.VISIBLE); + if (participantMap.containsKey(session) && avatarImageView.getDrawable() == null) { + + int size = Math.round(getResources().getDimension(R.dimen.avatar_size_big)); + + if (getActivity() != null) { + GlideApp.with(getActivity()) + .asBitmap() + .diskCacheStrategy(DiskCacheStrategy.NONE) + .load(ApiUtils.getUrlForAvatarWithName(baseUrl, participantMap.get(session).getUserId(), R.dimen.avatar_size_big)) + .centerInside() + .override(size, size) + .apply(RequestOptions.bitmapTransform(new CircleCrop())) + .into(avatarImageView); + } + } + } + } + + private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, boolean enable) { + boolean isInitialLayoutSetupForPeer = false; + if (remoteRenderersLayout.findViewWithTag(session) == null) { + setupNewPeerLayout(session); + isInitialLayoutSetupForPeer = true; + } + + RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session); + SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view); + ImageView 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); + } + } + + callControls.setZ(100.0f); + } + + private void gotAudioOrVideoChange(boolean video, String sessionId, boolean change) { + RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); + if (relativeLayout != null) { + ImageView imageView; + ImageView 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 { - handler.postDelayed(new Runnable() { - @Override - public void run() { - animateCallControls(false, 0); - - } - }, 5000); - return; + avatarImageView.setVisibility(View.VISIBLE); + surfaceViewRenderer.setVisibility(View.INVISIBLE); } } else { - alpha = 0.0f; - duration = 1000; + imageView = relativeLayout.findViewById(R.id.remote_audio_off); } - callControls.setEnabled(false); - callControls.animate() - .translationY(0) - .alpha(alpha) - .setDuration(duration) - .setStartDelay(startDelay) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - if (callControls != null) { - if (!show) { - callControls.setVisibility(View.GONE); - if (spotlightView != null && spotlightView.getVisibility() != View.GONE) { - spotlightView.setVisibility(View.GONE); - } - } else { - handler.postDelayed(new Runnable() { - @Override - public void run() { - if (!isPTTActive) { - animateCallControls(false, 0); - } - } - }, 7500); - } + if (change && imageView.getVisibility() != View.INVISIBLE) { + imageView.setVisibility(View.INVISIBLE); + } else if (!change && imageView.getVisibility() != View.VISIBLE) { + imageView.setVisibility(View.VISIBLE); + } + } + } - callControls.setEnabled(true); - } - } - }); + private void setupNewPeerLayout(String session) { + if (remoteRenderersLayout.findViewWithTag(session) == null && getActivity() != null) { + getActivity().runOnUiThread(() -> { + RelativeLayout relativeLayout = (RelativeLayout) + getActivity().getLayoutInflater().inflate(R.layout.call_item, remoteRenderersLayout, + false); + relativeLayout.setTag(session); + 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); + gotNick(session, getPeerConnectionWrapperForSessionId(session).getNick()); + setupAvatarForSession(session); + + callControls.setZ(100.0f); + }); + } + } + + private void gotNick(String sessionId, String nick) { + RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); + if (relativeLayout != null) { + TextView textView = relativeLayout.findViewById(R.id.peer_nick_text_view); + textView.setText(nick); } } @Override - public void onBackPressed() { - onHangupClick(); + protected void onAttach(@NonNull View view) { + super.onAttach(view); + eventBus.register(this); } - private class microphoneButtonTouchListener implements View.OnTouchListener { + @Override + protected void onDetach(@NonNull View view) { + super.onDetach(view); + eventBus.unregister(this); + } + + private class MicrophoneButtonTouchListener implements View.OnTouchListener { @SuppressLint("ClickableViewAccessibility") @Override @@ -1715,11 +1654,11 @@ public class CallActivity extends AppCompatActivity { } } - private class videoClickListener implements View.OnClickListener { + private class VideoClickListener implements View.OnClickListener { @Override public void onClick(View v) { showCallControls(); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java index db0935c28..13de6bcd5 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java @@ -117,7 +117,10 @@ public class CallNotificationController extends BaseController { @OnClick(R.id.callControlHangupView) void hangup() { leavingScreen = true; - getRouter().popCurrentController(); + + if (getActivity() != null) { + getActivity().finish(); + } } @OnClick(R.id.callAnswerCameraView) @@ -135,12 +138,9 @@ public class CallNotificationController extends BaseController { private void setBackstackAndProceed() { originalBundle.putString(BundleKeys.KEY_ROOM_TOKEN, currentRoom.getToken()); - List routerTransactions = new ArrayList<>(); - routerTransactions.add(RouterTransaction.with(new MagicBottomNavigationController()) - .popChangeHandler(new HorizontalChangeHandler()).pushChangeHandler(new HorizontalChangeHandler())); - routerTransactions.add(RouterTransaction.with(new ChatController(originalBundle)).popChangeHandler(new - HorizontalChangeHandler()).pushChangeHandler(new HorizontalChangeHandler())); - getRouter().setBackstack(routerTransactions, new HorizontalChangeHandler()); + getRouter().setRoot(RouterTransaction.with(new CallController(originalBundle)) + .popChangeHandler(new HorizontalChangeHandler()) + .pushChangeHandler(new HorizontalChangeHandler())); } private void checkIfAnyParticipantsRemainInRoom() { @@ -235,8 +235,6 @@ public class CallNotificationController extends BaseController { protected void onViewBound(@NonNull View view) { super.onViewBound(view); - getActionBar().hide(); - handleFromNotification(); String callRingtonePreferenceString = appPreferences.getCallRingtoneUri(); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java index ca5fb2b3c..e97791a50 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java @@ -50,7 +50,7 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler; import com.kennyc.bottomsheet.BottomSheet; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.adapters.items.CallItem; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; @@ -508,7 +508,7 @@ public class CallsListController extends BaseController implements SearchView.On } else { overridePushHandler(new NoOpControllerChangeHandler()); overridePopHandler(new NoOpControllerChangeHandler()); - Intent callIntent = new Intent(getActivity(), CallActivity.class); + Intent callIntent = new Intent(getActivity(), MagicCallActivity.class); callIntent.putExtras(bundle); startActivity(callIntent); } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.java b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.java index 6a5acded7..7df10c678 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.java @@ -56,7 +56,7 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder; import com.nextcloud.talk.adapters.messages.MagicOutcomingTextMessageViewHolder; import com.nextcloud.talk.api.NcApi; @@ -831,7 +831,7 @@ public class ChatController extends BaseController implements MessagesListAdapte bundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true); } - Intent callIntent = new Intent(getActivity(), CallActivity.class); + Intent callIntent = new Intent(getActivity(), MagicCallActivity.class); callIntent.putExtras(bundle); return callIntent; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java index 4d346cb54..8227bb909 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -51,7 +51,7 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.kennyc.bottomsheet.BottomSheet; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.adapters.items.ProgressItem; import com.nextcloud.talk.adapters.items.UserHeaderItem; import com.nextcloud.talk.adapters.items.UserItem; @@ -295,7 +295,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ @Override public void onNext(RoomOverall roomOverall) { - Intent conversationIntent = new Intent(getActivity(), CallActivity.class); + Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class); Bundle bundle = new Bundle(); bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.getOcs().getData().getToken()); bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.getOcs().getData().getRoomId()); @@ -828,7 +828,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ @Override public void onNext(RoomOverall roomOverall) { if (getActivity() != null) { - Intent conversationIntent = new Intent(getActivity(), CallActivity.class); + Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class); Bundle bundle = new Bundle(); bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.getOcs().getData().getToken()); bundle.putString(BundleKeys.KEY_ROOM_ID, roomOverall.getOcs().getData().getRoomId()); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java index 6f4e5949b..6d1056d3f 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java @@ -92,7 +92,7 @@ public abstract class BaseController extends RefWatchingController { @Override protected void onAttach(@NonNull View view) { setTitle(); - if (!MagicBottomNavigationController.class.getName().equals(getClass().getName())) { + if (!MagicBottomNavigationController.class.getName().equals(getClass().getName()) && getActionBar() != null) { getActionBar().setDisplayHomeAsUpEnabled(false); } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java index c9a920311..6a5d539d6 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java @@ -40,7 +40,7 @@ import android.widget.TextView; import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.ChatController; @@ -542,7 +542,7 @@ public class OperationsMenuController extends BaseController { eventBus.post(new BottomSheetLockEvent(true, 0, true, true, dismissView)); - Intent conversationIntent = new Intent(getActivity(), CallActivity.class); + Intent conversationIntent = new Intent(getActivity(), MagicCallActivity.class); bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken()); bundle.putString(BundleKeys.KEY_ROOM_ID, room.getRoomId()); bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, room.getDisplayName()); @@ -582,7 +582,7 @@ public class OperationsMenuController extends BaseController { if (getActivity() != null) { - Intent callIntent = new Intent(getActivity(), CallActivity.class); + Intent callIntent = new Intent(getActivity(), MagicCallActivity.class); callIntent.putExtras(bundle); InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java b/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java index c8860e8e2..96a1a8384 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java @@ -26,10 +26,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.MediaPlayer; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.text.TextUtils; @@ -40,14 +37,13 @@ import com.bluelinelabs.logansquare.LoganSquare; import com.evernote.android.job.Job; import com.evernote.android.job.util.support.PersistableBundleCompat; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.activities.MagicCallActivity; import com.nextcloud.talk.activities.MainActivity; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.models.RingtoneSettings; import com.nextcloud.talk.models.SignatureVerification; import com.nextcloud.talk.models.json.push.DecryptedPushMessage; import com.nextcloud.talk.utils.ApplicationWideCurrentRoomHolder; -import com.nextcloud.talk.utils.NotificationUtils; import com.nextcloud.talk.utils.PushUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; @@ -59,8 +55,6 @@ import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.util.Calendar; -import java.util.zip.CRC32; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; @@ -129,10 +123,11 @@ public class NotificationJob extends Job { Bundle bundle = new Bundle(); - if (hasChatSupport) { - intent = new Intent(context, MainActivity.class); + boolean startACall = decryptedPushMessage.getType().equals("call") || !hasChatSupport; + if (startACall) { + intent = new Intent(context, MagicCallActivity.class); } else { - intent = new Intent(context, CallActivity.class); + intent = new Intent(context, MainActivity.class); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -141,7 +136,7 @@ public class NotificationJob extends Job { .getUserEntity())); bundle.putBoolean(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, - decryptedPushMessage.getType().equals("call") || !hasChatSupport); + startACall); intent.putExtras(bundle); @@ -154,8 +149,7 @@ public class NotificationJob extends Job { String ringtonePreferencesString; switch (decryptedPushMessage.getType()) { case "call": - smallIcon = R.drawable.ic_call_white_24dp; - category = Notification.CATEGORY_CALL; + getContext().startActivity(intent); break; case "room": smallIcon = R.drawable.ic_notifications_white_24dp; @@ -183,7 +177,7 @@ public class NotificationJob extends Job { smallIcon = R.drawable.ic_logo; } - largeIcon = BitmapFactory.decodeResource(context.getResources(), smallIcon); + /*largeIcon = BitmapFactory.decodeResource(context.getResources(), smallIcon); CRC32 crc32 = new CRC32(); Notification.Builder notificationBuilder = new Notification.Builder(context) @@ -258,7 +252,7 @@ public class NotificationJob extends Job { mediaPlayer.setOnCompletionListener(MediaPlayer::release); } - } + }*/ } } diff --git a/app/src/main/res/layout/activity_magic_call.xml b/app/src/main/res/layout/activity_magic_call.xml new file mode 100644 index 000000000..acc95508e --- /dev/null +++ b/app/src/main/res/layout/activity_magic_call.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/controller_call.xml b/app/src/main/res/layout/controller_call.xml new file mode 100644 index 000000000..9c58dc482 --- /dev/null +++ b/app/src/main/res/layout/controller_call.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e91b71e18..0747453c4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,6 +114,7 @@ Open settings + Connecting… Incoming call from Guest New public conversation