Move notification worker to Kotlin & Coin

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2019-10-26 22:34:39 +02:00
parent 5141abeecc
commit a0d932e946
2 changed files with 762 additions and 684 deletions

View File

@ -1,684 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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<RoomOverall>() {
@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<NotificationOverall>() {
@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<String, HashMap<String, String>> subjectRichParameters = notification
.getSubjectRichParameters();
decryptedPushMessage.setTimestamp(notification.getDatetime().getMillis());
if (subjectRichParameters != null && subjectRichParameters.size() > 0) {
HashMap<String, String> callHashMap = subjectRichParameters.get("call");
HashMap<String, String> userHashMap = subjectRichParameters.get("user");
HashMap<String, String> 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<CloseableReference<CloseableImage>> 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<CloseableReference<CloseableImage>> 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();
}
}

View File

@ -0,0 +1,762 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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<RoomOverall?> {
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<NotificationOverall?> {
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<String, HashMap<String, String>>? =
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<RingtoneSettings>(
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<DecryptedPushMessage>(
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"
}
}