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

Commit af6068d4 authored by Olivier St-Onge's avatar Olivier St-Onge
Browse files

Add logs to stacked mobile icon

Bug: 411370541
Test: manually taking a bugreport
Flag: com.android.settingslib.flags.new_status_bar_icons
Flag: com.android.systemui.status_bar_root_modernization
Change-Id: I88664f51ef7089732b4744fa01d8450950b1af04
parent a60b62c5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
@@ -87,6 +88,7 @@ class MobileIconsViewModelTest : SysuiTestCase() {
                    override val hasDataCapabilities = true
                    override val shouldShowActivityConfig = false
                },
                logcatTableLogBuffer(kosmos, "summaryLogger"),
                testScope.backgroundScope,
            )

+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.statusbar.pipeline.dagger

import javax.inject.Qualifier

/** Logs for the dual-sim mobile icon. */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class StackedMobileIconTableLog
+7 −0
Original line number Diff line number Diff line
@@ -318,6 +318,13 @@ abstract class StatusBarPipelineModule {
            return factory.create("DeviceBasedSatelliteTableLog", 200)
        }

        @Provides
        @SysUISingleton
        @StackedMobileIconTableLog
        fun provideStackedMobileIconTableLog(factory: TableLogBufferFactory): TableLogBuffer {
            return factory.create("StackedMobileIconTableLog", 100)
        }

        const val FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON =
            "FirstMobileSubShowingNetworkTypeIcon"
    }
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.statusbar.pipeline.mobile.ui.model

import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
import com.android.systemui.statusbar.pipeline.mobile.ui.model.DualSimConstants.COL_IS_NULL
import com.android.systemui.statusbar.pipeline.mobile.ui.model.DualSimConstants.COL_PRIMARY_SUB_ID
import com.android.systemui.statusbar.pipeline.mobile.ui.model.DualSimConstants.COL_SECONDARY_SUB_ID
import com.android.systemui.statusbar.pipeline.mobile.ui.model.DualSimConstants.PREFIX_PRIMARY
import com.android.systemui.statusbar.pipeline.mobile.ui.model.DualSimConstants.PREFIX_SECONDARY

data class DualSim(
    private val primarySubId: Int,
    private val secondarySubId: Int,
    val primary: SignalIconModel.Cellular,
    val secondary: SignalIconModel.Cellular,
) : Diffable<DualSim> {
    constructor(
        primary: Pair<Int, SignalIconModel.Cellular>,
        secondary: Pair<Int, SignalIconModel.Cellular>,
    ) : this(
        primarySubId = primary.first,
        primary = primary.second,
        secondarySubId = secondary.first,
        secondary = secondary.second,
    )

    override fun logDiffs(prevVal: DualSim, row: TableRowLogger) {
        if (prevVal != this) {
            logFull(row)
        } else {
            if (primarySubId != prevVal.primarySubId) {
                row.logChange(COL_PRIMARY_SUB_ID, primarySubId)
            }
            if (secondarySubId != prevVal.secondarySubId) {
                row.logChange(COL_SECONDARY_SUB_ID, secondarySubId)
            }
            primary.logDiffs(prevVal.primary, TableRowLoggerWithPrefix(row, PREFIX_PRIMARY))
            secondary.logDiffs(prevVal.secondary, TableRowLoggerWithPrefix(row, PREFIX_SECONDARY))
        }
    }

    override fun logFull(row: TableRowLogger) {
        row.logChange(COL_PRIMARY_SUB_ID, primarySubId)
        row.logChange(COL_SECONDARY_SUB_ID, secondarySubId)
        primary.logFull(TableRowLoggerWithPrefix(row, PREFIX_PRIMARY))
        secondary.logFull(TableRowLoggerWithPrefix(row, PREFIX_SECONDARY))
    }

    /**
     * Wrapper for [TableRowLogger] to add a prefix to all columns. Useful when logging multiple
     * [SignalIconModel] while being able to differentiate them.
     */
    private class TableRowLoggerWithPrefix(
        private val row: TableRowLogger,
        private val prefix: String,
    ) : TableRowLogger {
        override fun logChange(columnName: String, value: String?) {
            row.logChange("$prefix.$columnName", value)
        }

        override fun logChange(columnName: String, value: Boolean) {
            row.logChange("$prefix.$columnName", value)
        }

        override fun logChange(columnName: String, value: Int) {
            row.logChange("$prefix.$columnName", value)
        }
    }
}

