Cleanup DefaultBugReporter before testing it.
This commit is contained in:
committed by
Benoit Marty
parent
842b046139
commit
124e708160
@@ -22,27 +22,19 @@ interface BugReporter {
|
||||
/**
|
||||
* Send a bug report.
|
||||
*
|
||||
* @param reportType The report type (bug, suggestion, feedback)
|
||||
* @param withDevicesLogs true to include the device log
|
||||
* @param withCrashLogs true to include the crash logs
|
||||
* @param withKeyRequestHistory true to include the crash logs
|
||||
* @param withScreenshot true to include the screenshot
|
||||
* @param theBugDescription the bug description
|
||||
* @param serverVersion version of the server
|
||||
* @param canContact true if the user opt in to be contacted directly
|
||||
* @param customFields fields which will be sent with the report
|
||||
* @param listener the listener
|
||||
*/
|
||||
suspend fun sendBugReport(
|
||||
reportType: ReportType,
|
||||
withDevicesLogs: Boolean,
|
||||
withCrashLogs: Boolean,
|
||||
withKeyRequestHistory: Boolean,
|
||||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
serverVersion: String,
|
||||
canContact: Boolean = false,
|
||||
customFields: Map<String, String>? = null,
|
||||
listener: BugReporterListener?
|
||||
)
|
||||
|
||||
|
||||
@@ -42,5 +42,5 @@ interface BugReporterListener {
|
||||
/**
|
||||
* The bug report upload succeeded.
|
||||
*/
|
||||
fun onUploadSucceed(reportUrl: String?)
|
||||
fun onUploadSucceed()
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.api.reporter
|
||||
|
||||
enum class ReportType {
|
||||
BUG_REPORT,
|
||||
SUGGESTION,
|
||||
SPACE_BETA_FEEDBACK,
|
||||
THREADS_BETA_FEEDBACK,
|
||||
AUTO_UISI,
|
||||
AUTO_UISI_SENDER,
|
||||
}
|
||||
@@ -25,12 +25,11 @@ import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.impl.logs.VectorFileLogger
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.logs.VectorFileLogger
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -64,7 +63,7 @@ class BugReportPresenter @Inject constructor(
|
||||
sendingAction.value = Async.Loading()
|
||||
}
|
||||
|
||||
override fun onUploadSucceed(reportUrl: String?) {
|
||||
override fun onUploadSucceed() {
|
||||
sendingProgress.floatValue = 0f
|
||||
sendingAction.value = Async.Success(Unit)
|
||||
}
|
||||
@@ -135,15 +134,11 @@ class BugReportPresenter @Inject constructor(
|
||||
listener: BugReporterListener,
|
||||
) = launch {
|
||||
bugReporter.sendBugReport(
|
||||
reportType = ReportType.BUG_REPORT,
|
||||
withDevicesLogs = formState.sendLogs,
|
||||
withCrashLogs = hasCrashLogs && formState.sendLogs,
|
||||
withKeyRequestHistory = false,
|
||||
withScreenshot = formState.sendScreenshot,
|
||||
theBugDescription = formState.description,
|
||||
serverVersion = "",
|
||||
canContact = formState.canContact,
|
||||
customFields = emptyMap(),
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,14 +25,12 @@ import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.R
|
||||
import io.element.android.libraries.androidutils.file.compressFile
|
||||
import io.element.android.libraries.androidutils.file.safeDelete
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.core.extensions.toOnOff
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -77,26 +75,11 @@ class DefaultBugReporter @Inject constructor(
|
||||
private val userAgentProvider: UserAgentProvider,
|
||||
private val sessionStore: SessionStore,
|
||||
private val buildMeta: BuildMeta,
|
||||
/*
|
||||
private val versionProvider: VersionProvider,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val vectorFileLogger: VectorFileLogger,
|
||||
private val systemLocaleProvider: SystemLocaleProvider,
|
||||
private val matrix: Matrix,
|
||||
private val processInfo: ProcessInfo,
|
||||
private val sdkIntProvider: BuildVersionSdkIntProvider,
|
||||
private val vectorLocale: VectorLocaleProvider,
|
||||
*/
|
||||
) : BugReporter {
|
||||
var inMultiWindowMode = false
|
||||
|
||||
companion object {
|
||||
// filenames
|
||||
private const val LOG_CAT_ERROR_FILENAME = "logcatError.log"
|
||||
private const val LOG_CAT_FILENAME = "logcat.log"
|
||||
private const val LOG_DIRECTORY_NAME = "logs"
|
||||
// private const val KEY_REQUESTS_FILENAME = "keyRequests.log"
|
||||
|
||||
private const val BUFFER_SIZE = 1024 * 1024 * 50
|
||||
}
|
||||
|
||||
@@ -105,58 +88,20 @@ class DefaultBugReporter @Inject constructor(
|
||||
|
||||
// boolean to cancel the bug report
|
||||
private val isCancelled = false
|
||||
|
||||
/*
|
||||
val adapter = MatrixJsonParser.getMoshi()
|
||||
.adapter<JsonDict>(Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java))
|
||||
*/
|
||||
|
||||
private val logcatCommandError = arrayOf(
|
||||
"logcat", // /< Run 'logcat' command
|
||||
"-d", // /< Dump the log rather than continue outputting it
|
||||
"-v", // formatting
|
||||
"threadtime", // include timestamps
|
||||
"AndroidRuntime:E " + // /< Pick all AndroidRuntime errors (such as uncaught exceptions)"communicatorjni:V " + ///< All communicatorjni logging
|
||||
"libcommunicator:V " + // /< All libcommunicator logging
|
||||
"DEBUG:V " + // /< All DEBUG logging - which includes native land crashes (seg faults, etc)
|
||||
"*:S" // /< Everything else silent, so don't pick it..
|
||||
)
|
||||
|
||||
private val logcatCommandDebug = arrayOf("logcat", "-d", "-v", "threadtime", "*:*")
|
||||
|
||||
/**
|
||||
* Send a bug report.
|
||||
*
|
||||
* @param reportType The report type (bug, suggestion, feedback)
|
||||
* @param withDevicesLogs true to include the device log
|
||||
* @param withCrashLogs true to include the crash logs
|
||||
* @param withKeyRequestHistory true to include the crash logs
|
||||
* @param withScreenshot true to include the screenshot
|
||||
* @param theBugDescription the bug description
|
||||
* @param serverVersion version of the server
|
||||
* @param canContact true if the user opt in to be contacted directly
|
||||
* @param customFields fields which will be sent with the report
|
||||
* @param listener the listener
|
||||
*/
|
||||
override suspend fun sendBugReport(
|
||||
reportType: ReportType,
|
||||
withDevicesLogs: Boolean,
|
||||
withCrashLogs: Boolean,
|
||||
withKeyRequestHistory: Boolean,
|
||||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
serverVersion: String,
|
||||
canContact: Boolean,
|
||||
customFields: Map<String, String>?,
|
||||
listener: BugReporterListener?
|
||||
) {
|
||||
// enumerate files to delete
|
||||
val bugReportFiles: MutableList<File> = ArrayList()
|
||||
|
||||
try {
|
||||
|
||||
var serverError: String? = null
|
||||
var reportURL: String? = null
|
||||
withContext(coroutineDispatchers.io) {
|
||||
var bugDescription = theBugDescription
|
||||
val crashCallStack = crashDataStore.crashInfo().first()
|
||||
@@ -181,7 +126,7 @@ class DefaultBugReporter @Inject constructor(
|
||||
}
|
||||
|
||||
if (!isCancelled && (withCrashLogs || withDevicesLogs)) {
|
||||
val gzippedLogcat = saveLogCat(false)
|
||||
val gzippedLogcat = saveLogCat()
|
||||
|
||||
if (null != gzippedLogcat) {
|
||||
if (gzippedFiles.size == 0) {
|
||||
@@ -192,68 +137,21 @@ class DefaultBugReporter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
activeSessionHolder.getSafeActiveSession()
|
||||
?.takeIf { !mIsCancelled && withKeyRequestHistory }
|
||||
?.cryptoService()
|
||||
?.getGossipingEvents()
|
||||
?.let { GossipingEventsSerializer().serialize(it) }
|
||||
?.toByteArray()
|
||||
?.let { rawByteArray ->
|
||||
File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME)
|
||||
.also {
|
||||
it.outputStream()
|
||||
.use { os -> os.write(rawByteArray) }
|
||||
}
|
||||
}
|
||||
?.let { compressFile(it) }
|
||||
?.let { gzippedFiles.add(it) }
|
||||
*/
|
||||
|
||||
val sessionData = sessionStore.getLatestSession()
|
||||
val deviceId = sessionData?.deviceId ?: "undefined"
|
||||
val userId = sessionData?.userId ?: "undefined"
|
||||
var olmVersion = "undefined"
|
||||
|
||||
if (!isCancelled) {
|
||||
val text = when (reportType) {
|
||||
ReportType.BUG_REPORT -> bugDescription
|
||||
ReportType.SUGGESTION -> "[Suggestion] $bugDescription"
|
||||
ReportType.SPACE_BETA_FEEDBACK -> "[spaces-feedback] $bugDescription"
|
||||
ReportType.THREADS_BETA_FEEDBACK -> "[threads-feedback] $bugDescription"
|
||||
ReportType.AUTO_UISI_SENDER,
|
||||
ReportType.AUTO_UISI -> bugDescription
|
||||
}
|
||||
|
||||
// build the multi part request
|
||||
val builder = BugReporterMultipartBody.Builder()
|
||||
.addFormDataPart("text", text)
|
||||
.addFormDataPart("app", rageShakeAppNameForReport(reportType))
|
||||
.addFormDataPart("text", bugDescription)
|
||||
.addFormDataPart("app", context.getString(R.string.bug_report_app_name))
|
||||
.addFormDataPart("user_agent", userAgentProvider.provide())
|
||||
.addFormDataPart("user_id", userId)
|
||||
.addFormDataPart("can_contact", canContact.toString())
|
||||
.addFormDataPart("device_id", deviceId)
|
||||
// .addFormDataPart("version", versionProvider.getVersion(longFormat = true))
|
||||
// .addFormDataPart("branch_name", buildMeta.gitBranchName)
|
||||
// .addFormDataPart("matrix_sdk_version", Matrix.getSdkVersion())
|
||||
.addFormDataPart("olm_version", olmVersion)
|
||||
.addFormDataPart("device", Build.MODEL.trim())
|
||||
// .addFormDataPart("verbose_log", vectorPreferences.labAllowedExtendedLogging().toOnOff())
|
||||
.addFormDataPart("multi_window", inMultiWindowMode.toOnOff())
|
||||
// .addFormDataPart(
|
||||
// "os", Build.VERSION.RELEASE + " (API " + sdkIntProvider.get() + ") " +
|
||||
// Build.VERSION.INCREMENTAL + "-" + Build.VERSION.CODENAME
|
||||
// )
|
||||
.addFormDataPart("locale", Locale.getDefault().toString())
|
||||
// .addFormDataPart("app_language", vectorLocale.applicationLocale.toString())
|
||||
// .addFormDataPart("default_app_language", systemLocaleProvider.getSystemLocale().toString())
|
||||
// .addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
|
||||
.addFormDataPart("server_version", serverVersion)
|
||||
.apply {
|
||||
customFields?.forEach { (name, value) ->
|
||||
addFormDataPart(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
// add the gzipped files, don't cancel the whole upload if only some file failed to upload
|
||||
var uploadedSomeLogs = false
|
||||
@@ -293,31 +191,6 @@ class DefaultBugReporter @Inject constructor(
|
||||
|
||||
// add some github labels
|
||||
builder.addFormDataPart("label", buildMeta.versionName)
|
||||
// builder.addFormDataPart("label", buildMeta.flavorDescription)
|
||||
// builder.addFormDataPart("label", buildMeta.gitBranchName)
|
||||
|
||||
// Possible values for BuildConfig.BUILD_TYPE: "debug", "nightly", "release".
|
||||
// builder.addFormDataPart("label", BuildConfig.BUILD_TYPE)
|
||||
|
||||
when (reportType) {
|
||||
ReportType.BUG_REPORT -> {
|
||||
/* nop */
|
||||
}
|
||||
ReportType.SUGGESTION -> builder.addFormDataPart("label", "[Suggestion]")
|
||||
ReportType.SPACE_BETA_FEEDBACK -> builder.addFormDataPart("label", "spaces-feedback")
|
||||
ReportType.THREADS_BETA_FEEDBACK -> builder.addFormDataPart("label", "threads-feedback")
|
||||
ReportType.AUTO_UISI -> {
|
||||
builder.addFormDataPart("label", "Z-UISI")
|
||||
builder.addFormDataPart("label", "android")
|
||||
builder.addFormDataPart("label", "uisi-recipient")
|
||||
}
|
||||
ReportType.AUTO_UISI_SENDER -> {
|
||||
builder.addFormDataPart("label", "Z-UISI")
|
||||
builder.addFormDataPart("label", "android")
|
||||
builder.addFormDataPart("label", "uisi-sender")
|
||||
}
|
||||
}
|
||||
|
||||
if (crashCallStack.isNotEmpty() && withCrashLogs) {
|
||||
builder.addFormDataPart("label", "crash")
|
||||
}
|
||||
@@ -379,7 +252,6 @@ class DefaultBugReporter @Inject constructor(
|
||||
} else {
|
||||
try {
|
||||
val inputStream = response.body!!.byteStream()
|
||||
|
||||
serverError = inputStream.use {
|
||||
buildString {
|
||||
var ch = it.read()
|
||||
@@ -389,7 +261,6 @@ class DefaultBugReporter @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the error message
|
||||
serverError?.let {
|
||||
try {
|
||||
@@ -401,7 +272,6 @@ class DefaultBugReporter @Inject constructor(
|
||||
Timber.e(e, "doInBackground ; Json conversion failed")
|
||||
}
|
||||
}
|
||||
|
||||
// should never happen
|
||||
if (null == serverError) {
|
||||
serverError = "Failed with error $responseCode"
|
||||
@@ -412,25 +282,17 @@ class DefaultBugReporter @Inject constructor(
|
||||
Timber.e(e, "## sendBugReport() : failed to parse error")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
reportURL = response?.body?.string()?.let { stringBody ->
|
||||
adapter.fromJson(stringBody)?.get("report_url")?.toString()
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withContext(coroutineDispatchers.main) {
|
||||
bugReportCall = null
|
||||
|
||||
if (null != listener) {
|
||||
try {
|
||||
if (isCancelled) {
|
||||
listener.onUploadCancelled()
|
||||
} else if (null == serverError) {
|
||||
listener.onUploadSucceed(reportURL)
|
||||
listener.onUploadSucceed()
|
||||
} else {
|
||||
listener.onUploadFailed(serverError)
|
||||
}
|
||||
@@ -449,47 +311,6 @@ class DefaultBugReporter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a bug report either with email or with Vector.
|
||||
*/
|
||||
/* TODO Remove
|
||||
fun openBugReportScreen(activity: FragmentActivity, reportType: ReportType = ReportType.BUG_REPORT) {
|
||||
screenshot = takeScreenshot(activity)
|
||||
logDbInfo()
|
||||
logProcessInfo()
|
||||
logOtherInfo()
|
||||
activity.startActivity(BugReportActivity.intent(activity, reportType))
|
||||
}
|
||||
*/
|
||||
|
||||
// private fun logOtherInfo() {
|
||||
// Timber.i("SyncThread state: " + activeSessionHolder.getSafeActiveSession()?.syncService()?.getSyncState())
|
||||
// }
|
||||
|
||||
// private fun logDbInfo() {
|
||||
// val dbInfo = matrix.debugService().getDbUsageInfo()
|
||||
// Timber.i(dbInfo)
|
||||
// }
|
||||
|
||||
// private fun logProcessInfo() {
|
||||
// val pInfo = processInfo.getInfo()
|
||||
// Timber.i(pInfo)
|
||||
// }
|
||||
|
||||
private fun rageShakeAppNameForReport(reportType: ReportType): String {
|
||||
// As per https://github.com/matrix-org/rageshake
|
||||
// app: Identifier for the application (eg 'riot-web').
|
||||
// Should correspond to a mapping configured in the configuration file for github issue reporting to work.
|
||||
// (see R.string.bug_report_url for configured RS server)
|
||||
return context.getString(
|
||||
when (reportType) {
|
||||
ReportType.AUTO_UISI_SENDER,
|
||||
ReportType.AUTO_UISI -> R.string.bug_report_auto_uisi_app_name
|
||||
else -> R.string.bug_report_app_name
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun logDirectory(): File {
|
||||
return File(context.cacheDir, LOG_DIRECTORY_NAME)
|
||||
}
|
||||
@@ -545,11 +366,10 @@ class DefaultBugReporter @Inject constructor(
|
||||
/**
|
||||
* Save the logcat.
|
||||
*
|
||||
* @param isErrorLogcat true to save the error logcat
|
||||
* @return the file if the operation succeeds
|
||||
*/
|
||||
private fun saveLogCat(isErrorLogcat: Boolean): File? {
|
||||
val logCatErrFile = File(context.cacheDir.absolutePath, if (isErrorLogcat) LOG_CAT_ERROR_FILENAME else LOG_CAT_FILENAME)
|
||||
private fun saveLogCat(): File? {
|
||||
val logCatErrFile = File(context.cacheDir.absolutePath, LOG_CAT_FILENAME)
|
||||
|
||||
if (logCatErrFile.exists()) {
|
||||
logCatErrFile.safeDelete()
|
||||
@@ -557,7 +377,7 @@ class DefaultBugReporter @Inject constructor(
|
||||
|
||||
try {
|
||||
logCatErrFile.writer().use {
|
||||
getLogCatError(it, isErrorLogcat)
|
||||
getLogCatError(it)
|
||||
}
|
||||
|
||||
return compressFile(logCatErrFile)
|
||||
@@ -578,13 +398,12 @@ class DefaultBugReporter @Inject constructor(
|
||||
* Retrieves the logs.
|
||||
*
|
||||
* @param streamWriter the stream writer
|
||||
* @param isErrorLogCat true to save the error logs
|
||||
*/
|
||||
private fun getLogCatError(streamWriter: OutputStreamWriter, isErrorLogCat: Boolean) {
|
||||
private fun getLogCatError(streamWriter: OutputStreamWriter) {
|
||||
val logcatProc: Process
|
||||
|
||||
try {
|
||||
logcatProc = Runtime.getRuntime().exec(if (isErrorLogCat) logcatCommandError else logcatCommandDebug)
|
||||
logcatProc = Runtime.getRuntime().exec(logcatCommandDebug)
|
||||
} catch (e1: IOException) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -19,7 +18,12 @@
|
||||
|
||||
<!-- Rageshake configuration -->
|
||||
<string name="bug_report_url" translatable="false">https://riot.im/bugreports/submit</string>
|
||||
<!--
|
||||
As per https://github.com/matrix-org/rageshake
|
||||
bug_report_app_name: Identifier for the application (eg 'riot-web').
|
||||
Should correspond to a mapping configured in the configuration file for github issue reporting to work.
|
||||
-->
|
||||
<string name="bug_report_app_name" translatable="false">element-x-android</string>
|
||||
<string name="bug_report_auto_uisi_app_name" translatable="false">element-auto-uisi</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -18,22 +18,17 @@ package io.element.android.features.rageshake.impl.bugreport
|
||||
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import io.element.android.libraries.matrix.test.A_FAILURE_REASON
|
||||
import kotlinx.coroutines.delay
|
||||
import java.io.File
|
||||
|
||||
class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Success) : BugReporter {
|
||||
override suspend fun sendBugReport(
|
||||
reportType: ReportType,
|
||||
withDevicesLogs: Boolean,
|
||||
withCrashLogs: Boolean,
|
||||
withKeyRequestHistory: Boolean,
|
||||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
serverVersion: String,
|
||||
canContact: Boolean,
|
||||
customFields: Map<String, String>?,
|
||||
listener: BugReporterListener?,
|
||||
) {
|
||||
delay(100)
|
||||
@@ -54,7 +49,7 @@ class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Succes
|
||||
}
|
||||
listener?.onProgress(100)
|
||||
delay(100)
|
||||
listener?.onUploadSucceed(null)
|
||||
listener?.onUploadSucceed()
|
||||
}
|
||||
|
||||
override fun cleanLogDirectoryIfNeeded() {
|
||||
|
||||
Reference in New Issue
Block a user