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

Commit 9f0d4b06 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make SysUI state instances display aware" into main

parents 033a7df1 5d44d8f8
Loading
Loading
Loading
Loading
+2 −12
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -32,20 +31,11 @@ class SysUiStateExtTest : SysuiTestCase() {

    private val kosmos = testKosmos()

    private val underTest =
        SysUiState(
            FakeDisplayTracker(context),
            kosmos.sceneContainerPlugin,
        )
    private val underTest = kosmos.sysUiState

    @Test
    fun updateFlags() {
        underTest.updateFlags(
            Display.DEFAULT_DISPLAY,
            1L to true,
            2L to false,
            3L to true,
        )
        underTest.updateFlags(Display.DEFAULT_DISPLAY, 1L to true, 2L to false, 3L to true)

        assertThat(underTest.flags and 1L).isNotEqualTo(0L)
        assertThat(underTest.flags and 2L).isEqualTo(0L)
+43 −15
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ package com.android.systemui.model;
import static android.view.Display.DEFAULT_DISPLAY;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@@ -28,7 +30,7 @@ import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.DisplayTracker;

import org.junit.Before;
import org.junit.Test;
@@ -46,14 +48,23 @@ public class SysUiStateTest extends SysuiTestCase {
    private KosmosJavaAdapter mKosmos;
    private SysUiState.SysUiStateCallback mCallback;
    private SysUiState mFlagsContainer;
    private DisplayTracker mDisplayTracker;
    private SceneContainerPlugin mSceneContainerPlugin;

    private SysUiState createInstance(int displayId) {
        var sysuiState = new SysUiStateImpl(displayId, mSceneContainerPlugin);
        sysuiState.addCallback(mCallback);
        return sysuiState;
    }

    @Before
    public void setup() {
        FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
        mKosmos = new KosmosJavaAdapter(this);
        mFlagsContainer = new SysUiState(displayTracker, mKosmos.getSceneContainerPlugin());
        mDisplayTracker = mKosmos.getDisplayTracker();
        mFlagsContainer = mKosmos.getSysuiState();
        mSceneContainerPlugin = mKosmos.getSceneContainerPlugin();
        mCallback = mock(SysUiState.SysUiStateCallback.class);
        mFlagsContainer.addCallback(mCallback);
        mFlagsContainer = createInstance(DEFAULT_DISPLAY);
    }

    @Test
@@ -69,20 +80,17 @@ public class SysUiStateTest extends SysuiTestCase {
        setFlags(FLAG_2);

        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1);
        verify(mCallback, times(1))
                .onSystemUiStateChanged(FLAG_1 | FLAG_2);
        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1 | FLAG_2);
    }

    @Test
    public void addMultipleRemoveOne_setFlag() {
        setFlags(FLAG_1);
        setFlags(FLAG_2);
        mFlagsContainer.setFlag(FLAG_1, false)
                .commitUpdate(DISPLAY_ID);
        mFlagsContainer.setFlag(FLAG_1, false).commitUpdate(DISPLAY_ID);

        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1);
        verify(mCallback, times(1))
                .onSystemUiStateChanged(FLAG_1 | FLAG_2);
        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1 | FLAG_2);
        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_2);
    }

