Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android

Commits:

4 changed files:

Changes:

  • fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsComposeFragment.kt
    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
    +}

  • fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsFragment.kt deleted
    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
    -}

  • fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsViewModel.kt
    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
    +)

  • fenix/app/src/main/res/navigation/nav_graph.xml
    ... ... @@ -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"