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
30 changes: 28 additions & 2 deletions app/src/main/kotlin/com/wire/android/ui/debug/DebugScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.wire.android.ui.debug

import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import android.widget.Toast
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
Expand Down Expand Up @@ -51,10 +52,12 @@ import com.wire.android.ui.common.topappbar.NavigationIconType
import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar
import com.ramcosta.composedestinations.generated.app.destinations.ConversationCryptoStatsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.DebugFeatureFlagsScreenDestination
import com.ramcosta.composedestinations.generated.app.destinations.ImportMediaScreenDestination
import com.wire.android.ui.common.rowitem.SectionHeader
import com.wire.android.ui.home.settings.SettingsItem
import com.wire.android.ui.home.settings.backup.BackupAndRestoreDialog
import com.wire.android.ui.home.settings.backup.rememberBackUpAndRestoreStateHolder
import com.wire.android.ui.sharing.ImportMediaNavArgs
import com.wire.android.ui.theme.WireTheme
import com.wire.android.util.AppNameUtil
import com.wire.android.util.logging.LogShareLauncher
Expand Down Expand Up @@ -94,6 +97,13 @@ fun DebugScreen(
dangerOptionsContent = {
DangerOptions(exportObfuscatedCopyViewModel = exportObfuscatedCopyViewModel)
},
onShareLogsViaWire = { uri ->
navigator.navigate(
NavigationCommand(
ImportMediaScreenDestination(ImportMediaNavArgs(arrayListOf(uri)))
)
)
},
)
}

