diff options
Diffstat (limited to 'quickstep/src/com/android/quickstep/TaskUtils.java')
-rw-r--r-- | quickstep/src/com/android/quickstep/TaskUtils.java | 172 |
1 files changed, 171 insertions, 1 deletions
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java index 5bf1d07db..2b0c98f93 100644 --- a/quickstep/src/com/android/quickstep/TaskUtils.java +++ b/quickstep/src/com/android/quickstep/TaskUtils.java @@ -16,25 +16,49 @@ package com.android.quickstep; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; +import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; +import static com.android.systemui.shared.recents.utilities.Utilities.getSurface; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; + +import android.animation.ValueAnimator; +import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.RectF; import android.os.UserHandle; import android.util.Log; +import android.view.Surface; +import android.view.View; +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.ComponentKey; +import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.MultiValueUpdateListener; +import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; + +import java.util.List; /** * Contains helpful methods for retrieving data from {@link Task}s. - * TODO: remove this once we switch to getting the icon and label from IconCache. */ public class TaskUtils { private static final String TAG = "TaskUtils"; + /** + * TODO: remove this once we switch to getting the icon and label from IconCache. + */ public static CharSequence getTitle(Context context, Task task) { LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context); UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(context); @@ -53,4 +77,150 @@ public class TaskUtils { public static ComponentKey getComponentKeyForTask(Task.TaskKey taskKey) { return new ComponentKey(taskKey.getComponent(), UserHandle.of(taskKey.userId)); } + + + /** + * Try to find a TaskView that corresponds with the component of the launched view. + * + * If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation. + * Otherwise, we will assume we are using a normal app transition, but it's possible that the + * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView. + */ + public static TaskView findTaskViewToLaunch( + BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) { + if (v instanceof TaskView) { + return (TaskView) v; + } + RecentsView recentsView = activity.getOverviewPanel(); + + // It's possible that the launched view can still be resolved to a visible task view, check + // the task id of the opening task and see if we can find a match. + if (v.getTag() instanceof ItemInfo) { + ItemInfo itemInfo = (ItemInfo) v.getTag(); + ComponentName componentName = itemInfo.getTargetComponent(); + int userId = itemInfo.user.getIdentifier(); + if (componentName != null) { + for (int i = 0; i < recentsView.getChildCount(); i++) { + TaskView taskView = recentsView.getPageAt(i); + if (recentsView.isTaskViewVisible(taskView)) { + Task.TaskKey key = taskView.getTask().key; + if (componentName.equals(key.getComponent()) && userId == key.userId) { + return taskView; + } + } + } + } + } + + if (targets == null) { + return null; + } + // Resolve the opening task id + int openingTaskId = -1; + for (RemoteAnimationTargetCompat target : targets) { + if (target.mode == MODE_OPENING) { + openingTaskId = target.taskId; + break; + } + } + + // If there is no opening task id, fall back to the normal app icon launch animation + if (openingTaskId == -1) { + return null; + } + + // If the opening task id is not currently visible in overview, then fall back to normal app + // icon launch animation + TaskView taskView = recentsView.getTaskView(openingTaskId); + if (taskView == null || !recentsView.isTaskViewVisible(taskView)) { + return null; + } + return taskView; + } + + /** + * @return Animator that controls the window of the opening targets for the recents launch + * animation. + */ + public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges, + RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) { + final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); + appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + appAnimator.addUpdateListener(new MultiValueUpdateListener() { + + // Defer fading out the view until after the app window gets faded in + final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR); + final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR); + + final RemoteAnimationTargetSet mTargetSet; + + final RectF mThumbnailRect; + private Surface mSurface; + private long mFrameNumber; + + { + mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING); + inOutHelper.setTaskTransformCallback((t, app) -> { + t.setAlpha(app.leash, mTaskAlpha.value); + + if (!skipViewChanges) { + t.deferTransactionUntil(app.leash, mSurface, mFrameNumber); + } + }); + + inOutHelper.prepareAnimation(true /* isOpening */); + inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), + mTargetSet.apps.length == 0 ? null : mTargetSet.apps[0]); + + mThumbnailRect = new RectF(inOutHelper.getTargetRect()); + mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY()); + Utilities.scaleRectFAboutCenter(mThumbnailRect, 1 / v.getScaleX()); + } + + @Override + public void onUpdate(float percent) { + mSurface = getSurface(v); + mFrameNumber = mSurface != null ? getNextFrameNumber(mSurface) : -1; + if (mFrameNumber == -1) { + // Booo, not cool! Our surface got destroyed, so no reason to animate anything. + Log.w(TAG, "Failed to animate, surface got destroyed."); + return; + } + + RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent); + if (!skipViewChanges) { + float scale = taskBounds.width() / mThumbnailRect.width(); + v.setScaleX(scale); + v.setScaleY(scale); + v.setTranslationX(taskBounds.centerX() - mThumbnailRect.centerX()); + v.setTranslationY(taskBounds.centerY() - mThumbnailRect.centerY()); + v.setAlpha(mViewAlpha.value); + } + } + }); + return appAnimator; + } + + public static boolean taskIsATargetWithMode(RemoteAnimationTargetCompat[] targets, + int taskId, int mode) { + for (RemoteAnimationTargetCompat target : targets) { + if (target.mode == mode && target.taskId == taskId) { + return true; + } + } + return false; + } + + public static boolean checkCurrentOrManagedUserId(int currentUserId, Context context) { + if (currentUserId == UserHandle.myUserId()) { + return true; + } + List<UserHandle> allUsers = UserManagerCompat.getInstance(context).getUserProfiles(); + for (int i = allUsers.size() - 1; i >= 0; i--) { + if (currentUserId == allUsers.get(i).getIdentifier()) { + return true; + } + } + return false; + } } |