From 53c7ea2831d32e6b8817c741fa124b0a7a214522 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 25 May 2020 15:21:31 +0200
Subject: [PATCH 1/2] 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 <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(frameId: Int,
     }
 }
 
+/**
+ * Return a list of all child Fragments, recursively
+ */
+fun Fragment.getAllChildFragments(): List<Fragment> {
+    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<View>(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<Bitmap> {
+        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
     }
 
     // ==============================================================================================================

From a036be6436d620157a9b5fcbe46d438d063ff5d7 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoitm@matrix.org>
Date: Mon, 25 May 2020 15:42:58 +0200
Subject: [PATCH 2/2] Fix missing title in BugReport screen

---
 .../im/vector/riotx/features/rageshake/BugReportActivity.kt     | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReportActivity.kt
index 5c1428cb54..f943186e2e 100755
--- a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReportActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReportActivity.kt
@@ -70,6 +70,8 @@ class BugReportActivity : VectorBaseActivity() {
             bug_report_button_include_crash_logs.isVisible = false
 
             // Keep the screenshot
+        } else {
+            supportActionBar?.setTitle(R.string.title_activity_bug_report)
         }
     }