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

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

Merge "Change strategy to move the shade" into main

parents 003fca61 1f7284d3
Loading
Loading
Loading
Loading
+5 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.shade.domain.interactor

import android.content.Context
import android.content.MutableContextWrapper
import android.content.res.Configuration
import android.content.res.Resources
import android.view.Display
@@ -66,11 +67,12 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        ShadeDisplaysInteractor(
            shadeRootview,
            positionRepository,
            defaultContext,
            MutableContextWrapper(defaultContext),
            resources,
            contextStore,
            testScope,
            testScope.backgroundScope,
            configurationForwarder,
            testScope.coroutineContext,
            testScope.backgroundScope.coroutineContext,
        )

    @Before
@@ -78,7 +80,6 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        whenever(shadeRootview.display).thenReturn(display)
        whenever(display.displayId).thenReturn(0)

        whenever(resources.configuration).thenReturn(configuration)
        whenever(resources.configuration).thenReturn(configuration)

        whenever(defaultContext.displayId).thenReturn(0)
@@ -124,7 +125,6 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        whenever(display.displayId).thenReturn(0)
        positionRepository.setDisplayId(1)
        interactor.start()
        testScope.advanceUntilIdle()

        verify(defaultWm).removeView(eq(shadeRootview))
        verify(secondaryWm).addView(eq(shadeRootview), any())
@@ -135,10 +135,8 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        whenever(display.displayId).thenReturn(0)
        positionRepository.setDisplayId(0)
        interactor.start()
        testScope.advanceUntilIdle()

        positionRepository.setDisplayId(1)
        testScope.advanceUntilIdle()

        verify(defaultWm).removeView(eq(shadeRootview))
        verify(secondaryWm).addView(eq(shadeRootview), any())
@@ -149,10 +147,8 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        whenever(display.displayId).thenReturn(0)
        positionRepository.setDisplayId(0)
        interactor.start()
        testScope.advanceUntilIdle()

        positionRepository.setDisplayId(1)
        testScope.advanceUntilIdle()

        verify(configurationForwarder).onConfigurationChanged(eq(configuration))
    }
+2 −5
Original line number Diff line number Diff line
@@ -17,9 +17,9 @@
package com.android.systemui.shade

