diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f95aa544..7fbe05f5b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,5 +66,10 @@ android:configChanges="orientation|screenSize" android:launchMode="singleTask"/> + + + + + diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java index a78d7356f..2bcd45904 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java @@ -102,7 +102,6 @@ import org.webrtc.RendererCommon; import org.webrtc.SessionDescription; import org.webrtc.SurfaceViewRenderer; import org.webrtc.VideoCapturer; -import org.webrtc.VideoRenderer; import org.webrtc.VideoSource; import org.webrtc.VideoTrack; @@ -165,6 +164,7 @@ public class CallController extends BaseController { FlipView cameraControlButton; @BindView(R.id.call_control_switch_camera) FlipView cameraSwitchButton; + @BindView(R.id.connectingRelativeLayoutView) RelativeLayout connectingView; @@ -182,23 +182,22 @@ public class CallController extends BaseController { @Inject Cache cache; - PeerConnectionFactory peerConnectionFactory; - MediaConstraints audioConstraints; - MediaConstraints videoConstraints; - MediaConstraints sdpConstraints; - MagicAudioManager audioManager; - VideoSource videoSource; - VideoTrack localVideoTrack; - AudioSource audioSource; - AudioTrack localAudioTrack; - VideoCapturer videoCapturer; - VideoRenderer localRenderer; - EglBase rootEglBase; - boolean leavingCall = false; - boolean inCall = false; - Disposable signalingDisposable; - Disposable pingDisposable; - List iceServers; + private PeerConnectionFactory peerConnectionFactory; + private MediaConstraints audioConstraints; + private MediaConstraints videoConstraints; + private MediaConstraints sdpConstraints; + private MagicAudioManager audioManager; + private VideoSource videoSource; + private VideoTrack localVideoTrack; + private AudioSource audioSource; + private AudioTrack localAudioTrack; + private VideoCapturer videoCapturer; + private EglBase rootEglBase; + private boolean leavingCall = false; + private boolean inCall = false; + private Disposable signalingDisposable; + private Disposable pingDisposable; + private List iceServers; private CameraEnumerator cameraEnumerator; private String roomToken; private UserEntity userEntity; @@ -252,8 +251,7 @@ public class CallController extends BaseController { baseUrl = userEntity.getBaseUrl(); } - isFromNotification = args.containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL) && TextUtils.isEmpty - (roomToken); + isFromNotification = TextUtils.isEmpty(roomToken); } @Override @@ -636,12 +634,14 @@ public class CallController extends BaseController { 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); + if (getActivity() != null) { + 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) + @OnClick(R.id.callControlHangupView) public void onHangupClick() { if (inCall) { hangup(false); @@ -652,7 +652,7 @@ public class CallController extends BaseController { @OnClick(R.id.call_control_camera) public void onCameraClick() { - if (EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA)) { + if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_CAMERA)) { videoOn = !videoOn; if (videoOn) { @@ -824,7 +824,7 @@ public class CallController extends BaseController { super.onDestroy(); } - public void startPullingSignalingMessages() { + private void startPullingSignalingMessages() { leavingCall = false; ncApi.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(baseUrl)) @@ -1055,6 +1055,7 @@ public class CallController extends BaseController { @Override public void onError(Throwable e) { + Log.d("MARIO", e.getLocalizedMessage()); dispose(signalingDisposable); } @@ -1396,7 +1397,7 @@ public class CallController extends BaseController { } private void removeMediaStream(String sessionId) { - if (remoteRenderersLayout.getChildCount() > 0) { + if (remoteRenderersLayout != null && remoteRenderersLayout.getChildCount() > 0) { RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId); if (relativeLayout != null) { SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view); 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 13de6bcd5..66c372c76 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java @@ -126,16 +126,16 @@ public class CallNotificationController extends BaseController { @OnClick(R.id.callAnswerCameraView) void answerWithCamera() { originalBundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, false); - setBackstackAndProceed(); + proceedToCall(); } @OnClick(R.id.callAnswerVoiceOnlyView) void answerVoiceOnly() { originalBundle.putBoolean(BundleKeys.KEY_CALL_VOICE_ONLY, true); - setBackstackAndProceed(); + proceedToCall(); } - private void setBackstackAndProceed() { + private void proceedToCall() { originalBundle.putString(BundleKeys.KEY_ROOM_TOKEN, currentRoom.getToken()); getRouter().setRoot(RouterTransaction.with(new CallController(originalBundle)) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java b/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java index f4d287218..32456ad92 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java @@ -21,12 +21,16 @@ package com.nextcloud.talk.jobs; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import com.bluelinelabs.logansquare.LoganSquare; import com.evernote.android.job.Job; +import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.models.database.UserEntity; @@ -38,6 +42,7 @@ import com.nextcloud.talk.utils.database.user.UserUtils; import java.io.IOException; import java.net.CookieManager; import java.util.HashMap; +import java.util.zip.CRC32; import javax.inject.Inject; @@ -113,6 +118,21 @@ public class AccountRemovalJob extends Job { @Override public void onNext(Void aVoid) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String groupName = String.format(getContext().getResources().getString(R.string + .nc_notification_channel), userEntity.getUserId(), userEntity.getBaseUrl()); + CRC32 crc32 = new CRC32(); + crc32.update(groupName.getBytes()); + NotificationManager notificationManager = + (NotificationManager) getContext().getSystemService(Context + .NOTIFICATION_SERVICE); + + if (notificationManager != null) { + notificationManager.deleteNotificationChannelGroup(Long + .toString(crc32.getValue())); + } + } + userUtils.deleteUser(userEntity.getId()).subscribe(new CompletableObserver() { @Override 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 96a1a8384..34186ab66 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java @@ -26,7 +26,10 @@ 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; @@ -44,6 +47,7 @@ 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; @@ -55,6 +59,8 @@ 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; @@ -110,10 +116,11 @@ public class NotificationJob extends Job { .getInstance().getUserInRoom()); boolean shouldShowNotification = decryptedPushMessage.getApp().equals("spreed") && + !decryptedPushMessage.getType().equals("room") && (!isInTheSameRoomAsNotification || decryptedPushMessage.getType().equals("call")); if (shouldShowNotification) { - int smallIcon; + int smallIcon = 0; Bitmap largeIcon; String category = ""; int priority = Notification.PRIORITY_HIGH; @@ -152,8 +159,7 @@ public class NotificationJob extends Job { getContext().startActivity(intent); break; case "room": - smallIcon = R.drawable.ic_notifications_white_24dp; - category = Notification.CATEGORY_CALL; + // do absolutely nothing, we won't even come to this point break; case "chat": ringtonePreferencesString = appPreferences.getMessageRingtoneUri(); @@ -177,84 +183,70 @@ public class NotificationJob extends Job { smallIcon = R.drawable.ic_logo; } - /*largeIcon = BitmapFactory.decodeResource(context.getResources(), smallIcon); - CRC32 crc32 = new CRC32(); + if (decryptedPushMessage.getType().equals("chat")) { + largeIcon = BitmapFactory.decodeResource(context.getResources(), smallIcon); + CRC32 crc32 = new CRC32(); - Notification.Builder notificationBuilder = new Notification.Builder(context) - .setLargeIcon(largeIcon) - .setSmallIcon(smallIcon) - .setCategory(category) - .setPriority(priority) - .setWhen(Calendar.getInstance().getTimeInMillis()) - .setShowWhen(true) - .setSubText(signatureVerification.getUserEntity().getDisplayName()) - .setContentTitle(decryptedPushMessage.getSubject()) - .setFullScreenIntent(pendingIntent, true) - .setAutoCancel(true); + Notification.Builder notificationBuilder = new Notification.Builder(context) + .setLargeIcon(largeIcon) + .setSmallIcon(smallIcon) + .setCategory(category) + .setPriority(priority) + .setWhen(Calendar.getInstance().getTimeInMillis()) + .setShowWhen(true) + .setSubText(signatureVerification.getUserEntity().getDisplayName()) + .setContentTitle(decryptedPushMessage.getSubject()) + .setContentIntent(pendingIntent) + .setAutoCancel(true); - if (Build.VERSION.SDK_INT >= 23) { - // This method should exist since API 21, but some phones don't have it - // So as a safeguard, we don't use it until 23 - notificationBuilder.setColor(context.getResources().getColor(R.color.colorPrimary)); - } + if (Build.VERSION.SDK_INT >= 23) { + // This method should exist since API 21, but some phones don't have it + // So as a safeguard, we don't use it until 23 + notificationBuilder.setColor(context.getResources().getColor(R.color.colorPrimary)); + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - String groupName = String.format(context.getResources().getString(R.string - .nc_notification_channel), signatureVerification.getUserEntity() - .getDisplayName(), signatureVerification.getUserEntity().getBaseUrl()); - crc32.update(groupName.getBytes()); + String groupName = String.format(context.getResources().getString(R.string + .nc_notification_channel), signatureVerification.getUserEntity() + .getUserId(), signatureVerification.getUserEntity().getBaseUrl()); + crc32.update(groupName.getBytes()); - NotificationUtils.createNotificationChannelGroup(notificationManager, - Long.toString(crc32.getValue()), - groupName); + NotificationUtils.createNotificationChannelGroup(notificationManager, + Long.toString(crc32.getValue()), + groupName); - if (category.equals(Notification.CATEGORY_CALL)) { NotificationUtils.createNotificationChannel(notificationManager, - NotificationUtils.NOTIFICATION_CHANNEL_CALLS, context.getResources() - .getString(R - .string.nc_notification_channel_calls), context.getResources() - .getString - (R.string.nc_notification_channel_calls_description), true, + NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2, context.getResources() + .getString(R.string.nc_notification_channel_messages), context.getResources() + .getString(R.string.nc_notification_channel_messages_description), true, NotificationManager.IMPORTANCE_HIGH); - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_CALLS); - } else { - NotificationUtils.createNotificationChannel(notificationManager, - NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES, context.getResources() - .getString(R - .string.nc_notification_channel_messages), context.getResources() - .getString - (R.string.nc_notification_channel_messages_description), true, - NotificationManager.IMPORTANCE_DEFAULT); - - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES); + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2); + notificationBuilder.setGroup(Long.toString(crc32.getValue())); } - notificationBuilder.setGroup(Long.toString(crc32.getValue())); + notificationBuilder.setContentIntent(pendingIntent); + + String stringForCrc = decryptedPushMessage.getSubject() + " " + signatureVerification + .getUserEntity().getDisplayName() + " " + signatureVerification.getUserEntity + ().getBaseUrl() + System.currentTimeMillis(); + + crc32 = new CRC32(); + crc32.update(stringForCrc.getBytes()); + + if (notificationManager != null) { + notificationManager.notify((int) crc32.getValue(), notificationBuilder.build()); + + if (soundUri != null) { + MediaPlayer mediaPlayer = MediaPlayer.create(context, soundUri); + mediaPlayer.start(); + mediaPlayer.setOnCompletionListener(MediaPlayer::release); + + } + } } - - notificationBuilder.setContentIntent(pendingIntent); - - String stringForCrc = decryptedPushMessage.getSubject() + " " + signatureVerification - .getUserEntity().getDisplayName() + " " + signatureVerification.getUserEntity - ().getBaseUrl(); - - crc32 = new CRC32(); - crc32.update(stringForCrc.getBytes()); - - if (notificationManager != null) { - notificationManager.notify((int) crc32.getValue(), notificationBuilder.build()); - - if (soundUri != null) { - MediaPlayer mediaPlayer = MediaPlayer.create(context, soundUri); - mediaPlayer.start(); - mediaPlayer.setOnCompletionListener(MediaPlayer::release); - - } - }*/ } - } } catch (NoSuchAlgorithmException e1) { Log.d(TAG, "No proper algorithm to decrypt the message " + e1.getLocalizedMessage()); diff --git a/app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.java b/app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.java new file mode 100644 index 000000000..0aae5f14a --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.java @@ -0,0 +1,58 @@ +/* + * 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.receivers; + +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.util.Log; + +import com.nextcloud.talk.utils.NotificationUtils; + +public class PackageReplacedReceiver extends BroadcastReceiver { + private static final String TAG = "PackageReplacedReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null && intent.getAction() != null && + intent.getAction().equals("android.intent.action.MY_PACKAGE_REPLACED")) { + try { + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + if (packageInfo.versionCode == 99 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context + .NOTIFICATION_SERVICE); + + if (notificationManager != null) { + notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS); + notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES); + } + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to find package info"); + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java index d60ade3ca..a8c736363 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.java @@ -30,6 +30,8 @@ import android.os.Build; public class NotificationUtils { public static final String NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS"; public static final String NOTIFICATION_CHANNEL_MESSAGES = "NOTIFICATION_CHANNEL_MESSAGES"; + public static final String NOTIFICATION_CHANNEL_CALLS_V2 = "NOTIFICATION_CHANNEL_CALLS_V2"; + public static final String NOTIFICATION_CHANNEL_MESSAGES_V2 = "NOTIFICATION_CHANNEL_MESSAGES_V2"; @TargetApi(Build.VERSION_CODES.O) public static void createNotificationChannel(NotificationManager notificationManager, diff --git a/app/src/main/res/layout/controller_call.xml b/app/src/main/res/layout/controller_call.xml index 9c58dc482..d89c6c07b 100644 --- a/app/src/main/res/layout/controller_call.xml +++ b/app/src/main/res/layout/controller_call.xml @@ -132,7 +132,7 @@