Loading packages/SystemUI/aconfig/systemui.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,13 @@ flag { bug: "202262476" } flag { name: "screenshot_action_dismiss_system_windows" namespace: "systemui" description: "Dismiss existing system windows when starting action from screenshot UI" bug: "309933761" } flag { name: "run_fingerprint_detect_on_dismissible_keyguard" namespace: "systemui" Loading packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +13 −1 Original line number Diff line number Diff line Loading @@ -31,10 +31,13 @@ import android.view.WindowManager import android.view.WindowManagerGlobal import com.android.app.tracing.coroutines.launch import com.android.internal.infra.ServiceConnector import com.android.systemui.Flags.screenshotActionDismissSystemWindows import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces import javax.inject.Inject import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineDispatcher Loading @@ -46,9 +49,11 @@ class ActionIntentExecutor @Inject constructor( private val context: Context, private val activityManagerWrapper: ActivityManagerWrapper, @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, private val displayTracker: DisplayTracker, private val keyguardController: ScreenshotKeyguardController, ) { /** * Execute the given intent with startActivity while performing operations for screenshot action Loading @@ -74,7 +79,14 @@ constructor( user: UserHandle, overrideTransition: Boolean, ) { if (screenshotActionDismissSystemWindows()) { keyguardController.dismiss() activityManagerWrapper.closeSystemWindows( CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT ) } else { dismissKeyguard() } if (user == myUserHandle()) { withContext(mainDispatcher) { context.startActivity(intent, options) } Loading packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt 0 → 100644 +46 −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.screenshot import android.content.Context import android.content.Intent import com.android.internal.infra.ServiceConnector import javax.inject.Inject import kotlinx.coroutines.CompletableDeferred open class ScreenshotKeyguardController @Inject constructor(context: Context) { private val proxyConnector: ServiceConnector<IScreenshotProxy> = ServiceConnector.Impl( context, Intent(context, ScreenshotProxyService::class.java), Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE, context.userId, IScreenshotProxy.Stub::asInterface ) suspend fun dismiss() { val completion = CompletableDeferred<Unit>() val onDoneBinder = object : IOnDoneCallback.Stub() { override fun onDone(success: Boolean) { completion.complete(Unit) } } proxyConnector.post { it.dismissKeyguard(onDoneBinder) } completion.await() } } packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt 0 → 100644 +73 −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.screenshot import android.content.Intent import android.os.Process.myUserHandle import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableContext import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.util.mockito.mock import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.verify @RunWith(AndroidTestingRunner::class) class ActionIntentExecutorTest : SysuiTestCase() { private val scheduler = TestCoroutineScheduler() private val mainDispatcher = StandardTestDispatcher(scheduler) private val testScope = TestScope(mainDispatcher) private val testableContext = TestableContext(mContext) private val activityManagerWrapper = mock<ActivityManagerWrapper>() private val displayTracker = mock<DisplayTracker>() private val keyguardController = mock<ScreenshotKeyguardController>() private val actionIntentExecutor = ActionIntentExecutor( testableContext, activityManagerWrapper, testScope, mainDispatcher, displayTracker, keyguardController, ) @Test @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS) fun launchIntent_callsCloseSystemWindows() = testScope.runTest { val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK } val userHandle = myUserHandle() actionIntentExecutor.launchIntent(intent, null, userHandle, false) scheduler.advanceUntilIdle() verify(activityManagerWrapper) .closeSystemWindows(CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT) } } Loading
packages/SystemUI/aconfig/systemui.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,13 @@ flag { bug: "202262476" } flag { name: "screenshot_action_dismiss_system_windows" namespace: "systemui" description: "Dismiss existing system windows when starting action from screenshot UI" bug: "309933761" } flag { name: "run_fingerprint_detect_on_dismissible_keyguard" namespace: "systemui" Loading
packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +13 −1 Original line number Diff line number Diff line Loading @@ -31,10 +31,13 @@ import android.view.WindowManager import android.view.WindowManagerGlobal import com.android.app.tracing.coroutines.launch import com.android.internal.infra.ServiceConnector import com.android.systemui.Flags.screenshotActionDismissSystemWindows import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces import javax.inject.Inject import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineDispatcher Loading @@ -46,9 +49,11 @@ class ActionIntentExecutor @Inject constructor( private val context: Context, private val activityManagerWrapper: ActivityManagerWrapper, @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, private val displayTracker: DisplayTracker, private val keyguardController: ScreenshotKeyguardController, ) { /** * Execute the given intent with startActivity while performing operations for screenshot action Loading @@ -74,7 +79,14 @@ constructor( user: UserHandle, overrideTransition: Boolean, ) { if (screenshotActionDismissSystemWindows()) { keyguardController.dismiss() activityManagerWrapper.closeSystemWindows( CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT ) } else { dismissKeyguard() } if (user == myUserHandle()) { withContext(mainDispatcher) { context.startActivity(intent, options) } Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt 0 → 100644 +46 −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.screenshot import android.content.Context import android.content.Intent import com.android.internal.infra.ServiceConnector import javax.inject.Inject import kotlinx.coroutines.CompletableDeferred open class ScreenshotKeyguardController @Inject constructor(context: Context) { private val proxyConnector: ServiceConnector<IScreenshotProxy> = ServiceConnector.Impl( context, Intent(context, ScreenshotProxyService::class.java), Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE, context.userId, IScreenshotProxy.Stub::asInterface ) suspend fun dismiss() { val completion = CompletableDeferred<Unit>() val onDoneBinder = object : IOnDoneCallback.Stub() { override fun onDone(success: Boolean) { completion.complete(Unit) } } proxyConnector.post { it.dismissKeyguard(onDoneBinder) } completion.await() } }
packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt 0 → 100644 +73 −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.screenshot import android.content.Intent import android.os.Process.myUserHandle import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableContext import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.util.mockito.mock import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.verify @RunWith(AndroidTestingRunner::class) class ActionIntentExecutorTest : SysuiTestCase() { private val scheduler = TestCoroutineScheduler() private val mainDispatcher = StandardTestDispatcher(scheduler) private val testScope = TestScope(mainDispatcher) private val testableContext = TestableContext(mContext) private val activityManagerWrapper = mock<ActivityManagerWrapper>() private val displayTracker = mock<DisplayTracker>() private val keyguardController = mock<ScreenshotKeyguardController>() private val actionIntentExecutor = ActionIntentExecutor( testableContext, activityManagerWrapper, testScope, mainDispatcher, displayTracker, keyguardController, ) @Test @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS) fun launchIntent_callsCloseSystemWindows() = testScope.runTest { val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK } val userHandle = myUserHandle() actionIntentExecutor.launchIntent(intent, null, userHandle, false) scheduler.advanceUntilIdle() verify(activityManagerWrapper) .closeSystemWindows(CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT) } }