Expand All @@ -105,6 +115,7 @@ internal fun UserDebugContent(
onDatabaseLoggerEnabledChanged: (Boolean) -> Unit,
onDeleteLogs: () -> Unit,
onFlushLogs: () -> Deferred<Unit>,
onShareLogsViaWire: (Uri) -> Unit,
debugDataOptionsContent: @Composable (DebugContentState) -> Unit,
dangerOptionsContent: @Composable () -> Unit,
) {
Expand All @@ -131,7 +142,8 @@ internal fun UserDebugContent(
isLoggingEnabled = isLoggingEnabled,
onLoggingEnabledChange = onLoggingEnabledChange,
onDeleteLogs = onDeleteLogs,
onShareLogs = { debugContentState.shareLogs(onFlushLogs) },
onShareLogsExternally = { debugContentState.shareLogsExternally(onFlushLogs) },
onShareLogsViaWire = { debugContentState.shareLogsViaWire(onFlushLogs, onShareLogsViaWire) },
isDBLoggerEnabled = state.isDBLoggingEnabled,
onDBLoggerEnabledChange = onDatabaseLoggerEnabledChanged,
isPrivateBuild = BuildConfig.PRIVATE_BUILD,
Expand Down Expand Up @@ -230,7 +242,7 @@ data class DebugContentState(
).show()
}

fun shareLogs(onFlushLogs: () -> Deferred<Unit>) {
fun shareLogsExternally(onFlushLogs: () -> Deferred<Unit>) {
val dir = File(logPath).parentFile
if (dir != null && dir.exists()) {
logShareLauncher.shareLogs(dir) {
Expand All @@ -239,6 +251,19 @@ data class DebugContentState(
}
}
}

fun shareLogsViaWire(onFlushLogs: () -> Deferred<Unit>, onShareUri: (Uri) -> Unit) {
val dir = File(logPath).parentFile
if (dir != null && dir.exists()) {
logShareLauncher.shareLogsViaWire(
logsDirectory = dir,
onShareUri = onShareUri
) {
// Flush any buffered logs before sharing to ensure completeness.
onFlushLogs().await()
}
}
}
}

@Preview(heightDp = 1400)
Expand All @@ -253,6 +278,7 @@ internal fun PreviewUserDebugContent() = WireTheme {
onLoggingEnabledChange = {},
onDeleteLogs = {},
onFlushLogs = { CompletableDeferred(Unit) },
onShareLogsViaWire = {},
onDatabaseLoggerEnabledChanged = {},
debugDataOptionsContent = {
DebugDataOptions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package com.wire.android.ui.debug

import com.ramcosta.composedestinations.generated.app.destinations.ImportMediaScreenDestination
import com.wire.android.navigation.annotation.app.WireRootDestination
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -26,11 +27,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.navigation.NavigationCommand
import com.wire.android.navigation.Navigator
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.scaffold.WireScaffold
import com.wire.android.ui.common.topappbar.NavigationIconType
import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar
import com.wire.android.ui.sharing.ImportMediaNavArgs

@WireRootDestination
@Composable
Expand Down Expand Up @@ -63,7 +66,16 @@ fun LogManagementScreen(
isLoggingEnabled = state.isLoggingEnabled,
onLoggingEnabledChange = viewModel::setLoggingEnabledState,
onDeleteLogs = viewModel::deleteLogs,
onShareLogs = { contentState.shareLogs(viewModel::flushLogs) },
onShareLogsExternally = { contentState.shareLogsExternally(viewModel::flushLogs) },
onShareLogsViaWire = {
contentState.shareLogsViaWire(viewModel::flushLogs) { uri ->
navigator.navigate(
NavigationCommand(
ImportMediaScreenDestination(ImportMediaNavArgs(arrayListOf(uri)))
)
)
}
},
isDBLoggerEnabled = false,
onDBLoggerEnabledChange = {},
isPrivateBuild = false
Expand Down
91 changes: 87 additions & 4 deletions app/src/main/kotlin/com/wire/android/ui/debug/LogOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.model.Clickable
import com.wire.android.ui.common.SurfaceBackgroundWrapper
import com.wire.android.ui.common.bottomsheet.MenuBottomSheetItem
import com.wire.android.ui.common.bottomsheet.MenuItemIcon
import com.wire.android.ui.common.bottomsheet.MenuModalSheetHeader
import com.wire.android.ui.common.bottomsheet.WireMenuModalSheetContent
import com.wire.android.ui.common.bottomsheet.WireModalSheetLayout
import com.wire.android.ui.common.bottomsheet.rememberWireModalSheetState
import com.wire.android.ui.common.bottomsheet.show
import com.wire.android.ui.common.button.WireSwitch
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
Expand All @@ -44,6 +51,7 @@ import com.wire.android.ui.home.settings.SettingsItem
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.supportsTrustedWireShareCaller
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
Expand All @@ -53,10 +61,21 @@ fun LogOptions(
isDBLoggerEnabled: Boolean,
onDBLoggerEnabledChange: (Boolean) -> Unit,
onDeleteLogs: () -> Unit,
onShareLogs: () -> Unit,
onShareLogsExternally: () -> Unit,
onShareLogsViaWire: () -> Unit,
isPrivateBuild: Boolean,
modifier: Modifier = Modifier
) {
val shareLogsSheetState = rememberWireModalSheetState<Unit>()
val shareLogsDirectly = supportsTrustedWireShareCaller()
val onShareLogsClick: () -> Unit = {
if (shareLogsDirectly) {
onShareLogsExternally()
} else {
shareLogsSheetState.show()
}
}

Column(modifier = modifier) {
SectionHeader(stringResource(R.string.label_logs_option_title))
EnableLoggingSwitch(
Expand All @@ -74,9 +93,13 @@ fun LogOptions(
SettingsItem(
text = stringResource(R.string.label_share_logs),
trailingIcon = R.drawable.ic_entypo_share,
onRowPressed = Clickable(
enabled = true,
onClick = onShareLogsClick
),
onIconPressed = Clickable(
enabled = true,
onClick = onShareLogs
onClick = onShareLogsClick
)
)

Expand All @@ -90,6 +113,64 @@ fun LogOptions(
)
}
}

if (!shareLogsDirectly) {
WireModalSheetLayout(
sheetState = shareLogsSheetState,
sheetContent = {
WireMenuModalSheetContent(
header = MenuModalSheetHeader.Visible(
title = stringResource(R.string.label_share_logs)
),
menuItems = shareLogsMenuItems(
onShareLogsExternally = {
shareLogsSheetState.hide { onShareLogsExternally() }
},
onShareLogsViaWire = {
shareLogsSheetState.hide { onShareLogsViaWire() }
}
)
)
}
)
}
}

private fun shareLogsMenuItems(
onShareLogsExternally: () -> Unit,
onShareLogsViaWire: () -> Unit
): List<@Composable () -> Unit> =
listOf(
{ ShareLogsInWireOption(onShareLogsViaWire) },
{ ShareLogsExternallyOption(onShareLogsExternally) }
)

@Composable
private fun ShareLogsInWireOption(onClick: () -> Unit) {
MenuBottomSheetItem(
leading = {
MenuItemIcon(
id = R.drawable.ic_share_file,
contentDescription = stringResource(R.string.content_description_share_the_file),
)
},
title = stringResource(R.string.label_share_logs_via_wire),
onItemClick = onClick
)
}

@Composable
private fun ShareLogsExternallyOption(onClick: () -> Unit) {
MenuBottomSheetItem(
leading = {
MenuItemIcon(
id = R.drawable.ic_entypo_share,
contentDescription = stringResource(R.string.content_description_share_the_file),
)
},
title = stringResource(R.string.label_share_logs_externally),
onItemClick = onClick
)
}

@Composable
Expand Down Expand Up @@ -172,7 +253,8 @@ fun PreviewLoggingOptionsPublicBuild() {
isDBLoggerEnabled = true,
onDBLoggerEnabledChange = {},
onDeleteLogs = {},
onShareLogs = {},
onShareLogsExternally = {},
onShareLogsViaWire = {},
isPrivateBuild = false,
)
}
Expand All @@ -186,7 +268,8 @@ fun PreviewLoggingOptionsPrivateBuild() {
isDBLoggerEnabled = true,
onDBLoggerEnabledChange = {},
onDeleteLogs = {},
onShareLogs = {},
onShareLogsExternally = {},
onShareLogsViaWire = {},
isPrivateBuild = true,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ fun ConversationScreen(
conversationMessages = conversationMessagesViewModel.infoMessage,
shareAssetExternally = conversationMessagesViewModel::shareAsset,
shareAssetViaWire = { messageId ->
conversationMessagesViewModel.shareAssetViaWire(messageId) { path, assetName ->
conversationMessagesViewModel.prepareAssetForWireShare(messageId) { path, assetName ->
navigator.navigate(
NavigationCommand(
ImportMediaScreenDestination(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fun ConversationMediaScreen(
},
shareAssetExternally = { conversationMessagesViewModel.shareAsset(context, it) },
shareAssetViaWire = { messageId ->
conversationMessagesViewModel.shareAssetViaWire(messageId) { path, assetName ->
conversationMessagesViewModel.prepareAssetForWireShare(messageId) { path, assetName ->
navigator.navigate(
NavigationCommand(
ImportMediaScreenDestination(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ class ConversationMessagesViewModel(
}
}

fun shareAssetViaWire(messageId: String, onAssetReady: (Path, String) -> Unit) {
fun prepareAssetForWireShare(messageId: String, onAssetReady: (Path, String) -> Unit) {
viewModelScope.launch {
assetDataPath(conversationId, messageId)?.run {
onAssetReady(first, second)
Expand Down
33 changes: 25 additions & 8 deletions app/src/main/kotlin/com/wire/android/util/logging/LogSharing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import android.content.ClipData
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import com.wire.android.R
import com.wire.android.appLogger
import com.wire.android.util.EmailComposer
import com.wire.android.util.externalShareChooserIntent
import com.wire.android.util.getDeviceIdString
import com.wire.android.util.getGitBuildId
import com.wire.android.util.getProviderAuthority
import com.wire.android.util.sha256
import com.wire.android.util.shareableFileProviderUri
import com.wire.android.util.startShareIntentWithTrustedWireTarget
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -65,7 +66,21 @@ class LogShareLauncher(
share(
logsDirectory = logsDirectory,
flushLogs = flushLogs,
intent = { archive -> context.logsSharingIntent(archive) }
shareArchive = { archive ->
context.startShareIntentWithTrustedWireTarget(context.logsSharingIntent(archive))
}
)
}

fun shareLogsViaWire(
logsDirectory: File,
onShareUri: (Uri) -> Unit,
flushLogs: suspend () -> Unit = {}
) {
share(
logsDirectory = logsDirectory,
flushLogs = flushLogs,
shareArchive = { archive -> onShareUri(context.logsSharingUri(archive)) }
)
}

Expand All @@ -75,20 +90,20 @@ class LogShareLauncher(
share(
logsDirectory = LogFileWriter.logsDirectory(context),
flushLogs = flushLogs,
intent = { archive -> context.bugReportLogsSharingIntent(archive) }
shareArchive = { archive -> context.startActivity(context.bugReportLogsSharingIntent(archive)) }
)
}

private fun share(
logsDirectory: File,
flushLogs: suspend () -> Unit,
intent: (File) -> Intent
shareArchive: (File) -> Unit
) {
coroutineScope.launch {
runCatching {
flushLogs()
val archive = archiveCreator.create(logsDirectory)
context.startActivity(intent(archive))
shareArchive(archive)
}.onFailure { error ->
appLogger.e("Failed to prepare logs for sharing", error)
onFailure(error)
Expand All @@ -114,8 +129,10 @@ class CompressedLogsArchiveCreator(
}
}

fun Context.logsSharingUri(archiveFile: File): Uri = shareableFileProviderUri(archiveFile)

fun Context.logsSharingIntent(archiveFile: File): Intent {
val archiveUri = FileProvider.getUriForFile(this, getProviderAuthority(), archiveFile)
val archiveUri = logsSharingUri(archiveFile)
return Intent(Intent.ACTION_SEND).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
type = LOGS_ARCHIVE_MIME_TYPE
Expand All @@ -137,7 +154,7 @@ fun Context.bugReportLogsSharingIntent(archiveFile: File): Intent {
)
selector = Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mailto:"))
}
return Intent.createChooser(intent, getString(R.string.send_feedback_choose_email))
return externalShareChooserIntent(intent, getString(R.string.send_feedback_choose_email))
}

internal fun deleteStaleCompressedLogsArchives(
Expand Down
Loading
Loading