diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java deleted file mode 100644 index ac01abfb7..000000000 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java +++ /dev/null @@ -1,684 +0,0 @@ -/* - * 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.jobs; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.AudioAttributes; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.VibrationEffect; -import android.os.Vibrator; -import android.service.notification.StatusBarNotification; -import android.text.TextUtils; -import android.util.Base64; -import android.util.Log; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.core.app.Person; -import androidx.core.graphics.drawable.IconCompat; -import androidx.emoji.text.EmojiCompat; -import androidx.work.Data; -import androidx.work.Worker; -import androidx.work.WorkerParameters; -import autodagger.AutoInjector; -import com.bluelinelabs.logansquare.LoganSquare; -import com.facebook.common.executors.UiThreadImmediateExecutorService; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.DataSource; -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.imagepipeline.core.ImagePipeline; -import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; -import com.facebook.imagepipeline.image.CloseableImage; -import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor; -import com.facebook.imagepipeline.request.ImageRequest; -import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.MagicCallActivity; -import com.nextcloud.talk.activities.MainActivity; -import com.nextcloud.talk.api.NcApi; -import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.models.RingtoneSettings; -import com.nextcloud.talk.models.SignatureVerification; -import com.nextcloud.talk.models.database.ArbitraryStorageEntity; -import com.nextcloud.talk.models.database.UserEntity; -import com.nextcloud.talk.models.json.chat.ChatUtils; -import com.nextcloud.talk.models.json.conversations.Conversation; -import com.nextcloud.talk.models.json.conversations.RoomOverall; -import com.nextcloud.talk.models.json.notifications.NotificationOverall; -import com.nextcloud.talk.models.json.push.DecryptedPushMessage; -import com.nextcloud.talk.models.json.push.NotificationUser; -import com.nextcloud.talk.utils.ApiUtils; -import com.nextcloud.talk.utils.DisplayUtils; -import com.nextcloud.talk.utils.DoNotDisturbUtils; -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.arbitrarystorage.ArbitraryStorageUtils; -import com.nextcloud.talk.utils.preferences.AppPreferences; -import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder; -import io.reactivex.Observer; -import io.reactivex.disposables.Disposable; -import java.io.IOException; -import java.net.CookieManager; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.util.HashMap; -import java.util.zip.CRC32; -import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; -import javax.inject.Inject; -import okhttp3.JavaNetCookieJar; -import okhttp3.OkHttpClient; -import org.parceler.Parcels; -import retrofit2.Retrofit; - -@AutoInjector(NextcloudTalkApplication.class) -public class NotificationWorker extends Worker { - public static final String TAG = "NotificationWorker"; - - @Inject - AppPreferences appPreferences; - - @Inject - ArbitraryStorageUtils arbitraryStorageUtils; - - @Inject - Retrofit retrofit; - - @Inject - OkHttpClient okHttpClient; - - private NcApi ncApi; - - private DecryptedPushMessage decryptedPushMessage; - private Context context; - private SignatureVerification signatureVerification; - private String conversationType = "one2one"; - - private String credentials; - private boolean muteCall = false; - private boolean importantConversation = false; - - public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - } - - private void showNotificationForCallWithNoPing(Intent intent) { - UserEntity userEntity = signatureVerification.getUserEntity(); - - ArbitraryStorageEntity arbitraryStorageEntity; - - if ((arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(userEntity.getId(), - "mute_calls", intent.getExtras().getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) - != null) { - muteCall = Boolean.parseBoolean(arbitraryStorageEntity.getValue()); - } - - if ((arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(userEntity.getId(), - "important_conversation", - intent.getExtras().getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) != null) { - importantConversation = Boolean.parseBoolean(arbitraryStorageEntity.getValue()); - } - - if (DoNotDisturbUtils.INSTANCE.isDnDActive()) { - if (!DoNotDisturbUtils.INSTANCE.isInDoNotDisturbWithPriority() - || !importantConversation - || muteCall) { - return; - } - } - - ncApi.getRoom(credentials, ApiUtils.getRoom(userEntity.getBaseUrl(), - intent.getExtras().getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()))) - .blockingSubscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(RoomOverall roomOverall) { - Conversation conversation = roomOverall.getOcs().getData(); - - intent.putExtra(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); - if (conversation.getType() - .equals(Conversation.ConversationType.ONE_TO_ONE_CONVERSATION) || - (!TextUtils.isEmpty(conversation.getObjectType()) && "share:password".equals - (conversation.getObjectType()))) { - context.startActivity(intent); - } else { - if (conversation.getType().equals(Conversation.ConversationType.GROUP_CONVERSATION)) { - conversationType = "group"; - } else { - conversationType = "public"; - } - if (decryptedPushMessage.getNotificationId() != Long.MIN_VALUE) { - showNotificationWithObjectData(intent); - } else { - showNotification(intent); - } - } - } - - @Override - public void onError(Throwable e) { - } - - @Override - public void onComplete() { - - } - }); - } - - private void showNotificationWithObjectData(Intent intent) { - UserEntity userEntity = signatureVerification.getUserEntity(); - ncApi.getNotification(credentials, ApiUtils.getUrlForNotificationWithId(userEntity.getBaseUrl(), - Long.toString(decryptedPushMessage.getNotificationId()))) - .blockingSubscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(NotificationOverall notificationOverall) { - com.nextcloud.talk.models.json.notifications.Notification notification = - notificationOverall.getOcs().getNotification(); - - if (notification.getMessageRichParameters() != null && - notification.getMessageRichParameters().size() > 0) { - decryptedPushMessage.setText(ChatUtils.getParsedMessage(notification.getMessageRich(), - notification.getMessageRichParameters())); - } else { - decryptedPushMessage.setText(notification.getMessage()); - } - - HashMap> subjectRichParameters = notification - .getSubjectRichParameters(); - - decryptedPushMessage.setTimestamp(notification.getDatetime().getMillis()); - - if (subjectRichParameters != null && subjectRichParameters.size() > 0) { - HashMap callHashMap = subjectRichParameters.get("call"); - HashMap userHashMap = subjectRichParameters.get("user"); - HashMap guestHashMap = subjectRichParameters.get("guest"); - - if (callHashMap != null && callHashMap.size() > 0 && callHashMap.containsKey( - "name")) { - if (notification.getObjectType().equals("chat")) { - decryptedPushMessage.setSubject(callHashMap.get("name")); - } else { - decryptedPushMessage.setSubject(notification.getSubject()); - } - - if (callHashMap.containsKey("call-type")) { - conversationType = callHashMap.get("call-type"); - } - } - - NotificationUser notificationUser = new NotificationUser(); - if (userHashMap != null && !userHashMap.isEmpty()) { - notificationUser.setId(userHashMap.get("id")); - notificationUser.setType(userHashMap.get("type")); - notificationUser.setName(userHashMap.get("name")); - decryptedPushMessage.setNotificationUser(notificationUser); - } else if (guestHashMap != null && !guestHashMap.isEmpty()) { - notificationUser.setId(guestHashMap.get("id")); - notificationUser.setType(guestHashMap.get("type")); - notificationUser.setName(guestHashMap.get("name")); - decryptedPushMessage.setNotificationUser(notificationUser); - } - } - - showNotification(intent); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - } - }); - } - - private void showNotification(Intent intent) { - int smallIcon; - Bitmap largeIcon; - String category; - int priority = Notification.PRIORITY_HIGH; - - smallIcon = R.drawable.ic_logo; - - if (decryptedPushMessage.getType().equals("chat") || decryptedPushMessage.getType() - .equals("room")) { - category = Notification.CATEGORY_MESSAGE; - } else { - category = Notification.CATEGORY_CALL; - } - - switch (conversationType) { - case "group": - largeIcon = BitmapFactory.decodeResource(context.getResources(), - R.drawable.ic_people_group_black_24px); - break; - case "public": - largeIcon = - BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_link_black_24px); - break; - default: - // assuming one2one - if (decryptedPushMessage.getType().equals("chat") || decryptedPushMessage.getType() - .equals("room")) { - largeIcon = - BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_chat_black_24dp); - } else { - largeIcon = - BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_call_black_24dp); - } - } - - intent.setAction(Long.toString(System.currentTimeMillis())); - - PendingIntent pendingIntent = PendingIntent.getActivity(context, - 0, intent, 0); - - Uri uri = Uri.parse(signatureVerification.getUserEntity().getBaseUrl()); - String baseUrl = uri.getHost(); - - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "1") - .setLargeIcon(largeIcon) - .setSmallIcon(smallIcon) - .setCategory(category) - .setPriority(priority) - .setSubText(baseUrl) - .setWhen(decryptedPushMessage.getTimestamp()) - .setShowWhen(true) - .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.getSubject())) - .setContentIntent(pendingIntent) - .setAutoCancel(true); - - if (!TextUtils.isEmpty(decryptedPushMessage.getText())) { - notificationBuilder.setContentText(EmojiCompat.get().process(decryptedPushMessage.getText())); - } - - 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)); - } - - Bundle notificationInfo = new Bundle(); - notificationInfo.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), - signatureVerification.getUserEntity().getId()); - // could be an ID or a TOKEN - notificationInfo.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), - decryptedPushMessage.getId()); - notificationInfo.putLong(BundleKeys.INSTANCE.getKEY_NOTIFICATION_ID(), - decryptedPushMessage.getNotificationId()); - notificationBuilder.setExtras(notificationInfo); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - - /*NotificationUtils.createNotificationChannelGroup(context, - Long.toString(crc32.getValue()), - groupName);*/ - - if (decryptedPushMessage.getType().equals("chat") || decryptedPushMessage.getType() - .equals("room")) { - NotificationUtils.INSTANCE.createNotificationChannel(context, - NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3(), context.getResources() - .getString(R.string.nc_notification_channel_messages), context.getResources() - .getString(R.string.nc_notification_channel_messages), true, - NotificationManager.IMPORTANCE_HIGH); - - notificationBuilder.setChannelId( - NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_MESSAGES_V3()); - } else { - NotificationUtils.INSTANCE.createNotificationChannel(context, - NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_CALLS_V3(), context.getResources() - .getString(R.string.nc_notification_channel_calls), context.getResources() - .getString(R.string.nc_notification_channel_calls_description), true, - NotificationManager.IMPORTANCE_HIGH); - - notificationBuilder.setChannelId( - NotificationUtils.INSTANCE.getNOTIFICATION_CHANNEL_CALLS_V3()); - } - } else { - // red color for the lights - notificationBuilder.setLights(0xFFFF0000, 200, 200); - } - - notificationBuilder.setContentIntent(pendingIntent); - - CRC32 crc32 = new CRC32(); - - String groupName = - signatureVerification.getUserEntity().getId() + "@" + decryptedPushMessage.getId(); - crc32.update(groupName.getBytes()); - notificationBuilder.setGroup(Long.toString(crc32.getValue())); - - // notificationId - crc32 = new CRC32(); - String stringForCrc = String.valueOf(System.currentTimeMillis()); - crc32.update(stringForCrc.getBytes()); - - StatusBarNotification activeStatusBarNotification = - NotificationUtils.INSTANCE.findNotificationForRoom(context, - signatureVerification.getUserEntity(), decryptedPushMessage.getId()); - - int notificationId; - - if (activeStatusBarNotification != null) { - notificationId = activeStatusBarNotification.getId(); - } else { - notificationId = (int) crc32.getValue(); - } - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N - && decryptedPushMessage.getNotificationUser() != null - && decryptedPushMessage.getType().equals("chat")) { - NotificationCompat.MessagingStyle style = null; - if (activeStatusBarNotification != null) { - Notification activeNotification = activeStatusBarNotification.getNotification(); - style = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification( - activeNotification); - } - - Person.Builder person = - new Person.Builder().setKey(signatureVerification.getUserEntity().getId() + - "@" + decryptedPushMessage.getNotificationUser().getId()) - .setName( - EmojiCompat.get().process(decryptedPushMessage.getNotificationUser().getName())) - .setBot(decryptedPushMessage.getNotificationUser().getType().equals("bot")); - - notificationBuilder.setOnlyAlertOnce(true); - - if (decryptedPushMessage.getNotificationUser().getType().equals("user") - || decryptedPushMessage.getNotificationUser().getType().equals("guest")) { - String avatarUrl = - ApiUtils.getUrlForAvatarWithName(signatureVerification.getUserEntity().getBaseUrl(), - decryptedPushMessage.getNotificationUser().getId(), R.dimen.avatar_size); - - if (decryptedPushMessage.getNotificationUser().getType().equals("guest")) { - avatarUrl = ApiUtils.getUrlForAvatarWithNameForGuests( - signatureVerification.getUserEntity().getBaseUrl(), - decryptedPushMessage.getNotificationUser().getName(), R.dimen.avatar_size); - } - - ImageRequest imageRequest = - DisplayUtils.INSTANCE.getImageRequestForUrl(avatarUrl, null); - ImagePipeline imagePipeline = Fresco.getImagePipeline(); - DataSource> dataSource = - imagePipeline.fetchDecodedImage(imageRequest, context); - - NotificationCompat.MessagingStyle finalStyle = style; - dataSource.subscribe( - new BaseBitmapDataSubscriber() { - @Override - protected void onNewResultImpl(Bitmap bitmap) { - if (bitmap != null) { - new RoundAsCirclePostprocessor(true).process(bitmap); - person.setIcon(IconCompat.createWithBitmap(bitmap)); - notificationBuilder.setStyle(getStyle(person.build(), - finalStyle)); - sendNotificationWithId(notificationId, notificationBuilder.build()); - } - } - - @Override - protected void onFailureImpl( - DataSource> dataSource) { - notificationBuilder.setStyle(getStyle(person.build(), finalStyle)); - sendNotificationWithId(notificationId, notificationBuilder.build()); - } - }, - UiThreadImmediateExecutorService.getInstance()); - } else { - notificationBuilder.setStyle(getStyle(person.build(), style)); - sendNotificationWithId(notificationId, notificationBuilder.build()); - } - } else { - sendNotificationWithId(notificationId, notificationBuilder.build()); - } - } - - private NotificationCompat.MessagingStyle getStyle(Person person, - @Nullable NotificationCompat.MessagingStyle style) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - NotificationCompat.MessagingStyle newStyle = - new NotificationCompat.MessagingStyle(person); - - newStyle.setConversationTitle(decryptedPushMessage.getSubject()); - newStyle.setGroupConversation(!conversationType.equals("one2one")); - - if (style != null) { - style.getMessages() - .forEach(message -> newStyle.addMessage( - new NotificationCompat.MessagingStyle.Message(message.getText(), - message.getTimestamp(), message.getPerson()))); - } - - newStyle.addMessage(decryptedPushMessage.getText(), decryptedPushMessage.getTimestamp(), - person); - return newStyle; - } - - // we'll never come here - return style; - } - - private void sendNotificationWithId(int notificationId, Notification notification) { - NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); - notificationManager.notify(notificationId, notification); - - if (!notification.category.equals(Notification.CATEGORY_CALL)) { - String ringtonePreferencesString; - Uri soundUri; - - ringtonePreferencesString = appPreferences.getMessageRingtoneUri(); - if (TextUtils.isEmpty(ringtonePreferencesString)) { - soundUri = Uri.parse("android.resource://" + context.getPackageName() + - "/raw/librem_by_feandesign_message"); - } else { - try { - RingtoneSettings ringtoneSettings = LoganSquare.parse - (ringtonePreferencesString, RingtoneSettings.class); - soundUri = ringtoneSettings.getRingtoneUri(); - } catch (IOException exception) { - soundUri = Uri.parse("android.resource://" + context.getPackageName() + - "/raw/librem_by_feandesign_message"); - } - } - - if (soundUri != null && !ApplicationWideCurrentRoomHolder.getInstance().isInCall() && - (DoNotDisturbUtils.INSTANCE.shouldPlaySound() || importantConversation)) { - AudioAttributes.Builder audioAttributesBuilder = - new AudioAttributes.Builder().setContentType - (AudioAttributes.CONTENT_TYPE_SONIFICATION); - - if (decryptedPushMessage.getType().equals("chat") || decryptedPushMessage.getType() - .equals("room")) { - audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT); - } else { - audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST); - } - - MediaPlayer mediaPlayer = new MediaPlayer(); - try { - mediaPlayer.setDataSource(context, soundUri); - mediaPlayer.setAudioAttributes(audioAttributesBuilder.build()); - - mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start()); - mediaPlayer.setOnCompletionListener(MediaPlayer::release); - - mediaPlayer.prepareAsync(); - } catch (IOException e) { - Log.e(TAG, "Failed to set data source"); - } - } - - if (DoNotDisturbUtils.INSTANCE.shouldVibrate(appPreferences.getShouldVibrateSetting()) - || importantConversation) { - Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - - if (vibrator != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)); - } else { - vibrator.vibrate(500); - } - } - } - } - } - - @NonNull - @Override - public Result doWork() { - NextcloudTalkApplication.Companion.getSharedApplication() - .getComponentApplication() - .inject(this); - - context = getApplicationContext(); - Data data = getInputData(); - String subject = data.getString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SUBJECT()); - String signature = data.getString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SIGNATURE()); - - try { - byte[] base64DecodedSubject = Base64.decode(subject, Base64.DEFAULT); - byte[] base64DecodedSignature = Base64.decode(signature, Base64.DEFAULT); - PushUtils pushUtils = new PushUtils(); - PrivateKey privateKey = (PrivateKey) pushUtils.readKeyFromFile(false); - - try { - signatureVerification = pushUtils.verifySignature(base64DecodedSignature, - base64DecodedSubject); - - if (signatureVerification.isSignatureValid()) { - Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - byte[] decryptedSubject = cipher.doFinal(base64DecodedSubject); - decryptedPushMessage = LoganSquare.parse(new String(decryptedSubject), - DecryptedPushMessage.class); - - decryptedPushMessage.setTimestamp(System.currentTimeMillis()); - if (decryptedPushMessage.isDelete()) { - NotificationUtils.INSTANCE.cancelExistingNotificationWithId(context, - signatureVerification.getUserEntity(), decryptedPushMessage.getNotificationId()); - } else if (decryptedPushMessage.isDeleteAll()) { - NotificationUtils.INSTANCE.cancelAllNotificationsForAccount(context, - signatureVerification.getUserEntity()); - } else { - credentials = - ApiUtils.getCredentials(signatureVerification.getUserEntity().getUsername(), - signatureVerification.getUserEntity().getToken()); - - ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new - JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class); - - boolean hasChatSupport = signatureVerification.getUserEntity(). - hasSpreedFeatureCapability("chat-v2"); - - boolean shouldShowNotification = decryptedPushMessage.getApp().equals("spreed"); - - if (shouldShowNotification) { - Intent intent; - Bundle bundle = new Bundle(); - - boolean startACall = decryptedPushMessage.getType().equals("call") || !hasChatSupport; - if (startACall) { - intent = new Intent(context, MagicCallActivity.class); - } else { - intent = new Intent(context, MainActivity.class); - } - - intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - - if (!signatureVerification.getUserEntity().hasSpreedFeatureCapability - ("no-ping")) { - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), - decryptedPushMessage.getId()); - } else { - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), - decryptedPushMessage.getId()); - } - - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), - signatureVerification.getUserEntity()); - - bundle.putBoolean(BundleKeys.INSTANCE.getKEY_FROM_NOTIFICATION_START_CALL(), - startACall); - - intent.putExtras(bundle); - - switch (decryptedPushMessage.getType()) { - case "call": - if (!bundle.containsKey(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN())) { - context.startActivity(intent); - } else { - showNotificationForCallWithNoPing(intent); - } - break; - case "room": - if (bundle.containsKey(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN())) { - showNotificationWithObjectData(intent); - } - break; - case "chat": - if (decryptedPushMessage.getNotificationId() != Long.MIN_VALUE) { - showNotificationWithObjectData(intent); - } else { - showNotification(intent); - } - break; - default: - break; - } - } - } - } - } catch (NoSuchAlgorithmException e1) { - Log.d(TAG, "No proper algorithm to decrypt the message " + e1.getLocalizedMessage()); - } catch (NoSuchPaddingException e1) { - Log.d(TAG, "No proper padding to decrypt the message " + e1.getLocalizedMessage()); - } catch (InvalidKeyException e1) { - Log.d(TAG, "Invalid private key " + e1.getLocalizedMessage()); - } - } catch (Exception exception) { - Log.d(TAG, "Something went very wrong " + exception.getLocalizedMessage()); - } - return Result.success(); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt new file mode 100644 index 000000000..3a2555f86 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -0,0 +1,762 @@ +/* + * 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.jobs + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.drawable.Drawable +import android.media.AudioAttributes +import android.media.MediaPlayer +import android.net.Uri +import android.os.Build.VERSION +import android.os.Build.VERSION_CODES +import android.os.Bundle +import android.os.VibrationEffect +import android.os.Vibrator +import android.text.TextUtils +import android.util.Base64 +import android.util.Log +import androidx.core.app.NotificationCompat.Builder +import androidx.core.app.NotificationCompat.MessagingStyle +import androidx.core.app.NotificationCompat.MessagingStyle.Message +import androidx.core.app.NotificationManagerCompat +import androidx.core.app.Person +import androidx.core.graphics.drawable.IconCompat +import androidx.core.graphics.drawable.toBitmap +import androidx.emoji.text.EmojiCompat +import androidx.work.ListenableWorker.Result +import androidx.work.Worker +import androidx.work.WorkerParameters +import autodagger.AutoInjector +import coil.Coil +import coil.target.Target +import coil.transform.CircleCropTransformation +import com.bluelinelabs.logansquare.LoganSquare +import com.nextcloud.talk.R.color +import com.nextcloud.talk.R.dimen +import com.nextcloud.talk.R.drawable +import com.nextcloud.talk.R.string +import com.nextcloud.talk.activities.MagicCallActivity +import com.nextcloud.talk.activities.MainActivity +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication +import com.nextcloud.talk.models.RingtoneSettings +import com.nextcloud.talk.models.SignatureVerification +import com.nextcloud.talk.models.database.ArbitraryStorageEntity +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.models.json.chat.ChatUtils +import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType.GROUP_CONVERSATION +import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType.ONE_TO_ONE_CONVERSATION +import com.nextcloud.talk.models.json.conversations.RoomOverall +import com.nextcloud.talk.models.json.notifications.NotificationOverall +import com.nextcloud.talk.models.json.push.DecryptedPushMessage +import com.nextcloud.talk.models.json.push.NotificationUser +import com.nextcloud.talk.newarch.utils.Images +import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.DoNotDisturbUtils.isDnDActive +import com.nextcloud.talk.utils.DoNotDisturbUtils.isInDoNotDisturbWithPriority +import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound +import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldVibrate +import com.nextcloud.talk.utils.NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V3 +import com.nextcloud.talk.utils.NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V3 +import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount +import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId +import com.nextcloud.talk.utils.NotificationUtils.createNotificationChannel +import com.nextcloud.talk.utils.NotificationUtils.findNotificationForRoom +import com.nextcloud.talk.utils.PushUtils +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SIGNATURE +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SUBJECT +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY +import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils +import com.nextcloud.talk.utils.preferences.AppPreferences +import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder +import io.reactivex.Observer +import io.reactivex.disposables.Disposable +import okhttp3.JavaNetCookieJar +import okhttp3.OkHttpClient +import org.parceler.Parcels +import retrofit2.Retrofit +import java.io.IOException +import java.net.CookieManager +import java.security.InvalidKeyException +import java.security.NoSuchAlgorithmException +import java.security.PrivateKey +import java.util.HashMap +import java.util.function.Consumer +import java.util.zip.CRC32 +import javax.crypto.Cipher +import javax.crypto.NoSuchPaddingException +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class NotificationWorker( + context: Context, + workerParams: WorkerParameters +) : Worker(context, workerParams) { + @Inject + internal var appPreferences: AppPreferences? = null + @Inject + internal var arbitraryStorageUtils: ArbitraryStorageUtils? = + null + @Inject + internal var retrofit: Retrofit? = null + @Inject + internal var okHttpClient: OkHttpClient? = null + private var ncApi: NcApi? = null + private var decryptedPushMessage: DecryptedPushMessage? = null + private var context: Context? = null + private var signatureVerification: SignatureVerification? = null + private var conversationType: String? = "one2one" + private var credentials: String? = null + private var muteCall = false + private var importantConversation = false + private fun showNotificationForCallWithNoPing(intent: Intent) { + val userEntity: UserEntity = + signatureVerification!!.userEntity + var arbitraryStorageEntity: ArbitraryStorageEntity + if (arbitraryStorageUtils!!.getStorageSetting( + userEntity.id, + "mute_calls", + intent.extras!!.getString(KEY_ROOM_TOKEN) + ).also { arbitraryStorageEntity = it } + != null + ) { + muteCall = arbitraryStorageEntity.value!!.toBoolean() + } + if (arbitraryStorageUtils!!.getStorageSetting( + userEntity.id, + "important_conversation", + intent.extras!!.getString(KEY_ROOM_TOKEN) + ).also { arbitraryStorageEntity = it } != null + ) { + importantConversation = arbitraryStorageEntity.value!!.toBoolean() + } + if (isDnDActive()) { + if (!isInDoNotDisturbWithPriority() + || !importantConversation + || muteCall + ) { + return + } + } + ncApi!!.getRoom( + credentials, ApiUtils.getRoom( + userEntity.baseUrl, + intent.extras!!.getString(KEY_ROOM_TOKEN) + ) + ) + .blockingSubscribe(object : Observer { + override fun onSubscribe(d: Disposable) {} + override fun onNext(roomOverall: RoomOverall) { + val conversation: Conversation = + roomOverall.getOcs() + .getData() + intent.putExtra( + KEY_ROOM, + Parcels.wrap( + conversation + ) + ) + if ((conversation.type + == ONE_TO_ONE_CONVERSATION) || + !TextUtils.isEmpty( + conversation.objectType + ) && "share:password" == conversation.objectType + ) { + context!!.startActivity(intent) + } else { + conversationType = if (conversation.type == GROUP_CONVERSATION) { + "group" + } else { + "public" + } + if (decryptedPushMessage!!.notificationId != Long.MIN_VALUE) { + showNotificationWithObjectData(intent) + } else { + showNotification(intent) + } + } + } + + override fun onError(e: Throwable) {} + override fun onComplete() {} + }) + } + + private fun showNotificationWithObjectData(intent: Intent) { + val userEntity: UserEntity = + signatureVerification!!.userEntity + ncApi!!.getNotification( + credentials, ApiUtils.getUrlForNotificationWithId( + userEntity.baseUrl, + decryptedPushMessage!!.notificationId.toString() + ) + ) + .blockingSubscribe(object : Observer { + override fun onSubscribe(d: Disposable) {} + override fun onNext(notificationOverall: NotificationOverall) { + val notification: com.nextcloud.talk.models.json.notifications.Notification = + notificationOverall.ocs + .notification + if (notification.messageRichParameters != null && + notification.messageRichParameters.size > 0 + ) { + decryptedPushMessage!!.text = ChatUtils.getParsedMessage( + notification.messageRich, + notification.messageRichParameters + ) + } else { + decryptedPushMessage!!.text = notification.message + } + val subjectRichParameters: HashMap>? = + notification + .subjectRichParameters + decryptedPushMessage!!.timestamp = notification.datetime.millis + if (subjectRichParameters != null && subjectRichParameters.size > 0) { + val callHashMap = + subjectRichParameters["call"] + val userHashMap = + subjectRichParameters["user"] + val guestHashMap = + subjectRichParameters["guest"] + if (callHashMap != null && callHashMap.size > 0 && callHashMap.containsKey( + "name" + ) + ) { + if (notification.objectType == "chat") { + decryptedPushMessage!!.subject = callHashMap["name"] + } else { + decryptedPushMessage!!.subject = notification.subject + } + if (callHashMap.containsKey("call-type")) { + conversationType = callHashMap["call-type"] + } + } + val notificationUser = + NotificationUser() + if (userHashMap != null && !userHashMap.isEmpty()) { + notificationUser.id = userHashMap["id"] + notificationUser.type = userHashMap["type"] + notificationUser.name = userHashMap["name"] + decryptedPushMessage!!.notificationUser = notificationUser + } else if (guestHashMap != null && !guestHashMap.isEmpty()) { + notificationUser.id = guestHashMap["id"] + notificationUser.type = guestHashMap["type"] + notificationUser.name = guestHashMap["name"] + decryptedPushMessage!!.notificationUser = notificationUser + } + } + showNotification(intent) + } + + override fun onError(e: Throwable) {} + override fun onComplete() {} + }) + } + + private fun showNotification(intent: Intent) { + val smallIcon: Int + val largeIcon: Bitmap? + val category: String + val priority = Notification.PRIORITY_HIGH + smallIcon = drawable.ic_logo + category = if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type + == "room") + ) { + Notification.CATEGORY_MESSAGE + } else { + Notification.CATEGORY_CALL + } + largeIcon = when (conversationType) { + "group" -> BitmapFactory.decodeResource( + context!!.resources, + drawable.ic_people_group_black_24px + ) + "public" -> BitmapFactory.decodeResource( + context!!.resources, drawable.ic_link_black_24px + ) + else -> // assuming one2one + if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type + == "room") + ) { + BitmapFactory.decodeResource( + context!!.resources, drawable.ic_chat_black_24dp + ) + } else { + BitmapFactory.decodeResource( + context!!.resources, drawable.ic_call_black_24dp + ) + } + } + intent.action = System.currentTimeMillis() + .toString() + val pendingIntent: PendingIntent? = PendingIntent.getActivity( + context, + 0, intent, 0 + ) + val uri: Uri = + Uri.parse(signatureVerification!!.userEntity.baseUrl) + val baseUrl = uri.host + val notificationBuilder: Builder = + Builder(context!!, "1") + .setLargeIcon(largeIcon) + .setSmallIcon(smallIcon) + .setCategory(category) + .setPriority(priority) + .setSubText(baseUrl) + .setWhen(decryptedPushMessage!!.timestamp) + .setShowWhen(true) + .setContentTitle( + EmojiCompat.get().process(decryptedPushMessage!!.subject) + ) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + if (!TextUtils.isEmpty(decryptedPushMessage!!.text)) { + notificationBuilder.setContentText( + EmojiCompat.get().process(decryptedPushMessage!!.text) + ) + } + if (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.color = context!!.resources.getColor(color.colorPrimary) + } + val notificationInfo = Bundle() + notificationInfo.putLong( + KEY_INTERNAL_USER_ID, + signatureVerification!!.userEntity.id + ) + // could be an ID or a TOKEN + + notificationInfo.putString( + KEY_ROOM_TOKEN, + decryptedPushMessage!!.id + ) + notificationInfo.putLong( + KEY_NOTIFICATION_ID, + decryptedPushMessage!!.notificationId + ) + notificationBuilder.extras = notificationInfo + if (VERSION.SDK_INT >= VERSION_CODES.O) { + + /*NotificationUtils.createNotificationChannelGroup(context, + Long.toString(crc32.getValue()), + groupName);*/ + + if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type + == "room") + ) { + createNotificationChannel( + context!!, + NOTIFICATION_CHANNEL_MESSAGES_V3, + context!!.resources + .getString(string.nc_notification_channel_messages), + context!!.resources + .getString(string.nc_notification_channel_messages), true, + NotificationManager.IMPORTANCE_HIGH + ) + notificationBuilder.setChannelId( + NOTIFICATION_CHANNEL_MESSAGES_V3 + ) + } else { + createNotificationChannel( + context!!, + NOTIFICATION_CHANNEL_CALLS_V3, + context!!.resources + .getString(string.nc_notification_channel_calls), + context!!.resources + .getString(string.nc_notification_channel_calls_description), + true, + NotificationManager.IMPORTANCE_HIGH + ) + notificationBuilder.setChannelId( + NOTIFICATION_CHANNEL_CALLS_V3 + ) + } + } else { + // red color for the lights + + notificationBuilder.setLights(-0x10000, 200, 200) + } + notificationBuilder.setContentIntent(pendingIntent) + var crc32 = CRC32() + val groupName = + signatureVerification!!.userEntity.id.toString() + "@" + decryptedPushMessage!!.id + crc32.update(groupName.toByteArray()) + notificationBuilder.setGroup(crc32.value.toString()) + + // notificationId + + crc32 = CRC32() + val stringForCrc = System.currentTimeMillis() + .toString() + crc32.update(stringForCrc.toByteArray()) + val activeStatusBarNotification = + findNotificationForRoom( + context, + signatureVerification!!.userEntity, decryptedPushMessage!!.id + ) + val notificationId: Int + notificationId = activeStatusBarNotification?.id ?: crc32.value + .toInt() + if (VERSION.SDK_INT >= VERSION_CODES.N && decryptedPushMessage!!.notificationUser != null && decryptedPushMessage!!.type == "chat") { + var style: MessagingStyle? = null + if (activeStatusBarNotification != null) { + val activeNotification: Notification? = + activeStatusBarNotification.notification + style = + MessagingStyle.extractMessagingStyleFromNotification( + activeNotification + ) + } + val person = Person.Builder() + .setKey( + signatureVerification!!.userEntity.id.toString() + + "@" + decryptedPushMessage!!.notificationUser.id + ) + .setName( + EmojiCompat.get().process( + decryptedPushMessage!!.notificationUser.name + ) + ) + .setBot(decryptedPushMessage!!.notificationUser.type == "bot") + notificationBuilder.setOnlyAlertOnce(true) + if (decryptedPushMessage!!.notificationUser.type == "user" || decryptedPushMessage!!.notificationUser.type == "guest") { + var avatarUrl: String? = ApiUtils.getUrlForAvatarWithName( + signatureVerification!!.userEntity.baseUrl, + decryptedPushMessage!!.notificationUser.id, + dimen.avatar_size + ) + if (decryptedPushMessage!!.notificationUser.type == "guest") { + avatarUrl = ApiUtils.getUrlForAvatarWithNameForGuests( + signatureVerification!!.userEntity.baseUrl, + decryptedPushMessage!!.notificationUser.name, + dimen.avatar_size + ) + } + + val target = object : Target { + override fun onSuccess(result: Drawable) { + super.onSuccess(result) + person.setIcon(IconCompat.createWithBitmap(result.toBitmap())) + notificationBuilder.setStyle( + getStyle( + person.build(), + style + ) + ) + sendNotificationWithId(notificationId, notificationBuilder.build()) + } + + override fun onError(error: Drawable?) { + super.onError(error) + notificationBuilder.setStyle(getStyle(person.build(), style)) + sendNotificationWithId(notificationId, notificationBuilder.build()) + } + + } + + val request = Images().getRequestForUrl( + Coil.loader(), context!!, avatarUrl!!, null, + target, null, CircleCropTransformation() + ) + + Coil.loader() + .load(request) + } else { + notificationBuilder.setStyle(getStyle(person.build(), style)) + sendNotificationWithId(notificationId, notificationBuilder.build()) + } + } else { + sendNotificationWithId(notificationId, notificationBuilder.build()) + } + } + + private fun getStyle( + person: Person, + style: MessagingStyle? + ): MessagingStyle? { + if (VERSION.SDK_INT >= VERSION_CODES.N) { + val newStyle = + MessagingStyle(person) + newStyle.conversationTitle = decryptedPushMessage!!.subject + newStyle.isGroupConversation = conversationType != "one2one" + style?.messages?.forEach( + Consumer { message: Message -> + newStyle.addMessage( + Message( + message.text, + message.timestamp, message.person + ) + ) + } + ) + newStyle.addMessage( + decryptedPushMessage!!.text, decryptedPushMessage!!.timestamp, + person + ) + return newStyle + } + + // we'll never come here + + return style + } + + private fun sendNotificationWithId( + notificationId: Int, + notification: Notification + ) { + val notificationManager = + NotificationManagerCompat.from(context!!) + notificationManager.notify(notificationId, notification) + if (notification.category != Notification.CATEGORY_CALL) { + val ringtonePreferencesString: String? + val soundUri: Uri? + ringtonePreferencesString = appPreferences!!.messageRingtoneUri + soundUri = if (TextUtils.isEmpty(ringtonePreferencesString)) { + Uri.parse( + "android.resource://" + context!!.packageName + + "/raw/librem_by_feandesign_message" + ) + } else { + try { + val ringtoneSettings: RingtoneSettings = + LoganSquare.parse( + ringtonePreferencesString, RingtoneSettings::class.java + ) + ringtoneSettings.getRingtoneUri() + } catch (exception: IOException) { + Uri.parse( + "android.resource://" + context!!.packageName + + "/raw/librem_by_feandesign_message" + ) + } + } + if (soundUri != null && !ApplicationWideCurrentRoomHolder.getInstance().isInCall && + (shouldPlaySound() || importantConversation) + ) { + val audioAttributesBuilder: AudioAttributes.Builder = + AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type + == "room") + ) { + audioAttributesBuilder.setUsage( + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT + ) + } else { + audioAttributesBuilder.setUsage( + AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST + ) + } + val mediaPlayer = MediaPlayer() + try { + mediaPlayer.setDataSource(context!!, soundUri) + mediaPlayer.setAudioAttributes(audioAttributesBuilder.build()) + mediaPlayer.setOnPreparedListener { mp: MediaPlayer? -> mediaPlayer.start() } + mediaPlayer.setOnCompletionListener { obj: MediaPlayer -> obj.release() } + mediaPlayer.prepareAsync() + } catch (e: IOException) { + Log.e(TAG, "Failed to set data source") + } + } + if (shouldVibrate( + appPreferences!!.shouldVibrateSetting + ) + || importantConversation + ) { + val vibrator = + context!!.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + if (VERSION.SDK_INT >= VERSION_CODES.O) { + vibrator.vibrate( + VibrationEffect.createOneShot( + 500, VibrationEffect.DEFAULT_AMPLITUDE + ) + ) + } else { + vibrator.vibrate(500) + } + } + } + } + + override fun doWork(): Result { + sharedApplication!!.componentApplication.inject(this) + context = applicationContext + val data = inputData + val subject = + data.getString(KEY_NOTIFICATION_SUBJECT) + val signature = + data.getString(KEY_NOTIFICATION_SIGNATURE) + try { + val base64DecodedSubject: ByteArray? = + Base64.decode(subject, Base64.DEFAULT) + val base64DecodedSignature: ByteArray? = + Base64.decode(signature, Base64.DEFAULT) + val pushUtils = PushUtils() + val privateKey = + pushUtils.readKeyFromFile(false) as PrivateKey + try { + signatureVerification = pushUtils.verifySignature( + base64DecodedSignature, + base64DecodedSubject + ) + if (signatureVerification!!.isSignatureValid()) { + val cipher: Cipher = Cipher.getInstance("RSA/None/PKCS1Padding") + cipher.init(Cipher.DECRYPT_MODE, privateKey) + val decryptedSubject: ByteArray? = cipher.doFinal(base64DecodedSubject) + decryptedPushMessage = + LoganSquare.parse( + String(decryptedSubject!!), + DecryptedPushMessage::class.java + ) + decryptedPushMessage!!.timestamp = System.currentTimeMillis() + if (decryptedPushMessage!!.isDelete) { + cancelExistingNotificationWithId( + context, + signatureVerification!!.getUserEntity(), decryptedPushMessage!!.notificationId + ) + } else if (decryptedPushMessage!!.isDeleteAll) { + cancelAllNotificationsForAccount( + context, + signatureVerification!!.getUserEntity() + ) + } else { + credentials = ApiUtils.getCredentials( + signatureVerification!!.getUserEntity().username, + signatureVerification!!.getUserEntity().token + ) + ncApi = retrofit!!.newBuilder() + .client( + okHttpClient!!.newBuilder().cookieJar( + JavaNetCookieJar(CookieManager()) + ).build() + ) + .build() + .create( + NcApi::class.java + ) + val hasChatSupport = signatureVerification!!.getUserEntity() + .hasSpreedFeatureCapability("chat-v2") + val shouldShowNotification = decryptedPushMessage!!.app == "spreed" + if (shouldShowNotification) { + val intent: Intent + val bundle = Bundle() + val startACall = + decryptedPushMessage!!.type == "call" || !hasChatSupport + intent = if (startACall) { + Intent( + context, MagicCallActivity::class.java + ) + } else { + Intent( + context, MainActivity::class.java + ) + } + intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + if (!signatureVerification!!.getUserEntity().hasSpreedFeatureCapability("no-ping")) { + bundle.putString( + KEY_ROOM_ID, + decryptedPushMessage!!.id + ) + } else { + bundle.putString( + KEY_ROOM_TOKEN, + decryptedPushMessage!!.id + ) + } + bundle.putParcelable( + KEY_USER_ENTITY, + signatureVerification!!.getUserEntity() + ) + bundle.putBoolean( + KEY_FROM_NOTIFICATION_START_CALL, + startACall + ) + intent.putExtras(bundle) + when (decryptedPushMessage!!.type) { + "call" -> if (!bundle.containsKey( + KEY_ROOM_TOKEN + ) + ) { + context!!.startActivity(intent) + } else { + showNotificationForCallWithNoPing(intent) + } + "room" -> if (bundle.containsKey( + KEY_ROOM_TOKEN + ) + ) { + showNotificationWithObjectData(intent) + } + "chat" -> if (decryptedPushMessage!!.notificationId != Long.MIN_VALUE) { + showNotificationWithObjectData(intent) + } else { + showNotification(intent) + } + else -> { + } + } + } + } + } + } catch (e1: NoSuchAlgorithmException) { + Log.d( + TAG, + "No proper algorithm to decrypt the message " + e1.localizedMessage + ) + } catch (e1: NoSuchPaddingException) { + Log.d( + TAG, + "No proper padding to decrypt the message " + e1.localizedMessage + ) + } catch (e1: InvalidKeyException) { + Log.d( + TAG, "Invalid private key " + e1.localizedMessage + ) + } + } catch (exception: Exception) { + Log.d( + TAG, "Something went very wrong " + exception.localizedMessage + ) + } + return Result.success() + } + + companion object { + const val TAG = "NotificationWorker" + } +} \ No newline at end of file