1 /* 2 * Copyright (C) 2019 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 package com.android.quickstep; 17 18 import static com.android.launcher3.Utilities.postAsyncCallback; 19 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; 20 import static com.android.quickstep.views.IconRecentsView.REMOTE_APP_TO_OVERVIEW_DURATION; 21 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; 22 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; 23 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; 24 25 import android.animation.AnimatorSet; 26 import android.animation.ValueAnimator; 27 import android.app.ActivityOptions; 28 import android.os.Handler; 29 import android.util.Log; 30 31 import com.android.launcher3.BaseDraggingActivity; 32 import com.android.launcher3.LauncherAnimationRunner; 33 import com.android.quickstep.util.RemoteAnimationProvider; 34 import com.android.quickstep.util.RemoteAnimationTargetSet; 35 import com.android.quickstep.views.IconRecentsView; 36 import com.android.systemui.shared.system.ActivityOptionsCompat; 37 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; 38 import com.android.systemui.shared.system.RemoteAnimationTargetCompat; 39 40 /** 41 * Provider for the atomic remote window animation from the app to the overview. 42 * 43 * @param <T> activity that contains the overview 44 */ 45 final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> implements 46 RemoteAnimationProvider { 47 private static final String TAG = "AppToOverviewAnimationProvider"; 48 49 private final ActivityControlHelper<T> mHelper; 50 private final int mTargetTaskId; 51 private IconRecentsView mRecentsView; 52 private AppToOverviewAnimationListener mAnimationReadyListener; 53 AppToOverviewAnimationProvider(ActivityControlHelper<T> helper, int targetTaskId)54 AppToOverviewAnimationProvider(ActivityControlHelper<T> helper, int targetTaskId) { 55 mHelper = helper; 56 mTargetTaskId = targetTaskId; 57 } 58 59 /** 60 * Set listener to various points in the animation preparing to animate. 61 * 62 * @param listener listener 63 */ setAnimationListener(AppToOverviewAnimationListener listener)64 void setAnimationListener(AppToOverviewAnimationListener listener) { 65 mAnimationReadyListener = listener; 66 } 67 68 /** 69 * Callback for when the activity is ready/initialized. 70 * 71 * @param activity the activity that is ready 72 * @param wasVisible true if it was visible before 73 */ onActivityReady(T activity, Boolean wasVisible)74 boolean onActivityReady(T activity, Boolean wasVisible) { 75 if (mAnimationReadyListener != null) { 76 mAnimationReadyListener.onActivityReady(activity); 77 } 78 ActivityControlHelper.AnimationFactory factory = 79 mHelper.prepareRecentsUI(activity, wasVisible, 80 false /* animate activity */, (controller) -> { 81 controller.dispatchOnStart(); 82 ValueAnimator anim = controller.getAnimationPlayer() 83 .setDuration(getRecentsLaunchDuration()); 84 anim.setInterpolator(FAST_OUT_SLOW_IN); 85 anim.start(); 86 }); 87 factory.onRemoteAnimationReceived(null); 88 factory.createActivityController(getRecentsLaunchDuration()); 89 mRecentsView = activity.getOverviewPanel(); 90 return false; 91 } 92 93 /** 94 * Create remote window animation from the currently running app to the overview panel. Should 95 * be called after {@link #onActivityReady}. 96 * 97 * @param targetCompats the target apps 98 * @return animation from app to overview 99 */ 100 @Override createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats)101 public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { 102 if (mAnimationReadyListener != null) { 103 mAnimationReadyListener.onWindowAnimationCreated(); 104 } 105 AnimatorSet anim = new AnimatorSet(); 106 if (mRecentsView == null) { 107 if (Log.isLoggable(TAG, Log.WARN)) { 108 Log.w(TAG, "No recents view. Using stub animation."); 109 } 110 anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration())); 111 return anim; 112 } 113 114 RemoteAnimationTargetSet targetSet = 115 new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); 116 mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome()); 117 118 RemoteAnimationTargetCompat recentsTarget = null; 119 RemoteAnimationTargetCompat closingAppTarget = null; 120 121 for (RemoteAnimationTargetCompat target : targetCompats) { 122 if (target.mode == MODE_OPENING) { 123 recentsTarget = target; 124 } else if (target.mode == MODE_CLOSING && target.taskId == mTargetTaskId) { 125 closingAppTarget = target; 126 } 127 } 128 129 if (closingAppTarget == null) { 130 if (Log.isLoggable(TAG, Log.WARN)) { 131 Log.w(TAG, "No closing app target. Using stub animation."); 132 } 133 anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration())); 134 return anim; 135 } 136 if (recentsTarget == null) { 137 if (Log.isLoggable(TAG, Log.WARN)) { 138 Log.w(TAG, "No recents target. Using stub animation."); 139 } 140 anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration())); 141 return anim; 142 } 143 144 if (closingAppTarget.activityType == ACTIVITY_TYPE_HOME) { 145 mRecentsView.playRemoteHomeToRecentsAnimation(anim, closingAppTarget, recentsTarget); 146 } else { 147 mRecentsView.playRemoteAppToRecentsAnimation(anim, closingAppTarget, recentsTarget); 148 } 149 150 return anim; 151 } 152 153 @Override toActivityOptions(Handler handler, long duration)154 public ActivityOptions toActivityOptions(Handler handler, long duration) { 155 LauncherAnimationRunner runner = new LauncherAnimationRunner(handler, 156 false /* startAtFrontOfQueue */) { 157 158 @Override 159 public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, 160 AnimationResult result) { 161 IconRecentsView recentsView = mRecentsView; 162 if (!recentsView.isReadyForRemoteAnim()) { 163 recentsView.setOnReadyForRemoteAnimCallback(() -> postAsyncCallback(handler, 164 () -> onCreateAnimation(targetCompats, result)) 165 ); 166 return; 167 } 168 result.setAnimation(createWindowAnimation(targetCompats)); 169 } 170 }; 171 return ActivityOptionsCompat.makeRemoteAnimation( 172 new RemoteAnimationAdapterCompat(runner, duration, 173 0 /* statusBarTransitionDelay */)); 174 } 175 176 /** 177 * Get duration of animation from app to overview. 178 * 179 * @return duration of animation 180 */ getRecentsLaunchDuration()181 long getRecentsLaunchDuration() { 182 return REMOTE_APP_TO_OVERVIEW_DURATION; 183 } 184 185 /** 186 * Listener for various points in the app to overview animation preparing to animate. 187 */ 188 interface AppToOverviewAnimationListener { 189 /** 190 * Logic for when activity we're animating to is ready 191 * 192 * @param activity activity to animate to 193 */ onActivityReady(BaseDraggingActivity activity)194 void onActivityReady(BaseDraggingActivity activity); 195 196 /** 197 * Logic for when we've created the app to recents animation. 198 */ onWindowAnimationCreated()199 void onWindowAnimationCreated(); 200 } 201 } 202