diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index b5aa6a1ae3..c25d157bb3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -248,7 +248,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe searchBottomBar.setEventListener(this) setUpSearchResultObserver() scrollToFirstUnreadMessageIfNeeded() - markAllAsRead() showOrHideInputIfNeeded() if (this.thread.isOpenGroupRecipient) { val openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadID) @@ -262,6 +261,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe override fun onResume() { super.onResume() ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadID) + markAllAsRead() } override fun onPause() { @@ -505,7 +505,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } else { MarkReadReceiver.process(this, messages) } - ApplicationContext.getInstance(this).messageNotifier.updateNotification(this, threadID) + ApplicationContext.getInstance(this).messageNotifier.updateNotification(this, false, 0) } override fun inputBarHeightChanged(newValue: Int) { @@ -984,7 +984,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } private fun showCamera() { - attachmentManager.capturePhoto(this, ConversationActivityV2.TAKE_PHOTO) + attachmentManager.capturePhoto(this, ConversationActivityV2.TAKE_PHOTO, thread); } override fun onAttachmentChanged() { @@ -1013,11 +1013,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val uri = intent?.data ?: return prepMediaForSending(uri, AttachmentManager.MediaType.DOCUMENT).addListener(mediaPreppedListener) } - TAKE_PHOTO -> { - if (resultCode != RESULT_OK) { return } - val uri = attachmentManager.captureUri ?: return - prepMediaForSending(uri, AttachmentManager.MediaType.IMAGE).addListener(mediaPreppedListener) - } PICK_GIF -> { intent ?: return val uri = intent.data ?: return @@ -1026,7 +1021,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val height = intent.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0) prepMediaForSending(uri, type, width, height).addListener(mediaPreppedListener) } - PICK_FROM_LIBRARY -> { + PICK_FROM_LIBRARY, + TAKE_PHOTO -> { intent ?: return val body = intent.getStringExtra(MediaSendActivity.EXTRA_MESSAGE) val media = intent.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA) ?: return diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 70e4737846..395d68bf34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -92,6 +92,9 @@ object ConversationMenuHelper { inflater.inflate(R.menu.menu_conversation_muted, menu) } else { inflater.inflate(R.menu.menu_conversation_unmuted, menu) + } + + if (thread.isGroupRecipient && !thread.isMuted) { inflater.inflate(R.menu.menu_conversation_notification_settings, menu) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java index d1d7e0b81c..dd90b699e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/AttachmentManager.java @@ -25,7 +25,6 @@ import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; -import android.provider.MediaStore; import android.provider.OpenableColumns; import android.text.TextUtils; import android.util.Pair; @@ -34,9 +33,12 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.session.libsignal.utilities.NoExternalStorageException; -import org.thoughtcrime.securesms.giph.ui.GiphyActivity; +import org.session.libsession.utilities.recipients.Recipient; +import org.session.libsignal.utilities.ListenableFuture; import org.session.libsignal.utilities.Log; +import org.session.libsignal.utilities.SettableFuture; +import org.session.libsignal.utilities.guava.Optional; +import org.thoughtcrime.securesms.giph.ui.GiphyActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mms.AudioSlide; import org.thoughtcrime.securesms.mms.DocumentSlide; @@ -50,16 +52,8 @@ import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.providers.BlobProvider; -import org.session.libsignal.utilities.ExternalStorageUtil; -import org.thoughtcrime.securesms.util.FileProviderUtil; import org.thoughtcrime.securesms.util.MediaUtil; -import org.session.libsignal.utilities.guava.Optional; -import org.session.libsession.utilities.recipients.Recipient; -import org.session.libsignal.utilities.ListenableFuture; -import org.session.libsignal.utilities.SettableFuture; - -import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; @@ -67,8 +61,6 @@ import java.util.List; import network.loki.messenger.R; -import static android.provider.MediaStore.EXTRA_OUTPUT; - public class AttachmentManager { private final static String TAG = AttachmentManager.class.getSimpleName(); @@ -278,25 +270,15 @@ public class AttachmentManager { return captureUri; } - public void capturePhoto(Activity activity, int requestCode) { + public void capturePhoto(Activity activity, int requestCode, Recipient recipient) { Permissions.with(activity) .request(Manifest.permission.CAMERA) .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_camera_permission_in_order_to_take_photos_but_it_has_been_permanently_denied)) .withRationaleDialog(activity.getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera),R.drawable.ic_baseline_photo_camera_24) .onAllGranted(() -> { - try { - File captureFile = File.createTempFile("conversation-capture", ".jpg", ExternalStorageUtil.getImageDir(activity)); - Uri captureUri = FileProviderUtil.getUriFor(context, captureFile); - Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - captureIntent.putExtra(EXTRA_OUTPUT, captureUri); - captureIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (captureIntent.resolveActivity(activity.getPackageManager()) != null) { - Log.d(TAG, "captureUri path is " + captureUri.getPath()); - this.captureUri = captureUri; - activity.startActivityForResult(captureIntent, requestCode); - } - } catch (IOException | NoExternalStorageException e) { - throw new RuntimeException("Error creating image capture intent.", e); + Intent captureIntent = MediaSendActivity.buildCameraIntent(activity, recipient); + if (captureIntent.resolveActivity(activity.getPackageManager()) != null) { + activity.startActivityForResult(captureIntent, requestCode); } }) .execute(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt index f6010bb53d..f13c2824d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.ClipData import android.content.ClipboardManager import android.content.Context +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -14,9 +15,11 @@ import android.widget.Toast import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.* import network.loki.messenger.R +import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.contacts.Contact import org.session.libsession.utilities.Address import org.session.libsession.utilities.recipients.Recipient +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.util.UiModeUtilities @@ -63,11 +66,23 @@ class UserDetailsBottomSheet : BottomSheetDialogFragment() { } nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally publicKeyTextView.text = publicKey - copyButton.setOnClickListener { + publicKeyTextView.setOnLongClickListener { val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("Session ID", publicKey) clipboard.setPrimaryClip(clip) Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show() + true + } + messageButton.setOnClickListener { + val threadId = MessagingModuleConfiguration.shared.storage.getThreadId(recipient) + val intent = Intent( + context, + ConversationActivityV2::class.java + ) + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId ?: -1) + startActivity(intent) + dismiss() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java index d2b36a6892..3e9fd7905e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java @@ -20,19 +20,18 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; +import org.session.libsession.utilities.Address; import org.session.libsession.utilities.MediaTypes; +import org.session.libsession.utilities.Util; +import org.session.libsession.utilities.concurrent.SimpleTask; +import org.session.libsession.utilities.recipients.Recipient; +import org.session.libsignal.utilities.Log; import org.session.libsignal.utilities.guava.Optional; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; -import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.scribbles.ImageEditorFragment; -import org.session.libsession.utilities.Address; -import org.session.libsession.utilities.recipients.Recipient; -import org.session.libsession.utilities.concurrent.SimpleTask; -import org.session.libsession.utilities.Util; - import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -87,7 +86,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple } /** - * Get an intent to launch the media send flow starting with the picker. + * Get an intent to launch the media send flow starting with the camera. */ public static Intent buildCameraIntent(@NonNull Context context, @NonNull Recipient recipient) { Intent intent = buildGalleryIntent(context, recipient, ""); diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index e7f8e8e5c8..936548ecc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -90,11 +90,11 @@ public class DefaultMessageNotifier implements MessageNotifier { private static final String TAG = DefaultMessageNotifier.class.getSimpleName(); - public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply"; + public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply"; public static final String LATEST_MESSAGE_ID_TAG = "extra_latest_message_id"; - private static final int FOREGROUND_ID = 313399; - private static final int SUMMARY_NOTIFICATION_ID = 1338; + private static final int FOREGROUND_ID = 313399; + private static final int SUMMARY_NOTIFICATION_ID = 1338; private static final int PENDING_MESSAGES_ID = 1111; private static final String NOTIFICATION_GROUP = "messages"; private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2); @@ -284,8 +284,9 @@ public class DefaultMessageNotifier implements MessageNotifier { sendMultipleThreadNotification(context, notificationState, signal); } else if (notificationState.getMessageCount() > 0){ sendSingleThreadNotification(context, notificationState, signal, false); + } else { + cancelActiveNotifications(context); } - cancelOrphanedNotifications(context, notificationState); updateBadge(context, notificationState.getMessageCount()); @@ -314,12 +315,12 @@ public class DefaultMessageNotifier implements MessageNotifier { List notifications = notificationState.getNotifications(); Recipient recipient = notifications.get(0).getRecipient(); int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0)); - String messageIdTag = String.valueOf(notifications.get(0).getId()); + String messageIdTag = String.valueOf(notifications.get(0).getTimestamp()); NotificationManager notificationManager = ServiceUtil.getNotificationManager(context); for (StatusBarNotification notification: notificationManager.getActiveNotifications()) { - - if (messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) { + if ( (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && notification.isAppGroup() == bundled) + && messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) { return; } } @@ -401,6 +402,16 @@ public class DefaultMessageNotifier implements MessageNotifier { builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY); builder.setAutoCancel(true); + String messageIdTag = String.valueOf(notifications.get(0).getTimestamp()); + + NotificationManager notificationManager = ServiceUtil.getNotificationManager(context); + for (StatusBarNotification notification: notificationManager.getActiveNotifications()) { + if (notification.getId() == SUMMARY_NOTIFICATION_ID + && messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) { + return; + } + } + long timestamp = notifications.get(0).getTimestamp(); if (timestamp != 0) builder.setWhen(timestamp); @@ -420,6 +431,8 @@ public class DefaultMessageNotifier implements MessageNotifier { MentionUtilities.highlightMentions(notifications.get(0).getText(), notifications.get(0).getThreadId(), context)); } + builder.putStringExtra(LATEST_MESSAGE_ID_TAG, messageIdTag); + Notification notification = builder.build(); NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build()); Log.i(TAG, "Posted notification. " + notification.toString()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java index 24374ddd0f..15b62df3c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java @@ -16,8 +16,8 @@ import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.Util; import org.session.libsession.utilities.recipients.Recipient; import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.home.HomeActivity; import org.thoughtcrime.securesms.database.SessionContactDatabase; +import org.thoughtcrime.securesms.home.HomeActivity; import java.util.LinkedList; import java.util.List; @@ -72,6 +72,10 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu extend(new NotificationCompat.WearableExtender().addAction(markAllAsReadAction)); } + public void putStringExtra(String key, String value) { + extras.putString(key,value); + } + public void addMessageBody(@NonNull Recipient sender, Recipient threadRecipient, @Nullable CharSequence body) { String displayName = sender.toShortString(); if (threadRecipient.isOpenGroupRecipient()) { diff --git a/app/src/main/res/layout/fragment_user_details_bottom_sheet.xml b/app/src/main/res/layout/fragment_user_details_bottom_sheet.xml index 985de78a64..4b46e134cd 100644 --- a/app/src/main/res/layout/fragment_user_details_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_user_details_bottom_sheet.xml @@ -111,12 +111,12 @@