Loading quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +146 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsView; import com.android.quickstep.TaskView; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; Loading @@ -70,6 +74,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION = "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"; private static final int RECENTS_LAUNCH_DURATION = 336; private static final int LAUNCHER_RESUME_START_DELAY = 150; private static final int CLOSING_TRANSITION_DURATION_MS = 350; Loading Loading @@ -139,8 +144,18 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // Post at front of queue ignoring sync barriers to make sure it gets // processed before the next frame. postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { LauncherTransitionAnimator animator = new LauncherTransitionAnimator( getLauncherAnimators(v), getWindowAnimators(v, targets)); final boolean removeTrackingView; LauncherTransitionAnimator animator = composeRecentsLaunchAnimator(v, targets); if (animator != null) { // We are animating the task view directly, do not remove it after removeTrackingView = false; } else { animator = composeAppLaunchAnimator(v, targets); // A new floating view is created for the animation, remove it after removeTrackingView = true; } setCurrentAnimator(animator); mAnimator = animator.getAnimatorSet(); mAnimator.addListener(new AnimatorListenerAdapter() { Loading @@ -148,7 +163,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag public void onAnimationEnd(Animator animation) { // Reset launcher to normal state v.setVisibility(View.VISIBLE); ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView); if (removeTrackingView) { ((ViewGroup) mDragLayer.getParent()).removeView( mFloatingView); } mDragLayer.setAlpha(1f); mDragLayer.setTranslationY(0f); Loading Loading @@ -178,6 +196,131 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } /** * Composes the animations for a launch from the recents list if possible. */ private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v, RemoteAnimationTargetCompat[] targets) { // Ensure recents is actually visible if (!mLauncher.isInState(LauncherState.OVERVIEW)) { return null; } // Resolve the opening task id int openingTaskId = -1; for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.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 RecentsView recentsView = mLauncher.getOverviewPanel(); TaskView taskView = recentsView.getTaskView(openingTaskId); if (taskView == null || !recentsView.isTaskViewVisible(taskView)) { return null; } // Found a visible recents task that matches the opening app, lets launch the app from there return new LauncherTransitionAnimator(null, getRecentsWindowAnimator(taskView, targets)); } /** * @return Animator that controls the window of the opening targets for the recents launch * animation. */ private ValueAnimator getRecentsWindowAnimator(TaskView v, RemoteAnimationTargetCompat[] targets) { Rect taskViewBounds = new Rect(); mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); // TODO: Use the actual target insets instead of the current thumbnail insets in case the // device state has changed RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator( new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), v.getThumbnail().getInsets(), taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0)); Rect crop = new Rect(); Matrix matrix = new Matrix(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); appAnimator.setDuration(RECENTS_LAUNCH_DURATION); appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { boolean isFirstFrame = true; @Override public void onAnimationUpdate(ValueAnimator animation) { final Surface surface = getSurface(v); final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1; if (frameNumber == -1) { // Booo, not cool! Our surface got destroyed, so no reason to animate anything. Log.w(TAG, "Failed to animate, surface got destroyed."); return; } final float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); v.setScaleX(tw.taskScale); v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY); // Defer fading out the view until after the app window gets faded in v.setAlpha(getValue(1f, 0f, 75, 75, appAnimator.getDuration() * percent, Interpolators.LINEAR)); matrix.setScale(tw.winScale, tw.winScale); matrix.postTranslate(tw.winX, tw.winY); crop.set(tw.winCrop); // Fade in the app window. float alphaDelay = 0; float alphaDuration = 75; float alpha = getValue(0f, 1f, alphaDelay, alphaDuration, appAnimator.getDuration() * percent, Interpolators.LINEAR); TransactionCompat t = new TransactionCompat(); for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { t.setAlpha(target.leash, alpha); // TODO: This isn't correct at the beginning of the animation, but better // than nothing. matrix.postTranslate(target.position.x, target.position.y); t.setMatrix(target.leash, matrix); t.setWindowCrop(target.leash, crop); t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface)); } if (isFirstFrame) { t.show(target.leash); } } t.apply(); matrix.reset(); isFirstFrame = false; } }); return appAnimator; } /** * Composes the animations for a launch from an app icon. */ private LauncherTransitionAnimator composeAppLaunchAnimator(View v, RemoteAnimationTargetCompat[] targets) { return new LauncherTransitionAnimator(getLauncherAnimators(v), getWindowAnimators(v, targets)); } /** * @return Animators that control the movements of the Launcher and icon of the opening target. */ Loading quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java +9 −3 Original line number Diff line number Diff line Loading @@ -32,11 +32,15 @@ public class LauncherTransitionAnimator { private Animator mWindowAnimator; LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) { if (launcherAnimator != null) { mLauncherAnimator = launcherAnimator; } mWindowAnimator = windowAnimator; mAnimatorSet = new AnimatorSet(); if (launcherAnimator != null) { mAnimatorSet.play(launcherAnimator); } mAnimatorSet.play(windowAnimator); } Loading @@ -53,6 +57,8 @@ public class LauncherTransitionAnimator { } public void finishLauncherAnimation() { if (mLauncherAnimator != null) { mLauncherAnimator.end(); } } } quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.quickstep; import android.graphics.Rect; import com.android.launcher3.Utilities; /** * Helper class to interpolate the animation between a task view representation and an actual * window. */ public class RecentsAnimationInterpolator { public static class TaskWindowBounds { public float taskScale = 1f; public float taskX = 0f; public float taskY = 0f; public float winScale = 1f; public float winX = 0f; public float winY = 0f; public Rect winCrop = new Rect(); @Override public String toString() { return "taskScale=" + taskScale + " taskX=" + taskX + " taskY=" + taskY + " winScale=" + winScale + " winX=" + winX + " winY=" + winY + " winCrop=" + winCrop; } } private TaskWindowBounds mTmpTaskWindowBounds = new TaskWindowBounds(); private Rect mTmpInsets = new Rect(); private Rect mWindow; private Rect mInsetWindow; private Rect mInsets; private Rect mTask; private Rect mTaskInsets; private Rect mThumbnail; private float mTaskScale; private Rect mScaledTask; private Rect mTargetTask; private Rect mSrcWindow; public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets) { mWindow = window; mInsets = insets; mTask = task; mTaskInsets = taskInsets; mInsetWindow = new Rect(window); Utilities.insetRect(mInsetWindow, insets); mThumbnail = new Rect(task); Utilities.insetRect(mThumbnail, taskInsets); mTaskScale = (float) mInsetWindow.width() / mThumbnail.width(); mScaledTask = new Rect(task); Utilities.scaleRectAboutCenter(mScaledTask, mTaskScale); Rect finalScaledTaskInsets = new Rect(taskInsets); Utilities.scaleRect(finalScaledTaskInsets, mTaskScale); mTargetTask = new Rect(mInsetWindow); mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top, window.left + insets.left - finalScaledTaskInsets.left); float initialWinScale = 1f / mTaskScale; Rect scaledWindow = new Rect(mInsetWindow); Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale); Rect scaledInsets = new Rect(insets); Utilities.scaleRect(scaledInsets, initialWinScale); mSrcWindow = new Rect(scaledWindow); mSrcWindow.offsetTo(mThumbnail.left - scaledInsets.left, mThumbnail.top - scaledInsets.top); } public TaskWindowBounds interpolate(float t) { mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t, 1, (float) mInsetWindow.width() / mThumbnail.width()); mTmpTaskWindowBounds.taskX = Utilities.mapRange(t, 0, mTargetTask.left - mScaledTask.left); mTmpTaskWindowBounds.taskY = Utilities.mapRange(t, 0, mTargetTask.top - mScaledTask.top); mTmpTaskWindowBounds.winScale = mTmpTaskWindowBounds.taskScale / mTaskScale; mTmpTaskWindowBounds.winX = Utilities.mapRange(t, mSrcWindow.left, 0); mTmpTaskWindowBounds.winY = Utilities.mapRange(t, mSrcWindow.top, 0); mTmpInsets.set(mInsets); Utilities.scaleRect(mTmpInsets, (1f - t)); mTmpTaskWindowBounds.winCrop.set(mWindow); Utilities.insetRect(mTmpTaskWindowBounds.winCrop, mTmpInsets); return mTmpTaskWindowBounds; } } quickstep/src/com/android/quickstep/RecentsView.java +21 −1 Original line number Diff line number Diff line Loading @@ -215,6 +215,21 @@ public class RecentsView extends PagedView implements Insettable { return mFirstTaskIndex; } public boolean isTaskViewVisible(TaskView tv) { // For now, just check if it's the active task return indexOfChild(tv) == getNextPage(); } public TaskView getTaskView(int taskId) { for (int i = getFirstTaskIndex(); i < getChildCount(); i++) { TaskView tv = (TaskView) getChildAt(i); if (tv.getTask().key.id == taskId) { return tv; } } return null; } public void setStateController(RecentsViewStateController stateController) { mStateController = stateController; } Loading Loading @@ -254,11 +269,16 @@ public class RecentsView extends PagedView implements Insettable { } setLayoutTransition(mLayoutTransition); // Rebind all task views // Rebind and reset all task views for (int i = tasks.size() - 1; i >= 0; i--) { final Task task = tasks.get(i); final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex); taskView.bind(task); taskView.setScaleX(1f); taskView.setScaleY(1f); taskView.setTranslationX(0f); taskView.setTranslationY(0f); taskView.setAlpha(1f); loader.loadTaskData(task); } } Loading quickstep/src/com/android/quickstep/TaskThumbnailView.java +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; Loading Loading @@ -108,6 +109,13 @@ public class TaskThumbnailView extends View { updateThumbnailPaintFilter(); } public Rect getInsets() { if (mThumbnailData != null) { return mThumbnailData.insets; } return new Rect(); } @Override protected void onDraw(Canvas canvas) { canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), Loading Loading
quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +146 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsView; import com.android.quickstep.TaskView; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; Loading @@ -70,6 +74,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION = "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"; private static final int RECENTS_LAUNCH_DURATION = 336; private static final int LAUNCHER_RESUME_START_DELAY = 150; private static final int CLOSING_TRANSITION_DURATION_MS = 350; Loading Loading @@ -139,8 +144,18 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // Post at front of queue ignoring sync barriers to make sure it gets // processed before the next frame. postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { LauncherTransitionAnimator animator = new LauncherTransitionAnimator( getLauncherAnimators(v), getWindowAnimators(v, targets)); final boolean removeTrackingView; LauncherTransitionAnimator animator = composeRecentsLaunchAnimator(v, targets); if (animator != null) { // We are animating the task view directly, do not remove it after removeTrackingView = false; } else { animator = composeAppLaunchAnimator(v, targets); // A new floating view is created for the animation, remove it after removeTrackingView = true; } setCurrentAnimator(animator); mAnimator = animator.getAnimatorSet(); mAnimator.addListener(new AnimatorListenerAdapter() { Loading @@ -148,7 +163,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag public void onAnimationEnd(Animator animation) { // Reset launcher to normal state v.setVisibility(View.VISIBLE); ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView); if (removeTrackingView) { ((ViewGroup) mDragLayer.getParent()).removeView( mFloatingView); } mDragLayer.setAlpha(1f); mDragLayer.setTranslationY(0f); Loading Loading @@ -178,6 +196,131 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } /** * Composes the animations for a launch from the recents list if possible. */ private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v, RemoteAnimationTargetCompat[] targets) { // Ensure recents is actually visible if (!mLauncher.isInState(LauncherState.OVERVIEW)) { return null; } // Resolve the opening task id int openingTaskId = -1; for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.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 RecentsView recentsView = mLauncher.getOverviewPanel(); TaskView taskView = recentsView.getTaskView(openingTaskId); if (taskView == null || !recentsView.isTaskViewVisible(taskView)) { return null; } // Found a visible recents task that matches the opening app, lets launch the app from there return new LauncherTransitionAnimator(null, getRecentsWindowAnimator(taskView, targets)); } /** * @return Animator that controls the window of the opening targets for the recents launch * animation. */ private ValueAnimator getRecentsWindowAnimator(TaskView v, RemoteAnimationTargetCompat[] targets) { Rect taskViewBounds = new Rect(); mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); // TODO: Use the actual target insets instead of the current thumbnail insets in case the // device state has changed RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator( new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), v.getThumbnail().getInsets(), taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0)); Rect crop = new Rect(); Matrix matrix = new Matrix(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); appAnimator.setDuration(RECENTS_LAUNCH_DURATION); appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { boolean isFirstFrame = true; @Override public void onAnimationUpdate(ValueAnimator animation) { final Surface surface = getSurface(v); final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1; if (frameNumber == -1) { // Booo, not cool! Our surface got destroyed, so no reason to animate anything. Log.w(TAG, "Failed to animate, surface got destroyed."); return; } final float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); v.setScaleX(tw.taskScale); v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY); // Defer fading out the view until after the app window gets faded in v.setAlpha(getValue(1f, 0f, 75, 75, appAnimator.getDuration() * percent, Interpolators.LINEAR)); matrix.setScale(tw.winScale, tw.winScale); matrix.postTranslate(tw.winX, tw.winY); crop.set(tw.winCrop); // Fade in the app window. float alphaDelay = 0; float alphaDuration = 75; float alpha = getValue(0f, 1f, alphaDelay, alphaDuration, appAnimator.getDuration() * percent, Interpolators.LINEAR); TransactionCompat t = new TransactionCompat(); for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { t.setAlpha(target.leash, alpha); // TODO: This isn't correct at the beginning of the animation, but better // than nothing. matrix.postTranslate(target.position.x, target.position.y); t.setMatrix(target.leash, matrix); t.setWindowCrop(target.leash, crop); t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface)); } if (isFirstFrame) { t.show(target.leash); } } t.apply(); matrix.reset(); isFirstFrame = false; } }); return appAnimator; } /** * Composes the animations for a launch from an app icon. */ private LauncherTransitionAnimator composeAppLaunchAnimator(View v, RemoteAnimationTargetCompat[] targets) { return new LauncherTransitionAnimator(getLauncherAnimators(v), getWindowAnimators(v, targets)); } /** * @return Animators that control the movements of the Launcher and icon of the opening target. */ Loading
quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java +9 −3 Original line number Diff line number Diff line Loading @@ -32,11 +32,15 @@ public class LauncherTransitionAnimator { private Animator mWindowAnimator; LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) { if (launcherAnimator != null) { mLauncherAnimator = launcherAnimator; } mWindowAnimator = windowAnimator; mAnimatorSet = new AnimatorSet(); if (launcherAnimator != null) { mAnimatorSet.play(launcherAnimator); } mAnimatorSet.play(windowAnimator); } Loading @@ -53,6 +57,8 @@ public class LauncherTransitionAnimator { } public void finishLauncherAnimation() { if (mLauncherAnimator != null) { mLauncherAnimator.end(); } } }
quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.quickstep; import android.graphics.Rect; import com.android.launcher3.Utilities; /** * Helper class to interpolate the animation between a task view representation and an actual * window. */ public class RecentsAnimationInterpolator { public static class TaskWindowBounds { public float taskScale = 1f; public float taskX = 0f; public float taskY = 0f; public float winScale = 1f; public float winX = 0f; public float winY = 0f; public Rect winCrop = new Rect(); @Override public String toString() { return "taskScale=" + taskScale + " taskX=" + taskX + " taskY=" + taskY + " winScale=" + winScale + " winX=" + winX + " winY=" + winY + " winCrop=" + winCrop; } } private TaskWindowBounds mTmpTaskWindowBounds = new TaskWindowBounds(); private Rect mTmpInsets = new Rect(); private Rect mWindow; private Rect mInsetWindow; private Rect mInsets; private Rect mTask; private Rect mTaskInsets; private Rect mThumbnail; private float mTaskScale; private Rect mScaledTask; private Rect mTargetTask; private Rect mSrcWindow; public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets) { mWindow = window; mInsets = insets; mTask = task; mTaskInsets = taskInsets; mInsetWindow = new Rect(window); Utilities.insetRect(mInsetWindow, insets); mThumbnail = new Rect(task); Utilities.insetRect(mThumbnail, taskInsets); mTaskScale = (float) mInsetWindow.width() / mThumbnail.width(); mScaledTask = new Rect(task); Utilities.scaleRectAboutCenter(mScaledTask, mTaskScale); Rect finalScaledTaskInsets = new Rect(taskInsets); Utilities.scaleRect(finalScaledTaskInsets, mTaskScale); mTargetTask = new Rect(mInsetWindow); mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top, window.left + insets.left - finalScaledTaskInsets.left); float initialWinScale = 1f / mTaskScale; Rect scaledWindow = new Rect(mInsetWindow); Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale); Rect scaledInsets = new Rect(insets); Utilities.scaleRect(scaledInsets, initialWinScale); mSrcWindow = new Rect(scaledWindow); mSrcWindow.offsetTo(mThumbnail.left - scaledInsets.left, mThumbnail.top - scaledInsets.top); } public TaskWindowBounds interpolate(float t) { mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t, 1, (float) mInsetWindow.width() / mThumbnail.width()); mTmpTaskWindowBounds.taskX = Utilities.mapRange(t, 0, mTargetTask.left - mScaledTask.left); mTmpTaskWindowBounds.taskY = Utilities.mapRange(t, 0, mTargetTask.top - mScaledTask.top); mTmpTaskWindowBounds.winScale = mTmpTaskWindowBounds.taskScale / mTaskScale; mTmpTaskWindowBounds.winX = Utilities.mapRange(t, mSrcWindow.left, 0); mTmpTaskWindowBounds.winY = Utilities.mapRange(t, mSrcWindow.top, 0); mTmpInsets.set(mInsets); Utilities.scaleRect(mTmpInsets, (1f - t)); mTmpTaskWindowBounds.winCrop.set(mWindow); Utilities.insetRect(mTmpTaskWindowBounds.winCrop, mTmpInsets); return mTmpTaskWindowBounds; } }
quickstep/src/com/android/quickstep/RecentsView.java +21 −1 Original line number Diff line number Diff line Loading @@ -215,6 +215,21 @@ public class RecentsView extends PagedView implements Insettable { return mFirstTaskIndex; } public boolean isTaskViewVisible(TaskView tv) { // For now, just check if it's the active task return indexOfChild(tv) == getNextPage(); } public TaskView getTaskView(int taskId) { for (int i = getFirstTaskIndex(); i < getChildCount(); i++) { TaskView tv = (TaskView) getChildAt(i); if (tv.getTask().key.id == taskId) { return tv; } } return null; } public void setStateController(RecentsViewStateController stateController) { mStateController = stateController; } Loading Loading @@ -254,11 +269,16 @@ public class RecentsView extends PagedView implements Insettable { } setLayoutTransition(mLayoutTransition); // Rebind all task views // Rebind and reset all task views for (int i = tasks.size() - 1; i >= 0; i--) { final Task task = tasks.get(i); final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex); taskView.bind(task); taskView.setScaleX(1f); taskView.setScaleY(1f); taskView.setTranslationX(0f); taskView.setTranslationY(0f); taskView.setAlpha(1f); loader.loadTaskData(task); } } Loading
quickstep/src/com/android/quickstep/TaskThumbnailView.java +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; Loading Loading @@ -108,6 +109,13 @@ public class TaskThumbnailView extends View { updateThumbnailPaintFilter(); } public Rect getInsets() { if (mThumbnailData != null) { return mThumbnailData.insets; } return new Rect(); } @Override protected void onDraw(Canvas canvas) { canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), Loading