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

Commit bc14312b authored by Matt Casey's avatar Matt Casey Committed by Android (Google) Code Review
Browse files

Merge "Proxy focused display ID from the sysui process to the screenshot process" into main

parents 11318d3b a31eca5d
Loading
Loading
Loading
Loading
+17 −7
Original line number Diff line number Diff line
@@ -20,12 +20,11 @@ import com.android.internal.util.ScreenshotRequest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.display.data.repository.FakeFocusedDisplayRepository
import com.android.systemui.display.data.repository.display
import com.android.systemui.screenshot.proxy.ScreenshotProxy
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.kotlinArgumentCaptor as ArgumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.lang.IllegalStateException
@@ -41,6 +40,9 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub

@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -56,10 +58,15 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
    private val fakeDisplayRepository = FakeDisplayRepository()
    private val requestProcessor = FakeRequestProcessor()
    private val topComponent = ComponentName(mContext, TakeScreenshotExecutorTest::class.java)
    private val testScope = TestScope(UnconfinedTestDispatcher())
    private val dispatcher = UnconfinedTestDispatcher()
    private val testScope = TestScope(dispatcher)
    private val eventLogger = UiEventLoggerFake()
    private val headlessHandler = mock<HeadlessScreenshotHandler>()
    private val focusedDisplayRepository = FakeFocusedDisplayRepository()

    private val screenshotProxy =
        mock<ScreenshotProxy> {
            onBlocking { getFocusedDisplay() } doReturn Display.DEFAULT_DISPLAY
        }

    private val screenshotExecutor =
        TakeScreenshotExecutorImpl(
@@ -70,7 +77,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
            eventLogger,
            notificationControllerFactory,
            headlessHandler,
            focusedDisplayRepository,
            screenshotProxy,
            dispatcher,
        )

    @Before
@@ -318,7 +326,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
            val displayId = 1
            setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = displayId))
            val onSaved = { _: Uri? -> }
            focusedDisplayRepository.setDisplayId(displayId)
            screenshotProxy.stub { onBlocking { getFocusedDisplay() } doReturn displayId }

            screenshotExecutor.executeScreenshots(
                createScreenshotRequest(
@@ -345,7 +353,9 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
                display(TYPE_INTERNAL, id = Display.DEFAULT_DISPLAY),
                display(TYPE_EXTERNAL, id = 1),
            )
            focusedDisplayRepository.setDisplayId(5) // invalid display
            screenshotProxy.stub {
                onBlocking { getFocusedDisplay() } doReturn 5 // invalid display
            }
            val onSaved = { _: Uri? -> }
            screenshotExecutor.executeScreenshots(
                createScreenshotRequest(
+15 −5
Original line number Diff line number Diff line
@@ -22,22 +22,25 @@ import android.util.Log
import android.view.Display
import android.view.WindowManager.ScreenshotSource
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.logging.UiEventLogger
import com.android.internal.util.ScreenshotRequest
import com.android.systemui.Flags.screenshotMultidisplayFocusChange
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
import com.android.systemui.screenshot.proxy.ScreenshotProxy
import java.util.function.Consumer
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext

interface TakeScreenshotExecutor {
    suspend fun executeScreenshots(
@@ -84,7 +87,8 @@ constructor(
    private val uiEventLogger: UiEventLogger,
    private val screenshotNotificationControllerFactory: ScreenshotNotificationsController.Factory,
    private val headlessScreenshotHandler: HeadlessScreenshotHandler,
    private val focusedDisplayRepository: FocusedDisplayRepository,
    private val screenshotProxy: ScreenshotProxy,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : TakeScreenshotExecutor {
    private val displays = displayRepository.displays
    private var screenshotController: InteractiveScreenshotHandler? = null
@@ -218,12 +222,15 @@ constructor(
                    ?: error("Can't find default display")

            // All other invocations use the focused display
            else ->
                displayRepository.getDisplay(focusedDisplayRepository.focusedDisplayId.value)
            else -> {
                val focusedDisplay = getFocusedDisplay()
                Log.i(TAG, "Focused display ID is $focusedDisplay")
                displayRepository.getDisplay(focusedDisplay)
                    ?: displayRepository.getDisplay(Display.DEFAULT_DISPLAY)
                    ?: error("Can't find default display")
            }
        }
    }

    /** Propagates the close system dialog signal to the ScreenshotController. */
    override fun onCloseSystemDialogsReceived() {
@@ -245,6 +252,9 @@ constructor(
        screenshotController = null
    }

    private suspend fun getFocusedDisplay() =
        withContext(backgroundDispatcher) { screenshotProxy.getFocusedDisplay() }

    private fun getNotificationController(id: Int): ScreenshotNotificationsController {
        return notificationControllers.computeIfAbsent(id) {
            screenshotNotificationControllerFactory.create(id)
+3 −0
Original line number Diff line number Diff line
@@ -26,4 +26,7 @@ interface IScreenshotProxy {

    /** Attempts to dismiss the keyguard. */
    void dismissKeyguard(IOnDoneCallback callback);

    /** Gets the ID of the display that currently has input focus. */
    int getFocusedDisplay();
}
+3 −0
Original line number Diff line number Diff line
@@ -33,4 +33,7 @@ interface ScreenshotProxy {
     * completion.
     */
    suspend fun dismissKeyguard()

    /** Get the currently focused display ID from FocusedDisplayRepository. */
    suspend fun getFocusedDisplay(): Int
}
+10 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.util.Log
import android.view.Display
import com.android.internal.infra.ServiceConnector
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
@@ -64,4 +65,13 @@ class ScreenshotProxyClient @Inject constructor(@Application context: Context) :
            Log.wtf(TAG, "Keyguard dismissal request failed")
        }
    }

    override suspend fun getFocusedDisplay(): Int = suspendCoroutine { k ->
        proxyConnector
            .postForResult { it.focusedDisplay }
            .whenComplete { display, error ->
                error?.also { Log.wtf(TAG, "getFocusedDisplay", it) }
                k.resume(display ?: Display.DEFAULT_DISPLAY)
            }
    }
}
Loading