Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58f96544 authored by Stefan Andonian's avatar Stefan Andonian
Browse files

Save Custom Trace Settings in Persistent Storage.

This will allow Custom Trace Settings to be sent to Traceur to start,
stop, and share custom traces.

Bug: 305049544
Test: Tested this manually on device.
Flag: com.android.systemui.record_issue_qs_tile
Change-Id: Ibbfdee100a12685deef56e062c9f4d3c0c8938d7
parent 493ff8b5
Loading
Loading
Loading
Loading
+60 −30
Original line number Original line Diff line number Diff line
@@ -29,14 +29,16 @@ import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.traceur.PresetTraceConfigs
import com.android.traceur.PresetTraceConfigs
import com.android.traceur.TraceConfig
import com.android.traceur.TraceConfig
import com.android.traceur.res.R as T
import com.android.traceur.res.R as T
import java.util.function.Consumer


class CustomTraceSettingsDialogDelegate(
class CustomTraceSettingsDialogDelegate(
    private val factory: SystemUIDialog.Factory,
    private val factory: SystemUIDialog.Factory,
    private val state: IssueRecordingState,
    private val customTraceState: CustomTraceState,
    private val tagTitles: Set<String>,
    private val onSave: Runnable,
    private val onSave: Runnable,
) : SystemUIDialog.Delegate {
) : SystemUIDialog.Delegate {


    private val builder = TraceConfig.Builder(PresetTraceConfigs.getDefaultConfig())
    private val builder = TraceConfig.Builder(customTraceState.traceConfig)


    override fun createDialog(): SystemUIDialog = factory.create(this)
    override fun createDialog(): SystemUIDialog = factory.create(this)


@@ -48,7 +50,10 @@ class CustomTraceSettingsDialogDelegate(
            setView(
            setView(
                LayoutInflater.from(context).inflate(R.layout.custom_trace_settings_dialog, null)
                LayoutInflater.from(context).inflate(R.layout.custom_trace_settings_dialog, null)
            )
            )
            setPositiveButton(R.string.save) { _, _ -> onSave.run() }
            setPositiveButton(R.string.save) { _, _ ->
                onSave.run()
                customTraceState.traceConfig = builder.build()
            }
            setNegativeButton(R.string.cancel) { _, _ -> }
            setNegativeButton(R.string.cancel) { _, _ -> }
        }
        }
    }
    }