@@ -97,8 +105,7 @@ public class SysUiStateTest extends SysuiTestCase {
    @Test
    public void addMultipleRemoveOne_setFlags() {
        setFlags(FLAG_1, FLAG_2, FLAG_3, FLAG_4);
        mFlagsContainer.setFlag(FLAG_2, false)
                .commitUpdate(DISPLAY_ID);
        mFlagsContainer.setFlag(FLAG_2, false).commitUpdate(DISPLAY_ID);

        int expected1 = FLAG_1 | FLAG_2 | FLAG_3 | FLAG_4;
        verify(mCallback, times(1)).onSystemUiStateChanged(expected1);
@@ -115,10 +122,31 @@ public class SysUiStateTest extends SysuiTestCase {
        verify(mCallback, times(0)).onSystemUiStateChanged(expected);
    }

    @Test
    public void setFlag_receivedForDefaultDisplay() {
        setFlags(FLAG_1);

        verify(mCallback, times(1)).onSystemUiStateChangedForDisplay(FLAG_1, DEFAULT_DISPLAY);
    }

    @Test
    public void setFlag_externalDisplayInstance_defaultDisplayCallbackNotPropagated() {
        var instance = createInstance(/* displayId = */ 2);
        reset(mCallback);
        setFlags(instance, FLAG_1);

        verify(mCallback, times(1)).onSystemUiStateChangedForDisplay(FLAG_1, /* displayId= */ 2);
        verify(mCallback, never()).onSystemUiStateChanged(FLAG_1);
    }

    private void setFlags(int... flags) {
        for (int i = 0; i < flags.length; i++) {
            mFlagsContainer.setFlag(flags[i], true);
        setFlags(mFlagsContainer, flags);
    }

    private void setFlags(SysUiState instance, int... flags) {
        for (int flag : flags) {
            instance.setFlag(flag, true);
        }
        mFlagsContainer.commitUpdate(DISPLAY_ID);
        instance.commitUpdate();
    }
}
+1 −3
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import com.android.systemui.animation.back.BackAnimationSpec;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.model.SysUiState;
import com.android.systemui.settings.FakeDisplayTracker;

import org.junit.Before;
import org.junit.Rule;
@@ -84,8 +83,7 @@ public class SystemUIDialogTest extends SysuiTestCase {
    public void setup() {
        MockitoAnnotations.initMocks(this);
        KosmosJavaAdapter kosmos = new KosmosJavaAdapter(this);
        FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
        mSysUiState = new SysUiState(displayTracker, kosmos.getSceneContainerPlugin());
        mSysUiState = kosmos.getSysuiState();
        mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
        when(mDelegate.getBackAnimationSpec(ArgumentMatchers.any()))
                .thenReturn(mock(BackAnimationSpec.class));
+4 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.Service;
import android.app.backup.BackupManager;
import android.content.Context;
import android.service.dreams.IDreamManager;
import android.view.Display;

import androidx.annotation.Nullable;

@@ -86,8 +87,8 @@ import com.android.systemui.mediaprojection.MediaProjectionModule;
import com.android.systemui.mediaprojection.appselector.MediaProjectionActivitiesModule;
import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherModule;
import com.android.systemui.mediarouter.MediaRouterModule;
import com.android.systemui.model.SceneContainerPlugin;
import com.android.systemui.model.SysUiState;
import com.android.systemui.model.SysUiStateImpl;
import com.android.systemui.motiontool.MotionToolModule;
import com.android.systemui.navigationbar.NavigationBarComponent;
import com.android.systemui.navigationbar.gestural.dagger.GestureModule;
@@ -113,7 +114,6 @@ import com.android.systemui.scene.ui.view.WindowRootViewComponent;
import com.android.systemui.screenrecord.ScreenRecordModule;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeDisplayAwareModule;
@@ -326,10 +326,9 @@ public abstract class SystemUIModule {
    @SysUISingleton
    @Provides
    static SysUiState provideSysUiState(
            DisplayTracker displayTracker,
            DumpManager dumpManager,
            SceneContainerPlugin sceneContainerPlugin) {
        final SysUiState state = new SysUiState(displayTracker, sceneContainerPlugin);
            SysUiStateImpl.Factory sysUiStateFactory) {
        final SysUiState state = sysUiStateFactory.create(Display.DEFAULT_DISPLAY);
        dumpManager.registerDumpable(state);
        return state;
    }
+91 −32
Original line number Diff line number Diff line
@@ -16,26 +16,78 @@
package com.android.systemui.model

import android.util.Log
import android.view.Display
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.model.SysUiState.SysUiStateCallback
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dalvik.annotation.optimization.NeverCompile
import java.io.PrintWriter

/** Contains sysUi state flags and notifies registered listeners whenever changes happen. */
@SysUISingleton
class SysUiState(
    private val displayTracker: DisplayTracker,
interface SysUiState : Dumpable {
    /**
     * Add listener to be notified of changes made to SysUI state.
     *
     * The callback will also be called as part of this function.
     */
    fun addCallback(callback: SysUiStateCallback)

    /** Removes a callback for state changes. */
    fun removeCallback(callback: SysUiStateCallback)

    /** Returns whether a flag is enabled in this state. */
    fun isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean

    /** Returns the current sysui state flags. */
    val flags: Long

    /** Methods to this call can be chained together before calling [commitUpdate]. */
    fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState

    /** Call to save all the flags updated from [setFlag]. */
    @Deprecated("Each SysUIState instance is now display specific. Just use commitUpdate()")
    fun commitUpdate(displayId: Int)

    /** Call to save all the flags updated from [setFlag]. */
    fun commitUpdate()

    /** Notify all those who are registered that the state has changed. */
    fun notifyAndSetSystemUiStateChanged(newFlags: Long, oldFlags: Long)

    /** Callback to be notified whenever system UI state flags are changed. */
    interface SysUiStateCallback {
        /** To be called when any SysUiStateFlag gets updated **for the default display** */
        fun onSystemUiStateChanged(@SystemUiStateFlags sysUiFlags: Long)

        /** To be called when any SysUiStateFlag gets updated for a specific [displayId]. */
        fun onSystemUiStateChangedForDisplay(
            @SystemUiStateFlags sysUiFlags: Long,
            displayId: Int,
        ) {}
    }

    companion object {
        const val DEBUG: Boolean = false
    }
}

class SysUiStateImpl
@AssistedInject
constructor(
    @Assisted private val displayId: Int,
    private val sceneContainerPlugin: SceneContainerPlugin?,
) : Dumpable {
) : SysUiState {
    /** Returns the current sysui state flags. */
    @get:SystemUiStateFlags
    @SystemUiStateFlags
    var flags: Long = 0
        private set
    override val flags: Long
        get() = _flags

    private var _flags: Long = 0
    private val callbacks: MutableList<SysUiStateCallback> = ArrayList()
    private var flagsToSet: Long = 0
    private var flagsToClear: Long = 0
@@ -44,26 +96,26 @@ class SysUiState(
     * Add listener to be notified of changes made to SysUI state. The callback will also be called
     * as part of this function.
     */
    fun addCallback(callback: SysUiStateCallback) {
    override fun addCallback(callback: SysUiStateCallback) {
        callbacks.add(callback)
        callback.onSystemUiStateChanged(flags)
    }

    /** Callback will no longer receive events on state change */
    fun removeCallback(callback: SysUiStateCallback) {
    override fun removeCallback(callback: SysUiStateCallback) {
        callbacks.remove(callback)
    }

    fun isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean {
    override fun isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean {
        return (flags and flag) != 0L
    }

    /** Methods to this call can be chained together before calling [.commitUpdate]. */
    fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
    override fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
        var enabled = enabled
        val overrideOrNull = sceneContainerPlugin?.flagValueOverride(flag)
        if (overrideOrNull != null && enabled != overrideOrNull) {
            if (DEBUG) {
            if (SysUiState.DEBUG) {
                Log.d(
                    TAG,
                    "setFlag for flag $flag and value $enabled overridden to $overrideOrNull by scene container plugin",
@@ -81,20 +133,22 @@ class SysUiState(
        return this
    }

    /** Call to save all the flags updated from [.setFlag]. */
    fun commitUpdate(displayId: Int) {
        updateFlags(displayId)
        flagsToSet = 0
        flagsToClear = 0
    @Deprecated(
        "Each SysUIState instance is now display specific. Just use commitUpdate.",
        ReplaceWith("commitUpdate()"),
    )
    override fun commitUpdate(displayId: Int) {
        // TODO b/398011576 - handle updates for different displays.
        commitUpdate()
    }

    private fun updateFlags(displayId: Int) {
        if (displayId != displayTracker.defaultDisplayId) {
            // Ignore non-default displays for now
            Log.w(TAG, "Ignoring flag update for display: $displayId", Throwable())
            return
    override fun commitUpdate() {
        updateFlags()
        flagsToSet = 0
        flagsToClear = 0
    }

    private fun updateFlags() {
        var newState = flags
        newState = newState or flagsToSet
        newState = newState and flagsToClear.inv()
@@ -102,16 +156,22 @@ class SysUiState(
    }

    /** Notify all those who are registered that the state has changed. */
    private fun notifyAndSetSystemUiStateChanged(newFlags: Long, oldFlags: Long) {
        if (DEBUG) {
    override fun notifyAndSetSystemUiStateChanged(newFlags: Long, oldFlags: Long) {
        if (SysUiState.DEBUG) {
            Log.d(TAG, "SysUiState changed: old=$oldFlags new=$newFlags")
        }
        if (newFlags != oldFlags) {
            callbacks.forEach { callback: SysUiStateCallback ->
                if (displayId == Display.DEFAULT_DISPLAY) {
                    callback.onSystemUiStateChanged(newFlags)
                }
                callback.onSystemUiStateChangedForDisplay(
                    sysUiFlags = newFlags,
                    displayId = displayId,
                )
            }

            flags = newFlags
            _flags = newFlags
        }
    }

@@ -127,14 +187,13 @@ class SysUiState(
        pw.println(QuickStepContract.isAssistantGestureDisabled(flags))
    }

    /** Callback to be notified whenever system UI state flags are changed. */
    interface SysUiStateCallback {
        /** To be called when any SysUiStateFlag gets updated */
        fun onSystemUiStateChanged(@SystemUiStateFlags sysUiFlags: Long)
    @AssistedFactory
    interface Factory {
        /** Creates a new instance of [SysUiStateImpl] for a given [displayId]. */
        fun create(displayId: Int): SysUiStateImpl
    }

    companion object {
        private val TAG: String = SysUiState::class.java.simpleName
        const val DEBUG: Boolean = false
    }
}
Loading