From 53c7ea2831d32e6b8817c741fa124b0a7a214522 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 25 May 2020 15:21:31 +0200 Subject: [PATCH] Kotlin: use orEmpty() for Maps --- CHANGES.md | 1 + .../vector/riotx/core/extensions/Fragment.kt | 7 ++ .../riotx/features/rageshake/BugReporter.kt | 76 +++++++++++++------ 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d88f9952e4..aadd03d1f1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Bugfix 🐛: - Fix issues with FontScale switch (#69, #645) - "Seen by" uses 12h time (#1378) - Enable markdown (if active) when sending emote (#734) + - Screenshots for Rageshake now includes Dialogs such as BottomSheet (#1349) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt index b93ab3fdce..c28dcf12d3 100644 --- a/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt @@ -80,5 +80,12 @@ fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, } } +/** + * Return a list of all child Fragments, recursively + */ +fun Fragment.getAllChildFragments(): List { + return listOf(this) + childFragmentManager.fragments.map { it.getAllChildFragments() }.flatten() +} + // Define a missing constant const val POP_BACK_STACK_EXCLUSIVE = 0 diff --git a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt index a001567635..d9020afab4 100755 --- a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt @@ -19,17 +19,20 @@ package im.vector.riotx.features.rageshake import android.annotation.SuppressLint -import android.app.Activity import android.content.Context import android.content.Intent import android.graphics.Bitmap +import android.graphics.Canvas import android.os.AsyncTask import android.os.Build import android.view.View +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentActivity import im.vector.matrix.android.api.Matrix import im.vector.riotx.BuildConfig import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder +import im.vector.riotx.core.extensions.getAllChildFragments import im.vector.riotx.core.extensions.toOnOff import im.vector.riotx.features.settings.VectorLocale import im.vector.riotx.features.settings.VectorPreferences @@ -423,7 +426,7 @@ class BugReporter @Inject constructor( /** * Send a bug report either with email or with Vector. */ - fun openBugReportScreen(activity: Activity, forSuggestion: Boolean = false) { + fun openBugReportScreen(activity: FragmentActivity, forSuggestion: Boolean = false) { screenshot = takeScreenshot(activity) val intent = Intent(activity, BugReportActivity::class.java) @@ -512,41 +515,64 @@ class BugReporter @Inject constructor( * * @return the screenshot */ - private fun takeScreenshot(activity: Activity): Bitmap? { - // get content view - val contentView = activity.findViewById(android.R.id.content) - if (contentView == null) { - Timber.e("Cannot find content view on $activity. Cannot take screenshot.") - return null - } - + private fun takeScreenshot(activity: FragmentActivity): Bitmap? { // get the root view to snapshot - val rootView = contentView.rootView + val rootView = activity.window?.decorView?.rootView if (rootView == null) { Timber.e("Cannot find root view on $activity. Cannot take screenshot.") return null } - // refresh it + + val mainBitmap = getBitmap(rootView) + + if (mainBitmap == null) { + Timber.e("Cannot get main screenshot") + return null + } + + try { + val cumulBitmap = Bitmap.createBitmap(mainBitmap.width, mainBitmap.height, Bitmap.Config.ARGB_8888) + + val canvas = Canvas(cumulBitmap) + canvas.drawBitmap(mainBitmap, 0f, 0f, null) + // Add the dialogs if any + getDialogBitmaps(activity).forEach { + canvas.drawBitmap(it, 0f, 0f, null) + } + + return cumulBitmap + } catch (e: Throwable) { + Timber.e(e, "Cannot get snapshot of screen: $e") + } + + return null + } + + private fun getDialogBitmaps(activity: FragmentActivity): List { + return activity.supportFragmentManager.fragments + .map { it.getAllChildFragments() } + .flatten() + .filterIsInstance(DialogFragment::class.java) + .mapNotNull { fragment -> + fragment.dialog?.window?.decorView?.rootView?.let { rootView -> + getBitmap(rootView) + } + } + } + + private fun getBitmap(rootView: View): Bitmap? { @Suppress("DEPRECATION") rootView.isDrawingCacheEnabled = false @Suppress("DEPRECATION") rootView.isDrawingCacheEnabled = true - try { + return try { @Suppress("DEPRECATION") - var bitmap = rootView.drawingCache - - // Make a copy, because if Activity is destroyed, the bitmap will be recycled - bitmap = Bitmap.createBitmap(bitmap) - - return bitmap - } catch (oom: OutOfMemoryError) { - Timber.e(oom, "Cannot get drawing cache for $activity OOM.") - } catch (e: Exception) { - Timber.e(e, "Cannot get snapshot of screen: $e") + rootView.drawingCache + } catch (e: Throwable) { + Timber.e(e, "Cannot get snapshot of dialog: $e") + null } - - return null } // ==============================================================================================================