From 9cb7d9ece84bb97f938f2f7d9da1bdabca9862c4 Mon Sep 17 00:00:00 2001
From: jubb <hjubb@users.noreply.github.com>
Date: Mon, 12 Jul 2021 15:44:46 +1000
Subject: [PATCH] fix: conversation activity now receives extra text shared via
 intent and accepts content shared by IME

---
 .../thoughtcrime/securesms/ShareActivity.java | 13 ++++++-
 .../conversation/v2/ConversationActivityV2.kt | 27 +++++++++-----
 .../conversation/v2/input_bar/InputBar.kt     |  8 +++-
 .../v2/input_bar/InputBarEditText.kt          | 37 +++++++++++++++++--
 4 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
index d92ff18d0a..b9bfb9cb10 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
@@ -76,6 +76,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
   private ImageView                    searchAction;
   private View                         progressWheel;
   private Uri                          resolvedExtra;
+  private CharSequence                 resolvedPlaintext;
   private String                       mimeType;
   private boolean                      isPassingAlongMedia;
 
@@ -173,12 +174,16 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
     isPassingAlongMedia = false;
 
     Uri streamExtra = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
-    mimeType        = getMimeType(streamExtra);
+    CharSequence charSequenceExtra = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT);
+    mimeType = getMimeType(streamExtra);
 
     if (streamExtra != null && PartAuthority.isLocalUri(streamExtra)) {
       isPassingAlongMedia = true;
       resolvedExtra       = streamExtra;
       handleResolvedMedia(getIntent(), false);
+    } else if (charSequenceExtra != null && mimeType != null && mimeType.startsWith("text/")) {
+      resolvedPlaintext = charSequenceExtra;
+      handleResolvedMedia(getIntent(), false);
     } else {
       contactsFragment.getView().setVisibility(View.GONE);
       progressWheel.setVisibility(View.VISIBLE);
@@ -225,7 +230,11 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
   private Intent getBaseShareIntent(final @NonNull Class<?> target) {
     final Intent           intent       = new Intent(this, target);
 
-    if (resolvedExtra != null) intent.setDataAndType(resolvedExtra, mimeType);
+    if (resolvedExtra != null) {
+      intent.setDataAndType(resolvedExtra, mimeType);
+    } else if (resolvedPlaintext != null) {
+      intent.putExtra(Intent.EXTRA_TEXT, resolvedPlaintext);
+    }
 
     return intent;
   }
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 835c35bcb6..52178c4f26 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
@@ -76,8 +76,9 @@ import org.session.libsignal.utilities.guava.Optional
 import org.thoughtcrime.securesms.ApplicationContext
 import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
 import org.thoughtcrime.securesms.audio.AudioRecorder
+import org.thoughtcrime.securesms.contacts.SelectContactsActivity
+import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
 import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
-
 import org.thoughtcrime.securesms.conversation.v2.dialogs.*
 import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton
 import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate
@@ -91,6 +92,7 @@ import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar
 import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel
 import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
 import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
+import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
 import org.thoughtcrime.securesms.database.DatabaseFactory
 import org.thoughtcrime.securesms.database.DraftDatabase
 import org.thoughtcrime.securesms.database.DraftDatabase.Drafts
@@ -101,10 +103,6 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
 import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
 import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
 import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState
-import org.thoughtcrime.securesms.contacts.SelectContactsActivity
-import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
-import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
-import org.thoughtcrime.securesms.util.toPx
 import org.thoughtcrime.securesms.mediasend.Media
 import org.thoughtcrime.securesms.mediasend.MediaSendActivity
 import org.thoughtcrime.securesms.mms.*
@@ -359,12 +357,16 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
                 })
                 return
             }
+        } else if (intent.hasExtra(Intent.EXTRA_TEXT)) {
+            val dataTextExtra = intent.getCharSequenceExtra(Intent.EXTRA_TEXT) ?: ""
+            inputBar.text = dataTextExtra.toString()
+        } else {
+            val draftDB = DatabaseFactory.getDraftDatabase(this)
+            val drafts = draftDB.getDrafts(threadID)
+            draftDB.clearDrafts(threadID)
+            val text = drafts.find { it.type == DraftDatabase.Draft.TEXT }?.value ?: return
+            inputBar.text = text
         }