/**
 * Tries to build a [DualSim] from the list of [SignalIconModel].
 *
 * A [DualSim] requires the connections to be stackable, meaning that there's exactly two cellular
 * connections.
 *
 * @param idsToIcon list of subscription ids to [SignalIconModel]
 * @return a [DualSim] representing the connections, or null if the connections are not stackable.
 */
fun tryParseDualSim(idsToIcon: List<Pair<Int, SignalIconModel>>): DualSim? {
    var first: Pair<Int, SignalIconModel.Cellular>? = null
    var second: Pair<Int, SignalIconModel.Cellular>? = null
    for ((id, icon) in idsToIcon) {
        when {
            icon !is SignalIconModel.Cellular -> continue
            first == null -> {
                first = id to icon
            }
            second == null -> {
                second = id to icon
            }
            else -> return null
        }
    }
    return first?.let { second?.let { DualSim(first, second) } }
}

/** Logs the [DualSim] difference between [old] and [new] using the provided [TableLogBuffer]. */
fun logDualSimDiff(old: DualSim?, new: DualSim?, tableLogger: TableLogBuffer) {
    if (old != null && new != null) {
        tableLogger.logChange { new.logDiffs(old, it) }
    } else if (old == null && new != null) {
        tableLogger.logChange {
            it.logChange(COL_IS_NULL, false)
            new.logFull(it)
        }
    } else if (old != null) {
        tableLogger.logChange { it.logChange(COL_IS_NULL, true) }
    }
}

private object DualSimConstants {
    const val COL_IS_NULL = "isNull"
    const val COL_PRIMARY_SUB_ID = "primarySubId"
    const val COL_SECONDARY_SUB_ID = "secondarySubId"
    const val PREFIX_PRIMARY = "primary"
    const val PREFIX_SECONDARY = "secondary"
}
+28 −3
Original line number Diff line number Diff line
@@ -21,8 +21,11 @@ import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.coroutines.newTracingContext
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
@@ -58,6 +61,7 @@ constructor(
    private val interactor: MobileIconsInteractor,
    private val airplaneModeInteractor: AirplaneModeInteractor,
    private val constants: ConnectivityConstants,
    @MobileSummaryLog private val tableLogger: TableLogBuffer,
    @Background private val scope: CoroutineScope,
) {
    @VisibleForTesting
@@ -103,14 +107,29 @@ constructor(

    /** Whether all of [mobileSubViewModels] are visible or not. */
    private val iconsAreAllVisible =
        mobileSubViewModels.flatMapLatest { viewModels ->
            combine(viewModels.map { it.isVisible }) { isVisibleArray -> isVisibleArray.all { it } }
        mobileSubViewModels
            .flatMapLatest { viewModels ->
                combine(viewModels.map { it.isVisible }) { isVisibleArray ->
                    isVisibleArray.all { it }
                }
            }
            .logDiffsForTable(
                tableLogger,
                LOGGING_PREFIX,
                columnName = COL_ICONS_VISIBLE,
                initialValue = false,
            )

    val isStackable: StateFlow<Boolean> =
        combine(iconsAreAllVisible, interactor.isStackable) { isVisible, isStackable ->
                isVisible && isStackable
            }
            .logDiffsForTable(
                tableLogger,
                LOGGING_PREFIX,
                columnName = COL_IS_STACKABLE,
                initialValue = false,
            )
            .stateIn(scope, SharingStarted.WhileSubscribed(), false)

    init {
@@ -161,4 +180,10 @@ constructor(
                    ?.cancel()
            }
    }

    companion object {
        private const val LOGGING_PREFIX = "VM"
        private const val COL_IS_STACKABLE = "isStackable"
        private const val COL_ICONS_VISIBLE = "iconsAreAllVisible"
    }
}
Loading