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