-        val draftDB = DatabaseFactory.getDraftDatabase(this)
-        val drafts = draftDB.getDrafts(threadID)
-        draftDB.clearDrafts(threadID)
-        val text = drafts.find { it.type == DraftDatabase.Draft.TEXT }?.value ?: return
-        inputBar.text = text
     }
 
     private fun addOpenGroupGuidelinesIfNeeded() {
@@ -885,6 +887,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
         }
     }
 
+    override fun commitInputContent(contentUri: Uri) {
+        val media = Media(contentUri, MediaUtil.getMimeType(this, contentUri)!!, 0, 0, 0, 0, Optional.absent(), Optional.absent())
+        startActivityForResult(MediaSendActivity.buildEditorIntent(this, listOf( media ), thread, getMessageBody()), ConversationActivityV2.PICK_FROM_LIBRARY)
+    }
+
     private fun sendTextOnlyMessage() {
         // Create the message
         val message = VisibleMessage()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
index 53ebf036ff..a5a7fe6061 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
 
 import android.content.Context
 import android.content.res.Resources
+import android.net.Uri
 import android.text.InputType
 import android.util.AttributeSet
 import android.view.LayoutInflater
@@ -19,9 +20,9 @@ import org.thoughtcrime.securesms.conversation.v2.messages.QuoteView
 import org.thoughtcrime.securesms.conversation.v2.messages.QuoteViewDelegate
 import org.thoughtcrime.securesms.database.model.MessageRecord
 import org.thoughtcrime.securesms.database.model.MmsMessageRecord
+import org.thoughtcrime.securesms.mms.GlideRequests
 import org.thoughtcrime.securesms.util.toDp
 import org.thoughtcrime.securesms.util.toPx
-import org.thoughtcrime.securesms.mms.GlideRequests
 import kotlin.math.max
 import kotlin.math.roundToInt
 
@@ -96,6 +97,10 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
         setHeight(newHeight)
     }
 
+    override fun commitInputContent(contentUri: Uri) {
+        delegate?.commitInputContent(contentUri)
+    }
+
     private fun toggleAttachmentOptions() {
         delegate?.toggleAttachmentOptions()
     }
@@ -193,4 +198,5 @@ interface InputBarDelegate {
     fun onMicrophoneButtonCancel(event: MotionEvent)
     fun onMicrophoneButtonUp(event: MotionEvent)
     fun sendMessage()
+    fun commitInputContent(contentUri: Uri)
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt
index 39db2f6d25..1d1446100e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt
@@ -2,12 +2,15 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
 
 import android.content.Context
 import android.content.res.Resources
-import android.text.Layout
-import android.text.StaticLayout
+import android.net.Uri
+import android.os.Build
 import android.util.AttributeSet
-import android.util.Log
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputConnection
 import android.widget.RelativeLayout
 import androidx.appcompat.widget.AppCompatEditText
+import androidx.core.view.inputmethod.EditorInfoCompat
+import androidx.core.view.inputmethod.InputConnectionCompat
 import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities
 import org.thoughtcrime.securesms.util.toPx
 import kotlin.math.max
@@ -41,10 +44,38 @@ class InputBarEditText : AppCompatEditText {
         this.layoutParams = layoutParams
         delegate?.inputBarEditTextHeightChanged(constrainedHeight.roundToInt())
     }
+
+    override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection {
+        val ic: InputConnection = super.onCreateInputConnection(editorInfo)
+        EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/png", "image/gif", "image/jpg"))
+
+        val callback =
+                InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, opts ->
+                    val lacksPermission = (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0
+                    // read and display inputContentInfo asynchronously
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && lacksPermission) {
+                        try {
+                            inputContentInfo.requestPermission()
+                        } catch (e: Exception) {
+                            return@OnCommitContentListener false // return false if failed
+                        }
+                    }
+
+                    inputContentInfo.contentUri
+
+                    // read and display inputContentInfo asynchronously.
+                    delegate?.commitInputContent(inputContentInfo.contentUri)
+
+                    true  // return true if succeeded
+                }
+        return InputConnectionCompat.createWrapper(ic, editorInfo, callback)
+    }
+
 }
 
 interface InputBarEditTextDelegate {
 
     fun inputBarEditTextContentChanged(text: CharSequence)
     fun inputBarEditTextHeightChanged(newValue: Int)
+    fun commitInputContent(contentUri: Uri)
 }
\ No newline at end of file