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