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

Commit eed85f83 authored by Daniel Akinola's avatar Daniel Akinola Committed by Android (Google) Code Review
Browse files

Merge "Add ShadePositionRepository" into main

parents 3daa7994 b53054e8
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.shade.data.repository

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.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.commandline.commandRegistry
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadePositionRepositoryTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val commandRegistry = kosmos.commandRegistry
    private val pw = PrintWriter(StringWriter())

    private val underTest = ShadePositionRepositoryImpl(commandRegistry)

    @Before
    fun setUp() {
        underTest.start()
    }

    @Test
    fun commandDisplayOverride_updatesDisplayId() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)
            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)

            val newDisplayId = 2
            commandRegistry.onShellCommand(
                pw,
                arrayOf("shade_display_override", newDisplayId.toString()),
            )

            assertThat(displayId).isEqualTo(newDisplayId)
        }

    @Test
    fun commandShadeDisplayOverride_resetsDisplayId() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)
            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)

            val newDisplayId = 2
            commandRegistry.onShellCommand(
                pw,
                arrayOf("shade_display_override", newDisplayId.toString()),
            )
            assertThat(displayId).isEqualTo(newDisplayId)

            commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", "reset"))
            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
        }
}
+26 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context
import android.content.res.Resources
import android.view.LayoutInflater
import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
import com.android.systemui.CoreStartable
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.ConfigurationStateImpl
import com.android.systemui.common.ui.GlobalConfig
@@ -29,12 +30,16 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.ShadePositionRepository
import com.android.systemui.shade.data.repository.ShadePositionRepositoryImpl
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.ConfigurationForwarder
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap

/**
 * Module responsible for managing display-specific components and resources for the notification
@@ -149,4 +154,25 @@ object ShadeDisplayAwareModule {
            configurationInteractor
        }
    }

    @SysUISingleton
    @Provides
    @ShadeDisplayAware
    fun provideShadePositionRepository(impl: ShadePositionRepositoryImpl): ShadePositionRepository {
        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
        return impl
    }

    @Provides
    @IntoMap
    @ClassKey(ShadePositionRepositoryImpl::class)
    fun provideShadePositionRepositoryAsCoreStartable(
        impl: ShadePositionRepositoryImpl
    ): CoreStartable {
        return if (ShadeWindowGoesAround.isEnabled) {
            impl
        } else {
            CoreStartable.NOP
        }
    }
}
+56 −0
Original line number 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.shade

import android.view.Display
import com.android.systemui.shade.data.repository.ShadePositionRepository
import com.android.systemui.statusbar.commandline.Command
import java.io.PrintWriter

class ShadePrimaryDisplayCommand(private val positionRepository: ShadePositionRepository) :
    Command {

    override fun execute(pw: PrintWriter, args: List<String>) {
        if (args[0].lowercase() == "reset") {
            positionRepository.resetDisplayId()
            pw.println("Reset shade primary display id to ${Display.DEFAULT_DISPLAY}")
            return
        }

        val displayId: Int =
            try {
                args[0].toInt()
            } catch (e: NumberFormatException) {
                pw.println("Error: task id should be an integer")
                return
            }

        if (displayId < 0) {
            pw.println("Error: display id should be positive integer")
        }

        positionRepository.setDisplayId(displayId)
        pw.println("New shade primary display id is $displayId")
    }

    override fun help(pw: PrintWriter) {
        pw.println("shade_display_override <displayId> ")
        pw.println("Set the display which is holding the shade.")
        pw.println("shade_display_override reset ")
        pw.println("Reset the display which is holding the shade.")
    }
}
+65 −0
Original line number 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.shade.data.repository

import android.view.Display
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.ShadePrimaryDisplayCommand
import com.android.systemui.statusbar.commandline.CommandRegistry
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

interface ShadePositionRepository {
    /** ID of the display which currently hosts the shade */
    val displayId: StateFlow<Int>

    /**
     * Updates the value of the shade display id stored, emitting to the new display id to every
     * component dependent on the shade display id
     */
    fun setDisplayId(displayId: Int)

    /** Resets value of shade primary display to the default display */
    fun resetDisplayId()
}

/** Source of truth for the display currently holding the shade. */
@SysUISingleton
class ShadePositionRepositoryImpl
@Inject
constructor(private val commandRegistry: CommandRegistry) : ShadePositionRepository, CoreStartable {
    private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)

    override val displayId: StateFlow<Int>
        get() = _displayId

    override fun setDisplayId(displayId: Int) {
        _displayId.value = displayId
    }

    override fun resetDisplayId() {
        _displayId.value = Display.DEFAULT_DISPLAY
    }

    override fun start() {
        commandRegistry.registerCommand("shade_display_override") {
            ShadePrimaryDisplayCommand(this)
        }
    }
}