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

Commit dcc945ed authored by Nicolo' Mazzucato's avatar Nicolo' Mazzucato
Browse files

Extract StateChange and optimize it

This extraction is needed to use "StateChange" in the next cl in the chain, to implement SysUIStateOverrides.

Also this makes it more efficient: instead of using a hashMap, now there are only bit operations.

Existing tests should cover this logic already.

Bug: 362719719
Bug: 398011576
Test: SysUIStateDisplaysInteractorTest
Flag: com.android.systemui.shade_window_goes_around
Change-Id: I42711886085a7bc68b757885df8c2f639f5529e2
parent 4fd3cb52
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.common.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.model.StateChange
import com.android.systemui.model.fakeSysUIStatePerDisplayRepository
import com.android.systemui.model.sysUiStateFactory
import com.android.systemui.model.sysuiStateInteractor
+1 −38
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.common.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.display.data.repository.PerDisplayRepository
import com.android.systemui.model.StateChange
import com.android.systemui.model.SysUiState
import javax.inject.Inject

@@ -42,41 +43,3 @@ constructor(private val sysUIStateRepository: PerDisplayRepository<SysUiState>)
    }
}
/**
 * Represents a set of state changes. A bit can either be set to `true` or `false`.
 *
 * This is used in [SysUIStateDisplaysInteractor] to selectively change bits.
 */
class StateChange {
    private val changes = mutableMapOf<Long, Boolean>()

    /**
     * Sets the [state] of the given [bit].
     *
     * @return `this` for chaining purposes
     */
    fun setFlag(bit: Long, state: Boolean): StateChange {
        changes[bit] = state
        return this
    }

    /**
     * Gets the value of a given [bit] or false if not present.
     *
     * @param bit the bit to query
     * @return the value of the bit or false if not present.
     */
    fun get(bit: Long): Boolean = changes[bit] ?: false

    /** Applies all changed flags to [sysUiState]. */
    fun applyTo(sysUiState: SysUiState) {
        changes.forEach { (bit, state) -> sysUiState.setFlag(bit, state) }
        sysUiState.commitUpdate()
    }

    /** Clears all the flags changed in a [sysUiState] */
    fun clearAllChangedFlagsIn(sysUiState: SysUiState) {
        changes.forEach { (bit, _) -> sysUiState.setFlag(bit, false) }
        sysUiState.commitUpdate()
    }
}
+82 −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.model

/**
 * Represents a set of state changes. A bit can either be set to `true` or `false`.
 *
 * This is used in [SysUIStateDisplaysInteractor] to selectively change bits.
 */
class StateChange {
    private var flagsToSet: Long = 0
    private var flagsToClear: Long = 0

    /**
     * Sets the [state] of the given [bit].
     *
     * @return `this` for chaining purposes
     */
    fun setFlag(bit: Long, state: Boolean): StateChange {
        if (state) {
            flagsToSet = flagsToSet or bit
            flagsToClear = flagsToClear and bit.inv()
        } else {
            flagsToClear = flagsToClear or bit
            flagsToSet = flagsToSet and bit.inv()
        }
        return this
    }

    fun hasChanges() = flagsToSet != 0L || flagsToClear != 0L

    /** Applies all changed flags to [sysUiState]. */
    fun applyTo(sysUiState: SysUiState) {
        iterateBits(flagsToSet or flagsToClear) { bit ->
            val isBitSetInNewState = flagsToSet and bit != 0L
            sysUiState.setFlag(bit, isBitSetInNewState)
        }
        sysUiState.commitUpdate()
    }

    fun applyTo(sysUiState: Long): Long {
        var newState = sysUiState
        newState = newState or flagsToSet
        newState = newState and flagsToClear.inv()
        return newState
    }

    private inline fun iterateBits(flags: Long, action: (bit: Long) -> Unit) {
        var remaining = flags
        while (remaining != 0L) {
            val lowestBit = remaining and -remaining
            action(lowestBit)

            remaining -= lowestBit
        }
    }

    /** Clears all the flags changed in a [sysUiState] */
    fun clearAllChangedFlagsIn(sysUiState: SysUiState) {
        iterateBits(flagsToSet or flagsToClear) { bit -> sysUiState.setFlag(bit, false) }
        sysUiState.commitUpdate()
    }

    fun clear() {
        flagsToSet = 0
        flagsToClear = 0
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ import com.android.systemui.Gefingerpoken;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.common.domain.interactor.StateChange;
import com.android.systemui.common.domain.interactor.SysUIStateDisplaysInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -122,6 +121,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardTouchHandlingViewModel
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController;
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
import com.android.systemui.model.StateChange;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationModeController;