1 /*
2  * Copyright (C) 2023 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.clipboardoverlay
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.RemoteException
24 import android.util.Log
25 import android.util.Pair
26 import android.view.IRemoteAnimationFinishedCallback
27 import android.view.IRemoteAnimationRunner
28 import android.view.RemoteAnimationAdapter
29 import android.view.RemoteAnimationTarget
30 import android.view.View
31 import android.view.Window
32 import android.view.WindowManagerGlobal
33 import com.android.internal.app.ChooserActivity
34 import com.android.systemui.settings.DisplayTracker
35 import javax.inject.Inject
36 
37 class ClipboardTransitionExecutor
38 @Inject
39 constructor(val context: Context, val displayTracker: DisplayTracker) {
startSharedTransitionnull40     fun startSharedTransition(window: Window, view: View, intent: Intent, onReady: Runnable) {
41         val transition: Pair<ActivityOptions, ExitTransitionCoordinator> =
42             ActivityOptions.startSharedElementAnimation(
43                 window,
44                 object : ExitTransitionCoordinator.ExitTransitionCallbacks {
45                     override fun isReturnTransitionAllowed(): Boolean {
46                         return false
47                     }
48 
49                     override fun hideSharedElements() {
50                         onReady.run()
51                     }
52 
53                     override fun onFinish() {}
54                 },
55                 null,
56                 Pair.create(view, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)
57             )
58         transition.second.startExit()
59         context.startActivity(intent, transition.first.toBundle())
60         val runner = RemoteAnimationAdapter(NULL_ACTIVITY_TRANSITION, 0, 0)
61         try {
62             checkNotNull(WindowManagerGlobal.getWindowManagerService())
63                 .overridePendingAppTransitionRemote(runner, displayTracker.defaultDisplayId)
64         } catch (e: Exception) {
65             Log.e(TAG, "Error overriding clipboard app transition", e)
66         }
67     }
68 
69     private val TAG: String = "ClipboardTransitionExec"
70 
71     /**
72      * This is effectively a no-op, but we need something non-null to pass in, in order to
73      * successfully override the pending activity entrance animation.
74      */
75     private val NULL_ACTIVITY_TRANSITION: IRemoteAnimationRunner.Stub =
76         object : IRemoteAnimationRunner.Stub() {
onAnimationStartnull77             override fun onAnimationStart(
78                 transit: Int,
79                 apps: Array<RemoteAnimationTarget>,
80                 wallpapers: Array<RemoteAnimationTarget>,
81                 nonApps: Array<RemoteAnimationTarget>,
82                 finishedCallback: IRemoteAnimationFinishedCallback
83             ) {
84                 try {
85                     finishedCallback.onAnimationFinished()
86                 } catch (e: RemoteException) {
87                     Log.e(TAG, "Error finishing screenshot remote animation", e)
88                 }
89             }
90 
onAnimationCancellednull91             override fun onAnimationCancelled() {}
92         }
93 }
94