import android.content.Context
import android.content.MutableContextWrapper
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
@@ -29,7 +29,6 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImp
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.ShadeDisplaysRepository
import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
@@ -62,9 +61,7 @@ object ShadeDisplayAwareModule {
    @SysUISingleton
    fun provideShadeDisplayAwareContext(context: Context): Context {
        return if (ShadeWindowGoesAround.isEnabled) {
            context
                .createWindowContext(context.display, TYPE_APPLICATION_OVERLAY, /* options= */ null)
                .apply { setTheme(R.style.Theme_SystemUI) }
            MutableContextWrapper(context)
        } else {
            context
        }
+78 −25
Original line number Diff line number Diff line
@@ -16,8 +16,13 @@

package com.android.systemui.shade.domain.interactor

import android.content.ComponentCallbacks
import android.content.Context
import android.content.MutableContextWrapper
import android.content.res.Configuration
import android.content.res.Resources
import android.util.Log
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
import com.android.app.tracing.coroutines.launchTraced
import com.android.app.tracing.traceSection
@@ -46,12 +51,17 @@ constructor(
    private val shadeRootView: WindowRootView,
    private val shadePositionRepository: ShadeDisplaysRepository,
    @ShadeDisplayAware private val shadeContext: Context,
    @ShadeDisplayAware private val shadeResources: Resources,
    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
    @Background private val bgScope: CoroutineScope,
    @ShadeDisplayAware private val configurationForwarder: ConfigurationForwarder,
    @Main private val mainContext: CoroutineContext,
    @ShadeDisplayAware private val shadeConfigurationForwarder: ConfigurationForwarder,
    @Main private val mainThreadContext: CoroutineContext,
) : CoreStartable {

    // TODO: b/362719719 - Get rid of this callback as the root view should automatically get the
    //  correct configuration once it's moved to another window.
    private var unregisterConfigChangedCallbacks: (() -> Unit)? = null

    override fun start() {
        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
        bgScope.launchTraced(TAG) {
@@ -60,43 +70,86 @@ constructor(
    }

    /** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */
    private suspend fun moveShadeWindowTo(destinationDisplayId: Int) {
        val currentId = shadeRootView.display.displayId
        if (currentId == destinationDisplayId) {
    private suspend fun moveShadeWindowTo(destinationId: Int) {
        Log.d(TAG, "Trying to move shade window to display with id $destinationId")
        val currentDisplay = shadeRootView.display
        if (currentDisplay == null) {
            Log.w(TAG, "Current shade display is null")
            return
        }
        val currentId = currentDisplay.displayId
        if (currentId == destinationId) {
            Log.w(TAG, "Trying to move the shade to a display it was already in")
            return
        }
        try {
            moveShadeWindow(fromId = currentId, toId = destinationDisplayId)
            moveShadeWindow(fromId = currentId, toId = destinationId)
        } catch (e: IllegalStateException) {
            Log.e(
                TAG,
                "Unable to move the shade window from display $currentId to $destinationDisplayId",
                "Unable to move the shade window from display $currentId to $destinationId",
                e,
            )
        }
    }

    private suspend fun moveShadeWindow(fromId: Int, toId: Int) {
        val sourceProperties = getDisplayWindowProperties(fromId)
        val destinationProperties = getDisplayWindowProperties(toId)
        val (_, _, _, sourceWm) = getDisplayWindowProperties(fromId)
        val (_, _, destContext, destWm) = getDisplayWindowProperties(toId)
        withContext(mainThreadContext) {
            traceSection({ "MovingShadeWindow from $fromId to $toId" }) {
            withContext(mainContext) {
                traceSection("removeView") {
                    sourceProperties.windowManager.removeView(shadeRootView)
                removeShade(sourceWm)
                addShade(destWm)
                overrideContextAndResources(newContext = destContext)
                registerConfigurationChange(destContext)
            }
            traceSection("ShadeDisplaysInteractor#onConfigurationChanged") {
                dispatchConfigurationChanged(destContext.resources.configuration)
            }
        }
    }

    private fun removeShade(wm: WindowManager): Unit =
        traceSection("removeView") { wm.removeView(shadeRootView) }

    private fun addShade(wm: WindowManager): Unit =
        traceSection("addView") {
                    destinationProperties.windowManager.addView(
                        shadeRootView,
                        ShadeWindowLayoutParams.create(shadeContext),
                    )
            wm.addView(shadeRootView, ShadeWindowLayoutParams.create(shadeContext))
        }

    private fun overrideContextAndResources(newContext: Context) {
        val contextWrapper =
            shadeContext as? MutableContextWrapper
                ?: error("Shade context is not a MutableContextWrapper!")
        contextWrapper.baseContext = newContext
        // Override needed in case someone is keeping a reference to the resources from the old
        // context.
        // TODO: b/362719719 - This shouldn't be needed, as resources should be updated when the
        //  window is moved to the new display automatically.
        shadeResources.impl = shadeContext.resources.impl
    }

    private fun dispatchConfigurationChanged(newConfig: Configuration) {
        shadeConfigurationForwarder.onConfigurationChanged(newConfig)
        shadeRootView.dispatchConfigurationChanged(newConfig)
        shadeRootView.requestLayout()
    }
        traceSection("SecondaryShadeInteractor#onConfigurationChanged") {
            configurationForwarder.onConfigurationChanged(
                destinationProperties.context.resources.configuration
            )

    private fun registerConfigurationChange(context: Context) {
        // we should keep only one at the time.
        unregisterConfigChangedCallbacks?.invoke()
        val callback =
            object : ComponentCallbacks {
                override fun onConfigurationChanged(newConfig: Configuration) {
                    dispatchConfigurationChanged(newConfig)
                }

                override fun onLowMemory() {}
            }
        context.registerComponentCallbacks(callback)
        unregisterConfigChangedCallbacks = {
            context.unregisterComponentCallbacks(callback)
            unregisterConfigChangedCallbacks = null
        }
    }

@@ -105,6 +158,6 @@ constructor(
    }

    private companion object {
        const val TAG = "SecondaryShadeInteractor"
        const val TAG = "ShadeDisplaysInteractor"
    }
}