Loading quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +0 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.quickstep.fallback; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.support.annotation.AnyThread; import android.util.AttributeSet; import android.view.View; Loading quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +77 −0 Original line number Diff line number Diff line Loading @@ -15,15 +15,23 @@ */ package com.android.quickstep.util; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.views.TaskThumbnailView; import com.android.systemui.shared.recents.utilities.RectFEvaluator; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; /** * Utility class to handle window clip animation Loading Loading @@ -126,4 +134,73 @@ public class ClipAnimationHelper { mTargetRect.offset(offsetX, offsetY); } } public void fromTaskThumbnailView(TaskThumbnailView ttv) { BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext()); BaseDragLayer dl = activity.getDragLayer(); int[] pos = new int[2]; dl.getLocationOnScreen(pos); mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight()); mHomeStackBounds.offset(pos[0], pos[1]); if (activity.isInMultiWindowModeCompat()) { // TODO: Fetch multi-window target bounds from system-ui DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile(); // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to // account for system insets int taskWidth = fullDp.availableWidthPx; int taskHeight = fullDp.availableHeightPx; int halfDividerSize = activity.getResources() .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; Rect insets = new Rect(); WindowManagerWrapper.getInstance().getStableInsets(insets); if (fullDp.isLandscape) { taskWidth = taskWidth / 2 - halfDividerSize; } else { taskHeight = taskHeight / 2 - halfDividerSize; } mSourceStackBounds.set(0, 0, taskWidth, taskHeight); // Align the task to bottom right (probably not true for seascape). mSourceStackBounds.offset(insets.left + fullDp.availableWidthPx - taskWidth, insets.top + fullDp.availableHeightPx - taskHeight); } else { mSourceStackBounds.set(mHomeStackBounds); mSourceInsets.set(activity.getDeviceProfile().getInsets()); } Rect targetRect = new Rect(); dl.getDescendantRectRelativeToSelf(ttv, targetRect); updateTargetRect(targetRect); // Transform the clip relative to the target rect. float scale = mTargetRect.width() / mSourceRect.width(); mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale; mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale; mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale; mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale; } public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) { RectF currentRect; synchronized (mTargetRect) { currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); } canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left, mSourceStackBounds.top - mHomeStackBounds.top); mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL); canvas.concat(mTmpMatrix); canvas.translate(mTargetRect.left, mTargetRect.top); float insetProgress = (1 - progress); ttv.drawOnCanvas(canvas, -mSourceWindowClipInsets.left * insetProgress, -mSourceWindowClipInsets.top * insetProgress, ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress, ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress, ttv.getCornerRadius() * progress); } } quickstep/src/com/android/quickstep/util/TaskViewDrawable.java 0 → 100644 +100 −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.util; import android.animation.TimeInterpolator; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.util.FloatProperty; import android.widget.ImageView; import com.android.launcher3.Utilities; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; public class TaskViewDrawable extends Drawable { public static FloatProperty<TaskViewDrawable> PROGRESS = new FloatProperty<TaskViewDrawable>("progress") { @Override public void setValue(TaskViewDrawable taskViewDrawable, float v) { taskViewDrawable.setProgress(v); } @Override public Float get(TaskViewDrawable taskViewDrawable) { return taskViewDrawable.mProgress; } }; private static final TimeInterpolator ICON_SIZE_INTERPOLATOR = (t) -> (Math.max(t, 0.3f) - 0.3f) / 0.7f; private final RecentsView mParent; private final ImageView mIconView; private final int[] mIconPos; private final TaskThumbnailView mThumbnailView; private final ClipAnimationHelper mClipAnimationHelper; private float mProgress = 1; public TaskViewDrawable(TaskView tv, RecentsView parent) { mParent = parent; mIconView = tv.getIconView(); mIconPos = new int[2]; Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true); mThumbnailView = tv.getThumbnail(); mClipAnimationHelper = new ClipAnimationHelper(); mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView); } public void setProgress(float progress) { mProgress = progress; mParent.invalidate(); } @Override public void draw(Canvas canvas) { canvas.save(); canvas.translate(mParent.getScrollX(), mParent.getScrollY()); mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress); canvas.restore(); canvas.save(); canvas.translate(mIconPos[0], mIconPos[1]); float scale = ICON_SIZE_INTERPOLATOR.getInterpolation(mProgress); canvas.scale(scale, scale, mIconView.getWidth() / 2, mIconView.getHeight() / 2); mIconView.draw(canvas); canvas.restore(); } @Override public void setAlpha(int i) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } } quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +8 −0 Original line number Diff line number Diff line Loading @@ -130,4 +130,12 @@ public class LauncherRecentsView extends RecentsView<Launcher> { protected void getTaskSize(DeviceProfile dp, Rect outRect) { LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); } @Override protected void onTaskLaunched(boolean success) { if (success) { mActivity.getStateManager().goToState(NORMAL, false /* animate */); } super.onTaskLaunched(success); } } quickstep/src/com/android/quickstep/views/RecentsView.java +23 −15 Original line number Diff line number Diff line Loading @@ -66,10 +66,10 @@ import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; import com.android.quickstep.OverviewCallbacks; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsModel; import com.android.quickstep.TaskUtils; import com.android.quickstep.util.TaskViewDrawable; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoader; import com.android.systemui.shared.recents.model.Task; Loading @@ -79,6 +79,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; import java.util.function.Consumer; /** * A list of recent tasks. Loading Loading @@ -522,7 +523,6 @@ public abstract class RecentsView<T extends BaseActivity> mHasVisibleTaskData.clear(); } protected abstract void onAllTasksRemoved(); public void reset() { Loading Loading @@ -1060,23 +1060,27 @@ public abstract class RecentsView<T extends BaseActivity> return new PendingAnimation(anim); } final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator(); ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1); targetViewAnim.addUpdateListener((animation) -> { float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); tv.setScaleX(tw.taskScale); tv.setScaleY(tw.taskScale); tv.setTranslationX(tw.taskX); tv.setTranslationY(tw.taskY); }); anim.play(targetViewAnim); tv.setVisibility(INVISIBLE); TaskViewDrawable drawable = new TaskViewDrawable(tv, this); getOverlay().add(drawable); ObjectAnimator drawableAnim = ObjectAnimator.ofFloat(drawable, TaskViewDrawable.PROGRESS, 1, 0); drawableAnim.setInterpolator(LINEAR); anim.play(drawableAnim); anim.setDuration(duration); Consumer<Boolean> onTaskLaunchFinish = (r) -> { onTaskLaunched(r); tv.setVisibility(VISIBLE); getOverlay().remove(drawable); }; mPendingAnimation = new PendingAnimation(anim); mPendingAnimation.addEndListener((onEndListener) -> { if (onEndListener.isSuccess) { tv.launchTask(false); tv.launchTask(false, onTaskLaunchFinish, getHandler()); Task task = tv.getTask(); if (task != null) { mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( Loading @@ -1084,13 +1088,17 @@ public abstract class RecentsView<T extends BaseActivity> TaskUtils.getComponentKeyForTask(task.key)); } } else { resetTaskVisuals(); onTaskLaunchFinish.accept(false); } mPendingAnimation = null; }); return mPendingAnimation; } protected void onTaskLaunched(boolean success) { resetTaskVisuals(); } @Override protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); Loading Loading
quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +0 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.quickstep.fallback; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.support.annotation.AnyThread; import android.util.AttributeSet; import android.view.View; Loading
quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java +77 −0 Original line number Diff line number Diff line Loading @@ -15,15 +15,23 @@ */ package com.android.quickstep.util; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.views.TaskThumbnailView; import com.android.systemui.shared.recents.utilities.RectFEvaluator; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; /** * Utility class to handle window clip animation Loading Loading @@ -126,4 +134,73 @@ public class ClipAnimationHelper { mTargetRect.offset(offsetX, offsetY); } } public void fromTaskThumbnailView(TaskThumbnailView ttv) { BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext()); BaseDragLayer dl = activity.getDragLayer(); int[] pos = new int[2]; dl.getLocationOnScreen(pos); mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight()); mHomeStackBounds.offset(pos[0], pos[1]); if (activity.isInMultiWindowModeCompat()) { // TODO: Fetch multi-window target bounds from system-ui DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile(); // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to // account for system insets int taskWidth = fullDp.availableWidthPx; int taskHeight = fullDp.availableHeightPx; int halfDividerSize = activity.getResources() .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; Rect insets = new Rect(); WindowManagerWrapper.getInstance().getStableInsets(insets); if (fullDp.isLandscape) { taskWidth = taskWidth / 2 - halfDividerSize; } else { taskHeight = taskHeight / 2 - halfDividerSize; } mSourceStackBounds.set(0, 0, taskWidth, taskHeight); // Align the task to bottom right (probably not true for seascape). mSourceStackBounds.offset(insets.left + fullDp.availableWidthPx - taskWidth, insets.top + fullDp.availableHeightPx - taskHeight); } else { mSourceStackBounds.set(mHomeStackBounds); mSourceInsets.set(activity.getDeviceProfile().getInsets()); } Rect targetRect = new Rect(); dl.getDescendantRectRelativeToSelf(ttv, targetRect); updateTargetRect(targetRect); // Transform the clip relative to the target rect. float scale = mTargetRect.width() / mSourceRect.width(); mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale; mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale; mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale; mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale; } public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) { RectF currentRect; synchronized (mTargetRect) { currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect); } canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left, mSourceStackBounds.top - mHomeStackBounds.top); mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL); canvas.concat(mTmpMatrix); canvas.translate(mTargetRect.left, mTargetRect.top); float insetProgress = (1 - progress); ttv.drawOnCanvas(canvas, -mSourceWindowClipInsets.left * insetProgress, -mSourceWindowClipInsets.top * insetProgress, ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress, ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress, ttv.getCornerRadius() * progress); } }
quickstep/src/com/android/quickstep/util/TaskViewDrawable.java 0 → 100644 +100 −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.util; import android.animation.TimeInterpolator; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.util.FloatProperty; import android.widget.ImageView; import com.android.launcher3.Utilities; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; public class TaskViewDrawable extends Drawable { public static FloatProperty<TaskViewDrawable> PROGRESS = new FloatProperty<TaskViewDrawable>("progress") { @Override public void setValue(TaskViewDrawable taskViewDrawable, float v) { taskViewDrawable.setProgress(v); } @Override public Float get(TaskViewDrawable taskViewDrawable) { return taskViewDrawable.mProgress; } }; private static final TimeInterpolator ICON_SIZE_INTERPOLATOR = (t) -> (Math.max(t, 0.3f) - 0.3f) / 0.7f; private final RecentsView mParent; private final ImageView mIconView; private final int[] mIconPos; private final TaskThumbnailView mThumbnailView; private final ClipAnimationHelper mClipAnimationHelper; private float mProgress = 1; public TaskViewDrawable(TaskView tv, RecentsView parent) { mParent = parent; mIconView = tv.getIconView(); mIconPos = new int[2]; Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true); mThumbnailView = tv.getThumbnail(); mClipAnimationHelper = new ClipAnimationHelper(); mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView); } public void setProgress(float progress) { mProgress = progress; mParent.invalidate(); } @Override public void draw(Canvas canvas) { canvas.save(); canvas.translate(mParent.getScrollX(), mParent.getScrollY()); mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress); canvas.restore(); canvas.save(); canvas.translate(mIconPos[0], mIconPos[1]); float scale = ICON_SIZE_INTERPOLATOR.getInterpolation(mProgress); canvas.scale(scale, scale, mIconView.getWidth() / 2, mIconView.getHeight() / 2); mIconView.draw(canvas); canvas.restore(); } @Override public void setAlpha(int i) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } }
quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +8 −0 Original line number Diff line number Diff line Loading @@ -130,4 +130,12 @@ public class LauncherRecentsView extends RecentsView<Launcher> { protected void getTaskSize(DeviceProfile dp, Rect outRect) { LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); } @Override protected void onTaskLaunched(boolean success) { if (success) { mActivity.getStateManager().goToState(NORMAL, false /* animate */); } super.onTaskLaunched(success); } }
quickstep/src/com/android/quickstep/views/RecentsView.java +23 −15 Original line number Diff line number Diff line Loading @@ -66,10 +66,10 @@ import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; import com.android.quickstep.OverviewCallbacks; import com.android.quickstep.QuickScrubController; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsModel; import com.android.quickstep.TaskUtils; import com.android.quickstep.util.TaskViewDrawable; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoader; import com.android.systemui.shared.recents.model.Task; Loading @@ -79,6 +79,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; import java.util.function.Consumer; /** * A list of recent tasks. Loading Loading @@ -522,7 +523,6 @@ public abstract class RecentsView<T extends BaseActivity> mHasVisibleTaskData.clear(); } protected abstract void onAllTasksRemoved(); public void reset() { Loading Loading @@ -1060,23 +1060,27 @@ public abstract class RecentsView<T extends BaseActivity> return new PendingAnimation(anim); } final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator(); ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1); targetViewAnim.addUpdateListener((animation) -> { float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); tv.setScaleX(tw.taskScale); tv.setScaleY(tw.taskScale); tv.setTranslationX(tw.taskX); tv.setTranslationY(tw.taskY); }); anim.play(targetViewAnim); tv.setVisibility(INVISIBLE); TaskViewDrawable drawable = new TaskViewDrawable(tv, this); getOverlay().add(drawable); ObjectAnimator drawableAnim = ObjectAnimator.ofFloat(drawable, TaskViewDrawable.PROGRESS, 1, 0); drawableAnim.setInterpolator(LINEAR); anim.play(drawableAnim); anim.setDuration(duration); Consumer<Boolean> onTaskLaunchFinish = (r) -> { onTaskLaunched(r); tv.setVisibility(VISIBLE); getOverlay().remove(drawable); }; mPendingAnimation = new PendingAnimation(anim); mPendingAnimation.addEndListener((onEndListener) -> { if (onEndListener.isSuccess) { tv.launchTask(false); tv.launchTask(false, onTaskLaunchFinish, getHandler()); Task task = tv.getTask(); if (task != null) { mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( Loading @@ -1084,13 +1088,17 @@ public abstract class RecentsView<T extends BaseActivity> TaskUtils.getComponentKeyForTask(task.key)); } } else { resetTaskVisuals(); onTaskLaunchFinish.accept(false); } mPendingAnimation = null; }); return mPendingAnimation; } protected void onTaskLaunched(boolean success) { resetTaskVisuals(); } @Override protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); Loading