@@ -62,35 +67,50 @@ class CustomTraceSettingsDialogDelegate(
                text =
                text =
                    context.getString(T.string.categories) +
                    context.getString(T.string.categories) +
                        "\n" +
                        "\n" +
                        if (
                            builder.tags == null ||
                                builder.tags!! == PresetTraceConfigs.getDefaultConfig().tags
                        ) {
                            context.getString(R.string.notification_alert_title)
                            context.getString(R.string.notification_alert_title)
                        } else {
                            tagTitles
                                .filter {
                                    builder.tags!!.contains(it.substringBefore(TAG_TITLE_DELIMITER))
                                }
                                .joinToString()
                        }
                setOnClickListener { showCategorySelector(this) }
                setOnClickListener { showCategorySelector(this) }
            }
            }
            requireViewById<Switch>(R.id.attach_to_bugreport_switch).apply {
            requireViewById<Switch>(R.id.attach_to_bugreport_switch).apply {
                isChecked = builder.attachToBugreport
                isChecked = builder.attachToBugreport
                setOnCheckedChangeListener { _, isChecked -> builder.attachToBugreport = isChecked }
            }
            }
            requireViewById<TextView>(R.id.cpu_buffer_size)
            requireViewById<TextView>(R.id.cpu_buffer_size).setupSingleChoiceText(
                .setupSingleChoiceText(
                T.array.buffer_size_values,
                T.array.buffer_size_values,
                T.array.buffer_size_names,
                T.array.buffer_size_names,
                builder.bufferSizeKb,
                builder.bufferSizeKb,
                T.string.buffer_size,
                T.string.buffer_size,
                )
            ) {
                builder.bufferSizeKb = it
            }
            val longTraceSizeText: TextView =
            val longTraceSizeText: TextView =
                requireViewById<TextView>(R.id.long_trace_size)
                requireViewById<TextView>(R.id.long_trace_size).setupSingleChoiceText(
                    .setupSingleChoiceText(
                    T.array.long_trace_size_values,
                    T.array.long_trace_size_values,
                    T.array.long_trace_size_names,
                    T.array.long_trace_size_names,
                    builder.maxLongTraceSizeMb,
                    builder.maxLongTraceSizeMb,
                    T.string.max_long_trace_size,
                    T.string.max_long_trace_size,
                    )
                ) {
                    builder.maxLongTraceSizeMb = it
                }
            val longTraceDurationText: TextView =
            val longTraceDurationText: TextView =
                requireViewById<TextView>(R.id.long_trace_duration)
                requireViewById<TextView>(R.id.long_trace_duration).setupSingleChoiceText(
                    .setupSingleChoiceText(
                    T.array.long_trace_duration_values,
                    T.array.long_trace_duration_values,
                    T.array.long_trace_duration_names,
                    T.array.long_trace_duration_names,
                    builder.maxLongTraceDurationMinutes,
                    builder.maxLongTraceDurationMinutes,
                    T.string.max_long_trace_duration,
                    T.string.max_long_trace_duration,
                    )
                ) {
                    builder.maxLongTraceDurationMinutes = it
                }
            requireViewById<Switch>(R.id.long_traces_switch).apply {
            requireViewById<Switch>(R.id.long_traces_switch).apply {
                isChecked = builder.longTrace
                isChecked = builder.longTrace
                val disabledAlpha by lazy { getDisabledAlpha(context) }
                val disabledAlpha by lazy { getDisabledAlpha(context) }
@@ -99,6 +119,7 @@ class CustomTraceSettingsDialogDelegate(
                longTraceSizeText.alpha = alpha
                longTraceSizeText.alpha = alpha


                setOnCheckedChangeListener { _, isChecked ->
                setOnCheckedChangeListener { _, isChecked ->
                    builder.longTrace = isChecked
                    longTraceDurationText.isEnabled = isChecked
                    longTraceDurationText.isEnabled = isChecked
                    longTraceSizeText.isEnabled = isChecked
                    longTraceSizeText.isEnabled = isChecked


@@ -107,9 +128,13 @@ class CustomTraceSettingsDialogDelegate(
                    longTraceSizeText.alpha = newAlpha
                    longTraceSizeText.alpha = newAlpha
                }
                }
            }
            }
            requireViewById<Switch>(R.id.winscope_switch).apply { isChecked = builder.winscope }
            requireViewById<Switch>(R.id.winscope_switch).apply {
                isChecked = builder.winscope
                setOnCheckedChangeListener { _, isChecked -> builder.winscope = isChecked }
            }
            requireViewById<Switch>(R.id.trace_debuggable_apps_switch).apply {
            requireViewById<Switch>(R.id.trace_debuggable_apps_switch).apply {
                isChecked = builder.apps
                isChecked = builder.apps
                setOnCheckedChangeListener { _, isChecked -> builder.apps = isChecked }
            }
            }
            requireViewById<TextView>(R.id.long_traces_switch_label).text =
            requireViewById<TextView>(R.id.long_traces_switch_label).text =
                context.getString(T.string.long_traces)
                context.getString(T.string.long_traces)
@@ -125,10 +150,11 @@ class CustomTraceSettingsDialogDelegate(
    @SuppressLint("SetTextI18n")
    @SuppressLint("SetTextI18n")
    private fun showCategorySelector(root: TextView) {
    private fun showCategorySelector(root: TextView) {
        showDialog(root.context) {
        showDialog(root.context) {
            val tags = builder.tags ?: PresetTraceConfigs.getDefaultConfig().tags
            val titlesToCheckmarks =
            val titlesToCheckmarks =
                state.tagTitles.associateBy(
                tagTitles.associateBy(
                    { it },
                    { it },
                    { builder.tags.contains(it.substringBefore(TAG_TITLE_DELIMITER)) }
                    { tags.contains(it.substringBefore(TAG_TITLE_DELIMITER)) }
                )
                )
            val titles = titlesToCheckmarks.keys.toTypedArray()
            val titles = titlesToCheckmarks.keys.toTypedArray()
            val checkmarks = titlesToCheckmarks.values.toBooleanArray()
            val checkmarks = titlesToCheckmarks.values.toBooleanArray()
@@ -138,7 +164,7 @@ class CustomTraceSettingsDialogDelegate(
                    .map { it.key.substringAfter(TAG_TITLE_DELIMITER) }
                    .map { it.key.substringAfter(TAG_TITLE_DELIMITER) }
                    .toMutableSet()
                    .toMutableSet()


            val newTags = builder.tags.toMutableSet()
            val newTags = tags.toMutableSet()
            setMultiChoiceItems(titles, checkmarks) { _, i, isChecked ->
            setMultiChoiceItems(titles, checkmarks) { _, i, isChecked ->
                val tag = titles[i].substringBefore(TAG_TITLE_DELIMITER)
                val tag = titles[i].substringBefore(TAG_TITLE_DELIMITER)
                val titleSuffix = titles[i].substringAfter(TAG_TITLE_DELIMITER)
                val titleSuffix = titles[i].substringAfter(TAG_TITLE_DELIMITER)
@@ -154,13 +180,15 @@ class CustomTraceSettingsDialogDelegate(
                root.text =
                root.text =
                    root.context.resources.getString(T.string.categories) +
                    root.context.resources.getString(T.string.categories) +
                        "\n" +
                        "\n" +
                        checkedTitleSuffixes.fold("") { acc, s -> "$acc, $s" }.substringAfter(", ")
                        checkedTitleSuffixes.joinToString()
                builder.tags = newTags
            }
            }
            setNeutralButton(R.string.restore_default) { _, _ ->
            setNeutralButton(R.string.restore_default) { _, _ ->
                root.text =
                root.text =
                    context.getString(T.string.categories) +
                    context.getString(T.string.categories) +
                        "\n" +
                        "\n" +
                        context.getString(R.string.notification_alert_title)
                        context.getString(R.string.notification_alert_title)
                builder.tags = null
            }
            }
            setNegativeButton(R.string.cancel) { _, _ -> }
            setNegativeButton(R.string.cancel) { _, _ -> }
        }
        }
@@ -172,6 +200,7 @@ class CustomTraceSettingsDialogDelegate(
        resNames: Int,
        resNames: Int,
        startingValue: Int,
        startingValue: Int,
        alertTitleRes: Int,
        alertTitleRes: Int,
        onChosen: Consumer<Int>,
    ): TextView {
    ): TextView {
        val values = resources.getStringArray(resValues).map { Integer.parseInt(it) }
        val values = resources.getStringArray(resValues).map { Integer.parseInt(it) }
        val names = resources.getStringArray(resNames)
        val names = resources.getStringArray(resNames)
@@ -183,6 +212,7 @@ class CustomTraceSettingsDialogDelegate(
                setTitle(alertTitleRes)
                setTitle(alertTitleRes)
                setSingleChoiceItems(names, startingIndex) { d, i ->
                setSingleChoiceItems(names, startingIndex) { d, i ->
                    text = resources.getString(alertTitleRes) + "\n${names[i]}"
                    text = resources.getString(alertTitleRes) + "\n${names[i]}"
                    onChosen.accept(values[i])
                    d.dismiss()
                    d.dismiss()
                }
                }
            }
            }
+74 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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 com.android.systemui.recordissue

import android.content.SharedPreferences
import com.android.traceur.PresetTraceConfigs.TraceOptions
import com.android.traceur.PresetTraceConfigs.getDefaultConfig
import com.android.traceur.TraceConfig

class CustomTraceState(private val prefs: SharedPreferences) {

    private var enabledTags: Set<String>?
        get() = prefs.getStringSet(KEY_TAGS, getDefaultConfig().tags) ?: getDefaultConfig().tags
        set(value) = prefs.edit().putStringSet(KEY_TAGS, value).apply()

    var traceConfig: TraceConfig
        get() = TraceConfig(options, enabledTags)
        set(value) {
            enabledTags = value.tags
            options = value.options
        }

    private var options: TraceOptions
        get() =
            TraceOptions(
                prefs.getInt(KEY_CUSTOM_BUFFER_SIZE_KB, getDefaultConfig().bufferSizeKb),
                prefs.getBoolean(KEY_WINSCOPE, getDefaultConfig().winscope),
                prefs.getBoolean(KEY_APPS, getDefaultConfig().apps),
                prefs.getBoolean(KEY_LONG_TRACE, getDefaultConfig().longTrace),
                prefs.getBoolean(KEY_ATTACH_TO_BUGREPORT, getDefaultConfig().attachToBugreport),
                prefs.getInt(KEY_LONG_TRACE_SIZE_MB, getDefaultConfig().maxLongTraceSizeMb),
                prefs.getInt(
                    KEY_LONG_TRACE_DURATION_MINUTES,
                    getDefaultConfig().maxLongTraceDurationMinutes
                ),
            )
        set(value) {
            prefs
                .edit()
                .putInt(KEY_CUSTOM_BUFFER_SIZE_KB, value.bufferSizeKb)
                .putBoolean(KEY_WINSCOPE, value.winscope)
                .putBoolean(KEY_APPS, value.apps)
                .putBoolean(KEY_LONG_TRACE, value.longTrace)
                .putBoolean(KEY_ATTACH_TO_BUGREPORT, value.attachToBugreport)
                .putInt(KEY_LONG_TRACE_SIZE_MB, value.maxLongTraceSizeMb)
                .putInt(KEY_LONG_TRACE_DURATION_MINUTES, value.maxLongTraceDurationMinutes)
                .apply()
        }

    companion object {
        private const val KEY_CUSTOM_BUFFER_SIZE_KB = "key_bufferSizeKb"
        private const val KEY_WINSCOPE = "key_winscope"
        private const val KEY_APPS = "key_apps"
        private const val KEY_LONG_TRACE = "key_longTrace"
        private const val KEY_ATTACH_TO_BUGREPORT = "key_attachToBugReport"
        private const val KEY_LONG_TRACE_SIZE_MB = "key_maxLongTraceSizeMb"
        private const val KEY_LONG_TRACE_DURATION_MINUTES = "key_maxLongTraceDurationInMinutes"
        private const val KEY_TAGS = "key_tags"
    }
}
+3 −1
Original line number Original line Diff line number Diff line
@@ -38,6 +38,8 @@ constructor(
    private val prefs =
    private val prefs =
        userFileManager.getSharedPreferences(TILE_SPEC, Context.MODE_PRIVATE, userTracker.userId)
        userFileManager.getSharedPreferences(TILE_SPEC, Context.MODE_PRIVATE, userTracker.userId)


    val customTraceState = CustomTraceState(prefs)

    var takeBugreport
    var takeBugreport
        get() = prefs.getBoolean(KEY_TAKE_BUG_REPORT, false)
        get() = prefs.getBoolean(KEY_TAKE_BUG_REPORT, false)
        set(value) = prefs.edit().putBoolean(KEY_TAKE_BUG_REPORT, value).apply()
        set(value) = prefs.edit().putBoolean(KEY_TAKE_BUG_REPORT, value).apply()
@@ -55,7 +57,7 @@ constructor(
        set(value) = prefs.edit().putInt(KEY_ISSUE_TYPE_RES, value).apply()
        set(value) = prefs.edit().putInt(KEY_ISSUE_TYPE_RES, value).apply()


    val traceConfig: TraceConfig
    val traceConfig: TraceConfig
        get() = ALL_ISSUE_TYPES[issueTypeRes] ?: PresetTraceConfigs.getDefaultConfig()
        get() = ALL_ISSUE_TYPES[issueTypeRes] ?: customTraceState.traceConfig


    // The 1st part of the title before the ": " is the tag, and the 2nd part is the description
    // The 1st part of the title before the ": " is the tag, and the 2nd part is the description
    var tagTitles: Set<String>
    var tagTitles: Set<String>
+5 −1
Original line number Original line Diff line number Diff line
@@ -189,7 +189,11 @@ constructor(


                if (it == R.string.custom) {
                if (it == R.string.custom) {
                    setOnMenuItemClickListener {
                    setOnMenuItemClickListener {
                        CustomTraceSettingsDialogDelegate(factory, state) {
                        CustomTraceSettingsDialogDelegate(
                                factory,
                                state.customTraceState,
                                state.tagTitles
                            ) {
                                onMenuItemClickListener.onMenuItemClick(it)
                                onMenuItemClickListener.onMenuItemClick(it)
                            }
                            }
                            .createDialog()
                            .createDialog()