1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.screenshot 18 19 import android.app.ActivityOptions 20 import android.app.ExitTransitionCoordinator 21 import android.content.Context 22 import android.content.Intent 23 import android.os.Bundle 24 import android.os.Process.myUserHandle 25 import android.os.RemoteException 26 import android.os.UserHandle 27 import android.util.Log 28 import android.view.IRemoteAnimationFinishedCallback 29 import android.view.IRemoteAnimationRunner 30 import android.view.RemoteAnimationAdapter 31 import android.view.RemoteAnimationTarget 32 import android.view.WindowManager 33 import android.view.WindowManagerGlobal 34 import com.android.app.tracing.coroutines.launchTraced as launch 35 import com.android.internal.infra.ServiceConnector 36 import com.android.systemui.Flags 37 import com.android.systemui.dagger.SysUISingleton 38 import com.android.systemui.dagger.qualifiers.Application 39 import com.android.systemui.dagger.qualifiers.Main 40 import com.android.systemui.screenshot.proxy.ScreenshotProxy 41 import com.android.systemui.settings.DisplayTracker 42 import com.android.systemui.shared.system.ActivityManagerWrapper 43 import com.android.systemui.statusbar.phone.CentralSurfaces 44 import javax.inject.Inject 45 import kotlinx.coroutines.CompletableDeferred 46 import kotlinx.coroutines.CoroutineDispatcher 47 import kotlinx.coroutines.CoroutineScope 48 import kotlinx.coroutines.withContext 49 50 @SysUISingleton 51 class ActionIntentExecutor 52 @Inject 53 constructor( 54 private val context: Context, 55 private val activityManagerWrapper: ActivityManagerWrapper, 56 @Application private val applicationScope: CoroutineScope, 57 @Main private val mainDispatcher: CoroutineDispatcher, 58 private val screenshotProxy: ScreenshotProxy, 59 private val displayTracker: DisplayTracker, 60 ) { 61 /** 62 * Execute the given intent with startActivity while performing operations for screenshot action 63 * launching. 64 * - Dismiss the keyguard first 65 * - If the userId is not the current user, proxy to a service running as that user to execute 66 * - After startActivity, optionally override the pending app transition. 67 */ launchIntentAsyncnull68 fun launchIntentAsync( 69 intent: Intent, 70 user: UserHandle, 71 overrideTransition: Boolean, 72 options: ActivityOptions?, 73 transitionCoordinator: ExitTransitionCoordinator?, 74 ) { 75 applicationScope.launch("$TAG#launchIntentAsync") { 76 launchIntent(intent, user, overrideTransition, options, transitionCoordinator) 77 } 78 } 79 launchIntentnull80 suspend fun launchIntent( 81 intent: Intent, 82 user: UserHandle, 83 overrideTransition: Boolean, 84 options: ActivityOptions?, 85 transitionCoordinator: ExitTransitionCoordinator?, 86 ) { 87 if (Flags.fixScreenshotActionDismissSystemWindows()) { 88 activityManagerWrapper.closeSystemWindows( 89 CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT 90 ) 91 } 92 screenshotProxy.dismissKeyguard() 93 var transitionOptions: ActivityOptions? = null 94 if (transitionCoordinator?.decor?.isAttachedToWindow == true) { 95 transitionCoordinator.startExit() 96 transitionOptions = options 97 } 98 99 if (user == myUserHandle()) { 100 withContext(mainDispatcher) { 101 context.startActivity(intent, transitionOptions?.toBundle()) 102 } 103 } else { 104 launchCrossProfileIntent(user, intent, transitionOptions?.toBundle()) 105 } 106 107 if (overrideTransition) { 108 val runner = RemoteAnimationAdapter(SCREENSHOT_REMOTE_RUNNER, 0, 0) 109 try { 110 checkNotNull(WindowManagerGlobal.getWindowManagerService()) 111 .overridePendingAppTransitionRemote(runner, displayTracker.defaultDisplayId) 112 } catch (e: Exception) { 113 Log.e(TAG, "Error overriding screenshot app transition", e) 114 } 115 } 116 } 117 getCrossProfileConnectornull118 private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> = 119 ServiceConnector.Impl<ICrossProfileService>( 120 context, 121 Intent(context, ScreenshotCrossProfileService::class.java), 122 Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE, 123 user.identifier, 124 ICrossProfileService.Stub::asInterface, 125 ) 126 127 private suspend fun launchCrossProfileIntent( 128 user: UserHandle, 129 intent: Intent, 130 bundle: Bundle?, 131 ) { 132 val connector = getCrossProfileConnector(user) 133 val completion = CompletableDeferred<Unit>() 134 connector.post { 135 intent.collectExtraIntentKeys() 136 it.launchIntent(intent, bundle) 137 completion.complete(Unit) 138 } 139 completion.await() 140 } 141 } 142 143 private const val TAG: String = "ActionIntentExecutor" 144 private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)" 145 146 /** 147 * This is effectively a no-op, but we need something non-null to pass in, in order to successfully 148 * override the pending activity entrance animation. 149 */ 150 private val SCREENSHOT_REMOTE_RUNNER: IRemoteAnimationRunner.Stub = 151 object : IRemoteAnimationRunner.Stub() { onAnimationStartnull152 override fun onAnimationStart( 153 @WindowManager.TransitionOldType transit: Int, 154 apps: Array<RemoteAnimationTarget>, 155 wallpapers: Array<RemoteAnimationTarget>, 156 nonApps: Array<RemoteAnimationTarget>, 157 finishedCallback: IRemoteAnimationFinishedCallback, 158 ) { 159 try { 160 finishedCallback.onAnimationFinished() 161 } catch (e: RemoteException) { 162 Log.e(TAG, "Error finishing screenshot remote animation", e) 163 } 164 } 165 onAnimationCancellednull166 override fun onAnimationCancelled() {} 167 } 168