1 /* 2 * Copyright (C) 2024 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.BroadcastOptions 21 import android.app.ExitTransitionCoordinator 22 import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks 23 import android.app.PendingIntent 24 import android.content.Intent 25 import android.os.UserHandle 26 import android.util.Log 27 import android.util.Pair 28 import android.view.Window 29 import com.android.app.tracing.coroutines.launch 30 import com.android.internal.app.ChooserActivity 31 import com.android.systemui.dagger.qualifiers.Application 32 import dagger.assisted.Assisted 33 import dagger.assisted.AssistedFactory 34 import dagger.assisted.AssistedInject 35 import kotlinx.coroutines.CoroutineScope 36 37 class ActionExecutor 38 @AssistedInject 39 constructor( 40 private val intentExecutor: ActionIntentExecutor, 41 @Application private val applicationScope: CoroutineScope, 42 @Assisted val window: Window, 43 @Assisted val viewProxy: ScreenshotViewProxy, 44 @Assisted val finishDismiss: () -> Unit, 45 ) { 46 47 var isPendingSharedTransition = false 48 private set 49 startSharedTransitionnull50 fun startSharedTransition(intent: Intent, user: UserHandle, overrideTransition: Boolean) { 51 isPendingSharedTransition = true 52 viewProxy.fadeForSharedTransition() 53 val windowTransition = createWindowTransition() 54 applicationScope.launch("$TAG#launchIntentAsync") { 55 intentExecutor.launchIntent( 56 intent, 57 user, 58 overrideTransition, 59 windowTransition.first, 60 windowTransition.second 61 ) 62 } 63 } 64 sendPendingIntentnull65 fun sendPendingIntent(pendingIntent: PendingIntent) { 66 try { 67 val options = BroadcastOptions.makeBasic() 68 options.setInteractive(true) 69 options.setPendingIntentBackgroundActivityStartMode( 70 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED 71 ) 72 pendingIntent.send(options.toBundle()) 73 viewProxy.requestDismissal(null) 74 } catch (e: PendingIntent.CanceledException) { 75 Log.e(TAG, "Intent cancelled", e) 76 } 77 } 78 79 /** 80 * Supplies the necessary bits for the shared element transition to share sheet. Note that once 81 * called, the action intent to share must be sent immediately after. 82 */ createWindowTransitionnull83 private fun createWindowTransition(): Pair<ActivityOptions, ExitTransitionCoordinator> { 84 val callbacks: ExitTransitionCallbacks = 85 object : ExitTransitionCallbacks { 86 override fun isReturnTransitionAllowed(): Boolean { 87 return false 88 } 89 90 override fun hideSharedElements() { 91 isPendingSharedTransition = false 92 finishDismiss.invoke() 93 } 94 95 override fun onFinish() {} 96 } 97 return ActivityOptions.startSharedElementAnimation( 98 window, 99 callbacks, 100 null, 101 Pair.create( 102 viewProxy.screenshotPreview, 103 ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME 104 ) 105 ) 106 } 107 108 @AssistedFactory 109 interface Factory { createnull110 fun create( 111 window: Window, 112 viewProxy: ScreenshotViewProxy, 113 finishDismiss: (() -> Unit) 114 ): ActionExecutor 115 } 116 117 companion object { 118 private const val TAG = "ActionExecutor" 119 } 120 } 121