Loading packages/SystemUI/aconfig/systemui.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -629,6 +629,13 @@ flag { bug: "354711957" } flag { name: "screenshot_multidisplay_focus_change" namespace: "systemui" description: "Only capture a single display when screenshotting" bug: "362720389" } flag { name: "run_fingerprint_detect_on_dismissible_keyguard" namespace: "systemui" Loading packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt +71 −33 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.net.Uri import android.os.Trace import android.util.Log import android.view.Display import android.view.WindowManager.ScreenshotSource import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE 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.display.data.repository.DisplayRepository Loading @@ -40,7 +42,7 @@ interface TakeScreenshotExecutor { suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, requestCallback: RequestCallback requestCallback: RequestCallback, ) fun onCloseSystemDialogsReceived() Loading @@ -52,7 +54,7 @@ interface TakeScreenshotExecutor { fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) } Loading @@ -60,7 +62,7 @@ interface ScreenshotHandler { fun handleScreenshot( screenshot: ScreenshotData, finisher: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) } Loading @@ -75,7 +77,7 @@ class TakeScreenshotExecutorImpl @Inject constructor( private val interactiveScreenshotHandlerFactory: InteractiveScreenshotHandler.Factory, displayRepository: DisplayRepository, private val displayRepository: DisplayRepository, @Application private val mainScope: CoroutineScope, private val screenshotRequestProcessor: ScreenshotRequestProcessor, private val uiEventLogger: UiEventLogger, Loading @@ -95,13 +97,24 @@ constructor( override suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, requestCallback: RequestCallback requestCallback: RequestCallback, ) { if (screenshotMultidisplayFocusChange()) { val display = getDisplayToScreenshot(screenshotRequest) val screenshotHandler = getScreenshotController(display) dispatchToController( screenshotHandler, ScreenshotData.fromRequest(screenshotRequest, display.displayId), onSaved, requestCallback, ) } else { val displays = getDisplaysToScreenshot(screenshotRequest.type) val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback) if (displays.isEmpty()) { Log.wtf(TAG, "No displays found for screenshot.") Log.e(TAG, "No displays found for screenshot.") } displays.forEach { display -> val displayId = display.displayId var screenshotHandler: ScreenshotHandler = Loading @@ -110,6 +123,7 @@ constructor( } else { headlessScreenshotHandler } Log.d(TAG, "Executing screenshot for display $displayId") dispatchToController( screenshotHandler, Loading @@ -118,17 +132,18 @@ constructor( if (displayId == Display.DEFAULT_DISPLAY) { onSaved } else { _ -> }, callback = resultCallbackWrapper.createCallbackForId(displayId) callback = resultCallbackWrapper.createCallbackForId(displayId), ) } } } /** All logging should be triggered only by this method. */ private suspend fun dispatchToController( screenshotHandler: ScreenshotHandler, rawScreenshotData: ScreenshotData, onSaved: (Uri?) -> Unit, callback: RequestCallback callback: RequestCallback, ) { // Let's wait before logging "screenshot requested", as we should log the processed // ScreenshotData. Loading Loading @@ -160,13 +175,13 @@ constructor( uiEventLogger.log( ScreenshotEvent.getScreenshotSource(screenshotData.source), 0, screenshotData.packageNameString screenshotData.packageNameString, ) } private fun onFailedScreenshotRequest( screenshotData: ScreenshotData, callback: RequestCallback callback: RequestCallback, ) { uiEventLogger.log(SCREENSHOT_CAPTURE_FAILED, 0, screenshotData.packageNameString) getNotificationController(screenshotData.displayId) Loading @@ -184,6 +199,31 @@ constructor( } } // Return the single display to be screenshot based upon the request. private suspend fun getDisplayToScreenshot(screenshotRequest: ScreenshotRequest): Display { return when (screenshotRequest.source) { // TODO(b/367394043): Overview requests should use a display ID provided in // ScreenshotRequest. ScreenshotSource.SCREENSHOT_OVERVIEW -> displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") // Key chord and vendor gesture occur on the device itself, so screenshot the device's // display ScreenshotSource.SCREENSHOT_KEY_CHORD, ScreenshotSource.SCREENSHOT_VENDOR_GESTURE -> displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") // All other invocations use the focused display else -> focusedDisplay() } } // TODO(b/367394043): Determine the focused display here. private suspend fun focusedDisplay() = displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") /** Propagates the close system dialog signal to the ScreenshotController. */ override fun onCloseSystemDialogsReceived() { if (screenshotController?.isPendingSharedTransition() == false) { Loading Loading @@ -214,7 +254,7 @@ constructor( override fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) { mainScope.launch { executeScreenshots(screenshotRequest, { uri -> onSaved.accept(uri) }, requestCallback) Loading @@ -235,9 +275,7 @@ constructor( * - If any finished with an error, [reportError] of [originalCallback] is called * - Otherwise, [onFinish] is called. */ private class MultiResultCallbackWrapper( private val originalCallback: RequestCallback, ) { private class MultiResultCallbackWrapper(private val originalCallback: RequestCallback) { private val idsPending = mutableSetOf<Int>() private val idsWithErrors = mutableSetOf<Int>() Loading Loading @@ -290,7 +328,7 @@ constructor( Display.TYPE_EXTERNAL, Display.TYPE_INTERNAL, Display.TYPE_OVERLAY, Display.TYPE_WIFI Display.TYPE_WIFI, ) } } packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt +73 −5 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ package com.android.systemui.screenshot import android.content.ComponentName import android.graphics.Bitmap import android.net.Uri import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.Display import android.view.Display.TYPE_EXTERNAL import android.view.Display.TYPE_INTERNAL Loading @@ -15,6 +17,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake 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.display Loading Loading @@ -75,6 +78,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_severalDisplays_callsControllerForEachOne() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) Loading Loading @@ -106,6 +110,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) Loading @@ -115,7 +120,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.executeScreenshots( createScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE), onSaved, callback callback, ) verify(controllerFactory).create(eq(internalDisplay)) Loading @@ -137,6 +142,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_onlyVirtualDisplays_noInteractionsWithControllers() = testScope.runTest { setDisplays(display(TYPE_VIRTUAL, id = 0), display(TYPE_VIRTUAL, id = 1)) Loading @@ -149,6 +155,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allowedTypes_allCaptured() = testScope.runTest { whenever(controllerFactory.create(any())).thenReturn(controller) Loading @@ -157,7 +164,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1), display(TYPE_OVERLAY, id = 2), display(TYPE_WIFI, id = 3) display(TYPE_WIFI, id = 3), ) val onSaved = { _: Uri? -> } screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) Loading @@ -168,6 +175,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_reportsOnFinishedOnlyWhenBothFinished() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading @@ -193,6 +201,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_oneFinishesOtherFails_reportFailsOnlyAtTheEnd() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -220,6 +229,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allDisplaysFail_reportsFail() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -319,6 +329,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsScreenshotRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading @@ -336,6 +347,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsUiError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -379,7 +391,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_reportsRequested() = @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -399,7 +412,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_reportsError() = @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_reportsRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) val screenshotRequested = eventLogger.logs.filter { it.eventId == ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id } assertThat(screenshotRequested).hasSize(1) screenshotExecutor.onDestroy() } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -419,7 +452,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_reportsError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) val screenshotRequested = eventLogger.logs.filter { it.eventId == ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED.id } assertThat(screenshotRequested).hasSize(1) screenshotExecutor.onDestroy() } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_showsErrorNotification() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -435,6 +488,21 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.onDestroy() } @Test @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) verify(notificationsController0).notifyScreenshotError(any()) screenshotExecutor.onDestroy() } @Test fun executeScreenshots_finisherCalledWithNullUri_succeeds() = testScope.runTest { Loading Loading
packages/SystemUI/aconfig/systemui.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -629,6 +629,13 @@ flag { bug: "354711957" } flag { name: "screenshot_multidisplay_focus_change" namespace: "systemui" description: "Only capture a single display when screenshotting" bug: "362720389" } flag { name: "run_fingerprint_detect_on_dismissible_keyguard" namespace: "systemui" Loading
packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt +71 −33 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.net.Uri import android.os.Trace import android.util.Log import android.view.Display import android.view.WindowManager.ScreenshotSource import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE 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.display.data.repository.DisplayRepository Loading @@ -40,7 +42,7 @@ interface TakeScreenshotExecutor { suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, requestCallback: RequestCallback requestCallback: RequestCallback, ) fun onCloseSystemDialogsReceived() Loading @@ -52,7 +54,7 @@ interface TakeScreenshotExecutor { fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) } Loading @@ -60,7 +62,7 @@ interface ScreenshotHandler { fun handleScreenshot( screenshot: ScreenshotData, finisher: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) } Loading @@ -75,7 +77,7 @@ class TakeScreenshotExecutorImpl @Inject constructor( private val interactiveScreenshotHandlerFactory: InteractiveScreenshotHandler.Factory, displayRepository: DisplayRepository, private val displayRepository: DisplayRepository, @Application private val mainScope: CoroutineScope, private val screenshotRequestProcessor: ScreenshotRequestProcessor, private val uiEventLogger: UiEventLogger, Loading @@ -95,13 +97,24 @@ constructor( override suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, requestCallback: RequestCallback requestCallback: RequestCallback, ) { if (screenshotMultidisplayFocusChange()) { val display = getDisplayToScreenshot(screenshotRequest) val screenshotHandler = getScreenshotController(display) dispatchToController( screenshotHandler, ScreenshotData.fromRequest(screenshotRequest, display.displayId), onSaved, requestCallback, ) } else { val displays = getDisplaysToScreenshot(screenshotRequest.type) val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback) if (displays.isEmpty()) { Log.wtf(TAG, "No displays found for screenshot.") Log.e(TAG, "No displays found for screenshot.") } displays.forEach { display -> val displayId = display.displayId var screenshotHandler: ScreenshotHandler = Loading @@ -110,6 +123,7 @@ constructor( } else { headlessScreenshotHandler } Log.d(TAG, "Executing screenshot for display $displayId") dispatchToController( screenshotHandler, Loading @@ -118,17 +132,18 @@ constructor( if (displayId == Display.DEFAULT_DISPLAY) { onSaved } else { _ -> }, callback = resultCallbackWrapper.createCallbackForId(displayId) callback = resultCallbackWrapper.createCallbackForId(displayId), ) } } } /** All logging should be triggered only by this method. */ private suspend fun dispatchToController( screenshotHandler: ScreenshotHandler, rawScreenshotData: ScreenshotData, onSaved: (Uri?) -> Unit, callback: RequestCallback callback: RequestCallback, ) { // Let's wait before logging "screenshot requested", as we should log the processed // ScreenshotData. Loading Loading @@ -160,13 +175,13 @@ constructor( uiEventLogger.log( ScreenshotEvent.getScreenshotSource(screenshotData.source), 0, screenshotData.packageNameString screenshotData.packageNameString, ) } private fun onFailedScreenshotRequest( screenshotData: ScreenshotData, callback: RequestCallback callback: RequestCallback, ) { uiEventLogger.log(SCREENSHOT_CAPTURE_FAILED, 0, screenshotData.packageNameString) getNotificationController(screenshotData.displayId) Loading @@ -184,6 +199,31 @@ constructor( } } // Return the single display to be screenshot based upon the request. private suspend fun getDisplayToScreenshot(screenshotRequest: ScreenshotRequest): Display { return when (screenshotRequest.source) { // TODO(b/367394043): Overview requests should use a display ID provided in // ScreenshotRequest. ScreenshotSource.SCREENSHOT_OVERVIEW -> displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") // Key chord and vendor gesture occur on the device itself, so screenshot the device's // display ScreenshotSource.SCREENSHOT_KEY_CHORD, ScreenshotSource.SCREENSHOT_VENDOR_GESTURE -> displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") // All other invocations use the focused display else -> focusedDisplay() } } // TODO(b/367394043): Determine the focused display here. private suspend fun focusedDisplay() = displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") /** Propagates the close system dialog signal to the ScreenshotController. */ override fun onCloseSystemDialogsReceived() { if (screenshotController?.isPendingSharedTransition() == false) { Loading Loading @@ -214,7 +254,7 @@ constructor( override fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer<Uri?>, requestCallback: RequestCallback requestCallback: RequestCallback, ) { mainScope.launch { executeScreenshots(screenshotRequest, { uri -> onSaved.accept(uri) }, requestCallback) Loading @@ -235,9 +275,7 @@ constructor( * - If any finished with an error, [reportError] of [originalCallback] is called * - Otherwise, [onFinish] is called. */ private class MultiResultCallbackWrapper( private val originalCallback: RequestCallback, ) { private class MultiResultCallbackWrapper(private val originalCallback: RequestCallback) { private val idsPending = mutableSetOf<Int>() private val idsWithErrors = mutableSetOf<Int>() Loading Loading @@ -290,7 +328,7 @@ constructor( Display.TYPE_EXTERNAL, Display.TYPE_INTERNAL, Display.TYPE_OVERLAY, Display.TYPE_WIFI Display.TYPE_WIFI, ) } }
packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt +73 −5 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ package com.android.systemui.screenshot import android.content.ComponentName import android.graphics.Bitmap import android.net.Uri import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.Display import android.view.Display.TYPE_EXTERNAL import android.view.Display.TYPE_INTERNAL Loading @@ -15,6 +17,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake 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.display Loading Loading @@ -75,6 +78,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_severalDisplays_callsControllerForEachOne() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) Loading Loading @@ -106,6 +110,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) Loading @@ -115,7 +120,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.executeScreenshots( createScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE), onSaved, callback callback, ) verify(controllerFactory).create(eq(internalDisplay)) Loading @@ -137,6 +142,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_onlyVirtualDisplays_noInteractionsWithControllers() = testScope.runTest { setDisplays(display(TYPE_VIRTUAL, id = 0), display(TYPE_VIRTUAL, id = 1)) Loading @@ -149,6 +155,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allowedTypes_allCaptured() = testScope.runTest { whenever(controllerFactory.create(any())).thenReturn(controller) Loading @@ -157,7 +164,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1), display(TYPE_OVERLAY, id = 2), display(TYPE_WIFI, id = 3) display(TYPE_WIFI, id = 3), ) val onSaved = { _: Uri? -> } screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) Loading @@ -168,6 +175,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_reportsOnFinishedOnlyWhenBothFinished() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading @@ -193,6 +201,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_oneFinishesOtherFails_reportFailsOnlyAtTheEnd() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -220,6 +229,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allDisplaysFail_reportsFail() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -319,6 +329,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsScreenshotRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading @@ -336,6 +347,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsUiError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) Loading Loading @@ -379,7 +391,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_reportsRequested() = @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -399,7 +412,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_reportsError() = @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_reportsRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) val screenshotRequested = eventLogger.logs.filter { it.eventId == ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id } assertThat(screenshotRequested).hasSize(1) screenshotExecutor.onDestroy() } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -419,7 +452,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_reportsError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) val screenshotRequested = eventLogger.logs.filter { it.eventId == ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED.id } assertThat(screenshotRequested).hasSize(1) screenshotExecutor.onDestroy() } @Test @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_multidisplay_showsErrorNotification() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } Loading @@ -435,6 +488,21 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.onDestroy() } @Test @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } whenever(controller.handleScreenshot(any(), any(), any())) .thenThrow(IllegalStateException::class.java) screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) verify(notificationsController0).notifyScreenshotError(any()) screenshotExecutor.onDestroy() } @Test fun executeScreenshots_finisherCalledWithNullUri_succeeds() = testScope.runTest { Loading