Add test for BugReportPresenter
This commit is contained in:
parent
fa37224109
commit
4b7f64dcff
8 changed files with 366 additions and 10 deletions
|
|
@ -23,7 +23,6 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.core.net.toUri
|
|
||||||
import io.element.android.features.rageshake.crash.CrashDataStore
|
import io.element.android.features.rageshake.crash.CrashDataStore
|
||||||
import io.element.android.features.rageshake.logs.VectorFileLogger
|
import io.element.android.features.rageshake.logs.VectorFileLogger
|
||||||
import io.element.android.features.rageshake.reporter.BugReporter
|
import io.element.android.features.rageshake.reporter.BugReporter
|
||||||
|
|
@ -73,7 +72,7 @@ class BugReportPresenter @Inject constructor(
|
||||||
override fun present(): BugReportState {
|
override fun present(): BugReportState {
|
||||||
val screenshotUri = rememberSaveable {
|
val screenshotUri = rememberSaveable {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
screenshotHolder.getFile()?.toUri()?.toString()
|
screenshotHolder.getFileUri()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val crashInfo: String by crashDataStore
|
val crashInfo: String by crashDataStore
|
||||||
|
|
@ -150,6 +149,6 @@ class BugReportPresenter @Inject constructor(
|
||||||
private fun CoroutineScope.resetAll() = launch {
|
private fun CoroutineScope.resetAll() = launch {
|
||||||
screenshotHolder.reset()
|
screenshotHolder.reset()
|
||||||
crashDataStore.reset()
|
crashDataStore.reset()
|
||||||
VectorFileLogger.getFromTimber().reset()
|
VectorFileLogger.getFromTimber()?.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ class VectorFileLogger(
|
||||||
) : Timber.Tree() {
|
) : Timber.Tree() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getFromTimber(): VectorFileLogger {
|
fun getFromTimber(): VectorFileLogger? {
|
||||||
return Timber.forest().filterIsInstance<VectorFileLogger>().first()
|
return Timber.forest().filterIsInstance<VectorFileLogger>().firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val SIZE_20MB = 20 * 1024 * 1024
|
private const val SIZE_20MB = 20 * 1024 * 1024
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package io.element.android.features.rageshake.reporter
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.core.net.toFile
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.features.rageshake.R
|
import io.element.android.features.rageshake.R
|
||||||
import io.element.android.features.rageshake.crash.CrashDataStore
|
import io.element.android.features.rageshake.crash.CrashDataStore
|
||||||
import io.element.android.features.rageshake.logs.VectorFileLogger
|
import io.element.android.features.rageshake.logs.VectorFileLogger
|
||||||
|
|
@ -153,7 +155,7 @@ class DefaultBugReporter @Inject constructor(
|
||||||
val gzippedFiles = ArrayList<File>()
|
val gzippedFiles = ArrayList<File>()
|
||||||
|
|
||||||
val vectorFileLogger = VectorFileLogger.getFromTimber()
|
val vectorFileLogger = VectorFileLogger.getFromTimber()
|
||||||
if (withDevicesLogs) {
|
if (withDevicesLogs && vectorFileLogger != null) {
|
||||||
val files = vectorFileLogger.getLogFiles()
|
val files = vectorFileLogger.getLogFiles()
|
||||||
files.mapNotNullTo(gzippedFiles) { f ->
|
files.mapNotNullTo(gzippedFiles) { f ->
|
||||||
if (!mIsCancelled) {
|
if (!mIsCancelled) {
|
||||||
|
|
@ -254,7 +256,10 @@ class DefaultBugReporter @Inject constructor(
|
||||||
mBugReportFiles.addAll(gzippedFiles)
|
mBugReportFiles.addAll(gzippedFiles)
|
||||||
|
|
||||||
if (withScreenshot) {
|
if (withScreenshot) {
|
||||||
screenshotHolder.getFile()?.let { screenshotFile ->
|
screenshotHolder.getFileUri()
|
||||||
|
?.toUri()
|
||||||
|
?.toFile()
|
||||||
|
?.let { screenshotFile ->
|
||||||
try {
|
try {
|
||||||
builder.addFormDataPart(
|
builder.addFormDataPart(
|
||||||
"file",
|
"file",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.rageshake.screenshot
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.libraries.androidutils.bitmap.writeBitmap
|
import io.element.android.libraries.androidutils.bitmap.writeBitmap
|
||||||
import io.element.android.libraries.androidutils.file.safeDelete
|
import io.element.android.libraries.androidutils.file.safeDelete
|
||||||
|
|
@ -38,7 +39,12 @@ class DefaultScreenshotHolder @Inject constructor(
|
||||||
file.writeBitmap(data, Bitmap.CompressFormat.PNG, 85)
|
file.writeBitmap(data, Bitmap.CompressFormat.PNG, 85)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFile() = file.takeIf { it.exists() && it.length() > 0 }
|
override fun getFileUri(): String? {
|
||||||
|
return file
|
||||||
|
.takeIf { it.exists() && it.length() > 0 }
|
||||||
|
?.toUri()
|
||||||
|
?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
override fun reset() {
|
override fun reset() {
|
||||||
file.safeDelete()
|
file.safeDelete()
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,9 @@
|
||||||
package io.element.android.features.rageshake.screenshot
|
package io.element.android.features.rageshake.screenshot
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
interface ScreenshotHolder {
|
interface ScreenshotHolder {
|
||||||
fun writeBitmap(data: Bitmap)
|
fun writeBitmap(data: Bitmap)
|
||||||
fun getFile(): File?
|
fun getFileUri(): String?
|
||||||
fun reset()
|
fun reset()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.bugreport
|
||||||
|
|
||||||
|
import app.cash.molecule.RecompositionClock
|
||||||
|
import app.cash.molecule.moleculeFlow
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.rageshake.crash.ui.A_CRASH_DATA
|
||||||
|
import io.element.android.features.rageshake.crash.ui.FakeCrashDataStore
|
||||||
|
import io.element.android.libraries.architecture.Async
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
const val A_SHORT_DESCRIPTION = "bug!"
|
||||||
|
const val A_LONG_DESCRIPTION = "I have seen a bug!"
|
||||||
|
|
||||||
|
class BugReportPresenterTest {
|
||||||
|
@Test
|
||||||
|
fun `present - initial state`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.hasCrashLogs).isFalse()
|
||||||
|
assertThat(initialState.formState).isEqualTo(BugReportFormState.Default)
|
||||||
|
assertThat(initialState.sending).isEqualTo(Async.Uninitialized)
|
||||||
|
assertThat(initialState.screenshotUri).isNull()
|
||||||
|
assertThat(initialState.sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat(initialState.submitEnabled).isFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - set description`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetDescription(A_SHORT_DESCRIPTION))
|
||||||
|
assertThat(awaitItem().submitEnabled).isFalse()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetDescription(A_LONG_DESCRIPTION))
|
||||||
|
assertThat(awaitItem().submitEnabled).isTrue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - can contact`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetCanContact(true))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(canContact = true))
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetCanContact(false))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(canContact = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send crash logs`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
// Since this is true by default, start by disabling
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendCrashLog(false))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendCrashLogs = false))
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendCrashLog(true))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendCrashLogs = true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send logs`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
// Since this is true by default, start by disabling
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendLog(false))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendLogs = false))
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendLog(true))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendLogs = true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send screenshot`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(),
|
||||||
|
FakeScreenshotHolder(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendScreenshot(true))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendScreenshot = true))
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SetSendScreenshot(false))
|
||||||
|
assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendScreenshot = false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - reset all`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(),
|
||||||
|
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
|
||||||
|
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
skipItems(1)
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.hasCrashLogs).isTrue()
|
||||||
|
assertThat(initialState.screenshotUri).isEqualTo(A_SCREENSHOT_URI)
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.ResetAll)
|
||||||
|
val resetState = awaitItem()
|
||||||
|
assertThat(resetState.hasCrashLogs).isFalse()
|
||||||
|
// TODO Make it live assertThat(resetState.screenshotUri).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send success`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(mode = FakeBugReporterMode.Success),
|
||||||
|
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
|
||||||
|
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
|
||||||
|
skipItems(1)
|
||||||
|
val progressState = awaitItem()
|
||||||
|
assertThat(progressState.sending).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(progressState.sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(0.5f)
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(1f)
|
||||||
|
skipItems(1)
|
||||||
|
assertThat(awaitItem().sending).isEqualTo(Async.Success(Unit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send failure`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(mode = FakeBugReporterMode.Failure),
|
||||||
|
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
|
||||||
|
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
|
||||||
|
skipItems(1)
|
||||||
|
val progressState = awaitItem()
|
||||||
|
assertThat(progressState.sending).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(progressState.sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(0.5f)
|
||||||
|
// Failure
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat((awaitItem().sending as Async.Failure).error.message).isEqualTo(A_REASON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - send cancel`() = runTest {
|
||||||
|
val presenter = BugReportPresenter(
|
||||||
|
FakeBugReporter(mode = FakeBugReporterMode.Cancel),
|
||||||
|
FakeCrashDataStore(crashData = A_CRASH_DATA, appHasCrashed = true),
|
||||||
|
FakeScreenshotHolder(screenshotUri = A_SCREENSHOT_URI),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
initialState.eventSink.invoke(BugReportEvents.SendBugReport)
|
||||||
|
skipItems(1)
|
||||||
|
val progressState = awaitItem()
|
||||||
|
assertThat(progressState.sending).isEqualTo(Async.Loading(null))
|
||||||
|
assertThat(progressState.sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(0.5f)
|
||||||
|
// Cancelled
|
||||||
|
assertThat(awaitItem().sendingProgress).isEqualTo(0f)
|
||||||
|
assertThat(awaitItem().sending).isEqualTo(Async.Uninitialized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.bugreport
|
||||||
|
|
||||||
|
import io.element.android.features.rageshake.reporter.BugReporter
|
||||||
|
import io.element.android.features.rageshake.reporter.BugReporterListener
|
||||||
|
import io.element.android.features.rageshake.reporter.ReportType
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
const val A_REASON = "There has been a failure"
|
||||||
|
|
||||||
|
class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Success) : BugReporter {
|
||||||
|
override fun sendBugReport(
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
|
reportType: ReportType,
|
||||||
|
withDevicesLogs: Boolean,
|
||||||
|
withCrashLogs: Boolean,
|
||||||
|
withKeyRequestHistory: Boolean,
|
||||||
|
withScreenshot: Boolean,
|
||||||
|
theBugDescription: String,
|
||||||
|
serverVersion: String,
|
||||||
|
canContact: Boolean,
|
||||||
|
customFields: Map<String, String>?,
|
||||||
|
listener: BugReporterListener?,
|
||||||
|
) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
delay(100)
|
||||||
|
listener?.onProgress(0)
|
||||||
|
delay(100)
|
||||||
|
listener?.onProgress(50)
|
||||||
|
delay(100)
|
||||||
|
when (mode) {
|
||||||
|
FakeBugReporterMode.Success -> Unit
|
||||||
|
FakeBugReporterMode.Failure -> {
|
||||||
|
listener?.onUploadFailed(A_REASON)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
FakeBugReporterMode.Cancel -> {
|
||||||
|
listener?.onUploadCancelled()
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listener?.onProgress(100)
|
||||||
|
delay(100)
|
||||||
|
listener?.onUploadSucceed(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class FakeBugReporterMode {
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
Cancel
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.bugreport
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import io.element.android.features.rageshake.screenshot.ScreenshotHolder
|
||||||
|
|
||||||
|
const val A_SCREENSHOT_URI = "file://content/uri"
|
||||||
|
|
||||||
|
class FakeScreenshotHolder(private val screenshotUri: String? = null) : ScreenshotHolder {
|
||||||
|
override fun writeBitmap(data: Bitmap) = Unit
|
||||||
|
|
||||||
|
override fun getFileUri() = screenshotUri
|
||||||
|
|
||||||
|
override fun reset() = Unit
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue