Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,21 @@ class FeedbackEmailHandler(
const val AUTHORITY_SUFFIX = "providers.fileprovider"
const val SCREENSHOTS_DIR = "feedback_screenshots"
const val LOGS_DIR = "feedback_logs"
const val MAX_EMAIL_BODY_CHARS = 50_000
private val log = LoggerFactory.getLogger(FeedbackEmailHandler::class.java)
}

private fun sanitizeEmailBody(body: String, hasLogAttachment: Boolean = true): String {
if (body.length <= MAX_EMAIL_BODY_CHARS) return body
val suffix = if (hasLogAttachment) " See attached file." else ""
return buildString {
append(body.take(MAX_EMAIL_BODY_CHARS))
append("\n\n---\n(Log truncated: ")
append(body.length - MAX_EMAIL_BODY_CHARS)
append(" chars omitted.$suffix)")
}
}

suspend fun captureAndPrepareScreenshotUri(
activity: Activity,
): Uri? {
Expand Down Expand Up @@ -138,32 +150,35 @@ class FeedbackEmailHandler(
emailRecipient = emailRecipient,
subject = subject,
body = body,
attachmentUris = attachmentUris
attachmentUris = attachmentUris,
hasLogAttachment = logContentUri != null
)
}

fun getIntentBasedOnAttachments(
emailRecipient: String,
subject: String,
body: String,
attachmentUris: MutableList<Uri>
attachmentUris: MutableList<Uri>,
hasLogAttachment: Boolean = false
): Intent {
val safeBody = sanitizeEmailBody(body, hasLogAttachment)
return when {
// No screenshot or log file (if both files failed to be created)
attachmentUris.isEmpty() -> {
Intent(Intent.ACTION_SENDTO).apply {
data = "mailto:".toUri()
putExtra(Intent.EXTRA_EMAIL, arrayOf(emailRecipient))
putExtra(Intent.EXTRA_SUBJECT, subject)
putExtra(Intent.EXTRA_TEXT, body)
putExtra(Intent.EXTRA_TEXT, safeBody)
}
}
// Screenshot and/or log file
else -> {
Intent(Intent.ACTION_SEND_MULTIPLE).apply {
putExtra(Intent.EXTRA_EMAIL, arrayOf(emailRecipient))
putExtra(Intent.EXTRA_SUBJECT, subject)
putExtra(Intent.EXTRA_TEXT, body)
putExtra(Intent.EXTRA_TEXT, safeBody)
putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(attachmentUris))
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
type = "message/rfc822"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.itsaky.androidide.utils

import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.TransactionTooLargeException
import android.view.PixelCopy
import android.view.View
import android.widget.Toast
Expand All @@ -19,10 +21,12 @@ import androidx.core.net.toUri
import androidx.core.text.HtmlCompat
import androidx.lifecycle.lifecycleScope
import com.itsaky.androidide.buildinfo.BuildInfo
import com.itsaky.androidide.eventbus.events.editor.ReportCaughtExceptionEvent
import com.itsaky.androidide.resources.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileOutputStream
Expand Down Expand Up @@ -334,13 +338,30 @@ object FeedbackManager {
feedbackBody,
)

if (emailIntent.resolveActivity(activity.packageManager) != null) {
runCatching {
activity.startActivity(emailIntent)
} else {
Toast
.makeText(activity,
activity.getString(R.string.no_email_apps), Toast.LENGTH_LONG)
.show()
}.onFailure { e ->
when {
e is ActivityNotFoundException -> {
Toast.makeText(activity, R.string.no_email_apps, Toast.LENGTH_LONG).show()
}
e is TransactionTooLargeException ||
(e is RuntimeException && e.cause is TransactionTooLargeException) -> {
logger.error("Intent transaction failed: Data too large", e)
Toast.makeText(activity, R.string.msg_feedback_log_too_long, Toast.LENGTH_LONG).show()
}
else -> {
logger.error("Intent transaction failed: Unknown error", e)
EventBus.getDefault().post(
ReportCaughtExceptionEvent(
throwable = e,
message = "Feedback email intent failed",
extras = mapOf("screen" to getCurrentScreenName(activity))
)
)
Toast.makeText(activity, R.string.unknown_error, Toast.LENGTH_LONG).show()
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions resources/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@
Internet access is required.</string>
<string name="code_on_the_go">Code on the Go</string>
<string name="feedback_email_subject">Feedback for Code on the Go</string>
<string name="msg_feedback_log_too_long">The log is too large to send directly.</string>
<string name="msg_no_internet_no_problem">No computer? No Internet?\nNo problem.</string>
<string name="offline_message">Offline</string>
<string name="more_label">More</string>
Expand Down