Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits:
-
2095a229
by clairehurst at 2024-04-17T00:27:30+00:00
4 changed files:
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsComposeFragment.kt
- − fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsFragment.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsViewModel.kt
- fenix/app/src/main/res/navigation/nav_graph.xml
Changes:
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | + |
|
| 5 | +package org.mozilla.fenix.tor
|
|
| 6 | + |
|
| 7 | +import android.os.Bundle
|
|
| 8 | +import android.view.LayoutInflater
|
|
| 9 | +import android.view.View
|
|
| 10 | +import android.view.ViewGroup
|
|
| 11 | +import androidx.compose.foundation.layout.Column
|
|
| 12 | +import androidx.compose.foundation.layout.fillMaxSize
|
|
| 13 | +import androidx.compose.foundation.layout.fillMaxWidth
|
|
| 14 | +import androidx.compose.foundation.layout.padding
|
|
| 15 | +import androidx.compose.foundation.rememberScrollState
|
|
| 16 | +import androidx.compose.foundation.text.selection.DisableSelection
|
|
| 17 | +import androidx.compose.foundation.text.selection.SelectionContainer
|
|
| 18 | +import androidx.compose.foundation.verticalScroll
|
|
| 19 | +import androidx.compose.material.Text
|
|
| 20 | +import androidx.compose.runtime.Composable
|
|
| 21 | +import androidx.compose.runtime.Stable
|
|
| 22 | +import androidx.compose.ui.Modifier
|
|
| 23 | +import androidx.compose.ui.platform.ComposeView
|
|
| 24 | +import androidx.compose.ui.unit.dp
|
|
| 25 | +import androidx.fragment.app.Fragment
|
|
| 26 | +import androidx.fragment.app.viewModels
|
|
| 27 | +import mozilla.components.ui.colors.PhotonColors
|
|
| 28 | + |
|
| 29 | +class TorLogsComposeFragment : Fragment() {
|
|
| 30 | + private val viewModel: TorLogsViewModel by viewModels()
|
|
| 31 | + |
|
| 32 | + override fun onCreateView(
|
|
| 33 | + inflater: LayoutInflater,
|
|
| 34 | + container: ViewGroup?,
|
|
| 35 | + savedInstanceState: Bundle?,
|
|
| 36 | + ): View {
|
|
| 37 | + return ComposeView(requireContext()).apply {
|
|
| 38 | + setContent {
|
|
| 39 | + SelectionContainer {
|
|
| 40 | + Column(
|
|
| 41 | + // Column instead of LazyColumn so that you can select all the logs, and not just one "screen" at a time
|
|
| 42 | + // The logs won't be too big so loading them all instead of just whats visible shouldn't be a big deal
|
|
| 43 | + modifier = Modifier
|
|
| 44 | + .fillMaxSize()
|
|
| 45 | + .verticalScroll(state = rememberScrollState(), reverseScrolling = true),
|
|
| 46 | + ) {
|
|
| 47 | + for (log in viewModel.torLogs) {
|
|
| 48 | + LogRow(log = log)
|
|
| 49 | + }
|
|
| 50 | + }
|
|
| 51 | + }
|
|
| 52 | + }
|
|
| 53 | + }
|
|
| 54 | + }
|
|
| 55 | +}
|
|
| 56 | + |
|
| 57 | +@Composable
|
|
| 58 | +@Stable
|
|
| 59 | +fun LogRow(log: TorLog, modifier: Modifier = Modifier) {
|
|
| 60 | + Column(
|
|
| 61 | + modifier
|
|
| 62 | + .fillMaxWidth()
|
|
| 63 | + .padding(
|
|
| 64 | + start = 16.dp,
|
|
| 65 | + end = 16.dp,
|
|
| 66 | + bottom = 16.dp,
|
|
| 67 | + ),
|
|
| 68 | + ) {
|
|
| 69 | + DisableSelection {
|
|
| 70 | + Text(
|
|
| 71 | + text = log.timestamp.toString(),
|
|
| 72 | + color = PhotonColors.LightGrey40,
|
|
| 73 | + modifier = modifier
|
|
| 74 | + .padding(bottom = 4.dp),
|
|
| 75 | + )
|
|
| 76 | + }
|
|
| 77 | + Text(
|
|
| 78 | + text = log.text,
|
|
| 79 | + color = PhotonColors.LightGrey05,
|
|
| 80 | + )
|
|
| 81 | + }
|
|
| 82 | +} |
| 1 | -/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | - |
|
| 5 | -package org.mozilla.fenix.tor
|
|
| 6 | - |
|
| 7 | -import android.os.Bundle
|
|
| 8 | -import android.text.method.ScrollingMovementMethod
|
|
| 9 | -import android.view.LayoutInflater
|
|
| 10 | -import android.view.View
|
|
| 11 | -import android.view.ViewGroup
|
|
| 12 | -import androidx.fragment.app.Fragment
|
|
| 13 | -import org.mozilla.fenix.R
|
|
| 14 | -import org.mozilla.fenix.components.Components
|
|
| 15 | -import org.mozilla.fenix.databinding.TorBootstrapLoggerBinding
|
|
| 16 | -import org.mozilla.fenix.ext.requireComponents
|
|
| 17 | -import org.mozilla.fenix.tor.view.TorBootstrapLoggerViewHolder
|
|
| 18 | - |
|
| 19 | -class TorLogsFragment : Fragment(), TorLogs {
|
|
| 20 | - |
|
| 21 | - private var entries = mutableListOf<String>()
|
|
| 22 | - internal var _binding: TorBootstrapLoggerBinding? = null
|
|
| 23 | - private val binding get() = _binding!!
|
|
| 24 | - |
|
| 25 | - private var _components: Components? = null
|
|
| 26 | - private val components get() = _components!!
|
|
| 27 | - |
|
| 28 | - override fun onCreateView(
|
|
| 29 | - inflater: LayoutInflater,
|
|
| 30 | - container: ViewGroup?,
|
|
| 31 | - savedInstanceState: Bundle?,
|
|
| 32 | - ): View {
|
|
| 33 | - _binding = TorBootstrapLoggerBinding.inflate(inflater)
|
|
| 34 | - _components = requireComponents
|
|
| 35 | - |
|
| 36 | - components.torController.registerTorLogListener(this)
|
|
| 37 | - |
|
| 38 | - val currentEntries = components.torController.logEntries.filter { it.second != null }
|
|
| 39 | - .filter { !(it.second!!.startsWith("Circuit") && it.first == "ON") }
|
|
| 40 | - // Keep synchronized with format in onTorStatusUpdate
|
|
| 41 | - .flatMap { listOf("(${it.first}) '${it.second}'") }
|
|
| 42 | - val entriesLen = currentEntries.size
|
|
| 43 | - val subListOffset =
|
|
| 44 | - if (entriesLen > TorBootstrapLoggerViewHolder.MAX_NEW_ENTRIES) TorBootstrapLoggerViewHolder.MAX_NEW_ENTRIES else entriesLen
|
|
| 45 | - entries =
|
|
| 46 | - currentEntries.subList((entriesLen - subListOffset), entriesLen) as MutableList<String>
|
|
| 47 | - val initLog =
|
|
| 48 | - "---------------" + getString(R.string.tor_initializing_log) + "---------------"
|
|
| 49 | - entries.add(0, initLog)
|
|
| 50 | - |
|
| 51 | - with(binding.torBootstrapLogEntries) {
|
|
| 52 | - movementMethod = ScrollingMovementMethod()
|
|
| 53 | - text = formatLogEntries(entries)
|
|
| 54 | - }
|
|
| 55 | - |
|
| 56 | - |
|
| 57 | - return binding.root
|
|
| 58 | - }
|
|
| 59 | - |
|
| 60 | - // TODO on destroy unregiuster
|
|
| 61 | - |
|
| 62 | - private fun formatLogEntries(entries: List<String>) = entries.joinToString("\n")
|
|
| 63 | - |
|
| 64 | - override fun onLog(type: String?, message: String?) {
|
|
| 65 | - if (message == null || type == null) return
|
|
| 66 | - if (type == "ON" && type.startsWith("Circuit")) return
|
|
| 67 | - |
|
| 68 | - if (entries.size > TorBootstrapLoggerViewHolder.MAX_LINES) {
|
|
| 69 | - entries = entries.drop(1) as MutableList<String>
|
|
| 70 | - }
|
|
| 71 | - entries.add("($type) '$message'")
|
|
| 72 | - |
|
| 73 | - binding.torBootstrapLogEntries.text = formatLogEntries(entries)
|
|
| 74 | - }
|
|
| 75 | - |
|
| 76 | - override fun onStop() {
|
|
| 77 | - super.onStop()
|
|
| 78 | - components.torController.unregisterTorLogListener(this)
|
|
| 79 | - }
|
|
| 80 | - |
|
| 81 | -} |
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | + |
|
| 5 | +package org.mozilla.fenix.tor
|
|
| 6 | + |
|
| 7 | +import android.app.Application
|
|
| 8 | +import android.content.ClipData
|
|
| 9 | +import android.content.ClipboardManager
|
|
| 10 | +import android.content.Context
|
|
| 11 | +import android.os.Build
|
|
| 12 | +import android.widget.Toast
|
|
| 13 | +import androidx.compose.runtime.Stable
|
|
| 14 | +import androidx.lifecycle.AndroidViewModel
|
|
| 15 | +import org.mozilla.fenix.R
|
|
| 16 | +import org.mozilla.fenix.ext.components
|
|
| 17 | +import java.sql.Timestamp
|
|
| 18 | + |
|
| 19 | +class TorLogsViewModel(application: Application) : AndroidViewModel(application), TorLogs {
|
|
| 20 | + private val torController = application.components.torController
|
|
| 21 | + private val clipboardManager =
|
|
| 22 | + application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
| 23 | + |
|
| 24 | + val torLogs: MutableList<TorLog> = mutableListOf(
|
|
| 25 | + TorLog(
|
|
| 26 | + "---------------" + application.getString(R.string.tor_initializing_log) + "---------------",
|
|
| 27 | + ),
|
|
| 28 | + )
|
|
| 29 | + |
|
| 30 | + init {
|
|
| 31 | + setupClipboardListener()
|
|
| 32 | + torController.registerTorLogListener(this)
|
|
| 33 | + val currentEntries = torController.logEntries.filter { it.second != null }
|
|
| 34 | + .filter { !(it.second!!.startsWith("Circuit") && it.first == "ON") }
|
|
| 35 | + // Keep synchronized with format in onTorStatusUpdate
|
|
| 36 | + .flatMap { listOf(TorLog("[${it.first}] ${it.second}")) }
|
|
| 37 | + torLogs.addAll(currentEntries)
|
|
| 38 | + }
|
|
| 39 | + |
|
| 40 | + override fun onLog(type: String?, message: String?) {
|
|
| 41 | + if (message == null || type == null) return
|
|
| 42 | + if (type == "ON" && type.startsWith("Circuit")) return
|
|
| 43 | + |
|
| 44 | + torLogs.add(TorLog("[$type] $message"))
|
|
| 45 | + }
|
|
| 46 | + |
|
| 47 | + override fun onCleared() {
|
|
| 48 | + super.onCleared()
|
|
| 49 | + torController.unregisterTorLogListener(this)
|
|
| 50 | + }
|
|
| 51 | + |
|
| 52 | + private fun setupClipboardListener() {
|
|
| 53 | + clipboardManager.addPrimaryClipChangedListener {
|
|
| 54 | + // Only show a toast for Android 12 and lower.
|
|
| 55 | + // https://developer.android.com/develop/ui/views/touch-and-input/copy-paste#duplicate-notifications
|
|
| 56 | + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
|
| 57 | + Toast.makeText(
|
|
| 58 | + getApplication<Application>().applicationContext,
|
|
| 59 | + getApplication<Application>().getString(R.string.toast_copy_link_to_clipboard), // "Copied to clipboard" already translated
|
|
| 60 | + Toast.LENGTH_SHORT,
|
|
| 61 | + ).show()
|
|
| 62 | + }
|
|
| 63 | + }
|
|
| 64 | + }
|
|
| 65 | + |
|
| 66 | + fun copyAllLogsToClipboard() { // TODO add kebab menu in top right corner which includes option to "Copy all logs"
|
|
| 67 | + clipboardManager.setPrimaryClip(
|
|
| 68 | + ClipData.newPlainText(
|
|
| 69 | + "Copied Text",
|
|
| 70 | + getAllTorLogs(),
|
|
| 71 | + ),
|
|
| 72 | + )
|
|
| 73 | + }
|
|
| 74 | + |
|
| 75 | + private fun getAllTorLogs(): String {
|
|
| 76 | + var ret = ""
|
|
| 77 | + for (log in torLogs) {
|
|
| 78 | + ret += log.text + '\n'
|
|
| 79 | + }
|
|
| 80 | + return ret
|
|
| 81 | + }
|
|
| 82 | +}
|
|
| 83 | + |
|
| 84 | +@Stable
|
|
| 85 | +data class TorLog(
|
|
| 86 | + val text: String,
|
|
| 87 | + val timestamp: Timestamp = Timestamp(System.currentTimeMillis()),
|
|
| 88 | +) |
| ... | ... | @@ -976,8 +976,7 @@ |
| 976 | 976 | <fragment
|
| 977 | 977 | android:id="@+id/torBridgeConfigFragment"
|
| 978 | 978 | android:name="org.mozilla.fenix.settings.TorBridgeConfigFragment"
|
| 979 | - android:label="@string/preferences_tor_network_settings_bridge_config"
|
|
| 980 | - tools:layout="@layout/fragment_tor_bridge_config" />
|
|
| 979 | + android:label="@string/preferences_tor_network_settings_bridge_config" />
|
|
| 981 | 980 | <fragment
|
| 982 | 981 | android:id="@+id/torBetaConnectionFeaturesFragment"
|
| 983 | 982 | android:name="org.mozilla.fenix.tor.TorBetaConnectionFeaturesFragment"
|
| ... | ... | @@ -985,9 +984,8 @@ |
| 985 | 984 | tools:layout="@layout/tor_network_settings_beta_connection_features" />
|
| 986 | 985 | <fragment
|
| 987 | 986 | android:id="@+id/torLogsFragment"
|
| 988 | - android:name="org.mozilla.fenix.tor.TorLogsFragment"
|
|
| 989 | - android:label="Tor Logs"
|
|
| 990 | - tools:layout="@layout/tor_bootstrap_logger" />
|
|
| 987 | + android:name="org.mozilla.fenix.tor.TorLogsComposeFragment"
|
|
| 988 | + android:label="@string/preferences_tor_logs" />
|
|
| 991 | 989 | |
| 992 | 990 | <fragment
|
| 993 | 991 | android:id="@+id/trackingProtectionFragment"
|