am f7093202: Enabling recents stack clipping
* commit 'f709320263f370145780270fdc825cfbc48912d1': Enabling recents stack clipping
This commit is contained in:
@@ -18,26 +18,31 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true">
|
||||
<com.android.systemui.recents.views.TaskViewThumbnail
|
||||
android:id="@+id/task_view_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<include layout="@layout/recents_task_view_header" />
|
||||
<FrameLayout
|
||||
android:id="@+id/lock_to_app_fab"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:translationZ="3dp"
|
||||
android:contentDescription="@string/recents_lock_to_app_button_label"
|
||||
android:background="@drawable/recents_lock_to_task_button_bg">
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/recents_lock_to_app_pin" />
|
||||
android:id="@+id/task_view_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<com.android.systemui.recents.views.TaskViewThumbnail
|
||||
android:id="@+id/task_view_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<include layout="@layout/recents_task_view_header" />
|
||||
<FrameLayout
|
||||
android:id="@+id/lock_to_app_fab"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:translationZ="2dp"
|
||||
android:contentDescription="@string/recents_lock_to_app_button_label"
|
||||
android:background="@drawable/recents_lock_to_task_button_bg">
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/recents_lock_to_app_pin" />
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
</com.android.systemui.recents.views.TaskView>
|
||||
|
||||
|
||||
@@ -154,9 +154,12 @@
|
||||
duration of the transition in to recents from home. -->
|
||||
<integer name="recents_animate_task_enter_from_home_delay">150</integer>
|
||||
<!-- The min animation duration for animating the task in when transitioning from home. -->
|
||||
<integer name="recents_animate_task_enter_from_home_duration">275</integer>
|
||||
<!-- The animation stagger to apply to each task animation when transitioning from home. -->
|
||||
<integer name="recents_animate_task_enter_from_home_stagger_delay">10</integer>
|
||||
<integer name="recents_animate_task_enter_from_home_duration">200</integer>
|
||||
<!-- The total animation stagger delay when entering from home. -->
|
||||
<integer name="recents_animate_task_enter_from_home_stagger_delay">110</integer>
|
||||
<!-- The total animation duration added to the last card when entering from home.
|
||||
This value is partialy also added to the previous tasks -->
|
||||
<integer name="recents_animate_task_enter_from_home_stagger_duration">72</integer>
|
||||
<!-- The short duration when animating in/out the lock to app button. -->
|
||||
<integer name="recents_animate_lock_to_app_button_short_duration">150</integer>
|
||||
<!-- The long duration when animating in/out the lock to app button. -->
|
||||
|
||||
@@ -32,7 +32,7 @@ public class Constants {
|
||||
// Enables the filtering of tasks according to their grouping
|
||||
public static final boolean EnableTaskFiltering = false;
|
||||
// Enables clipping of tasks against each other
|
||||
public static final boolean EnableTaskStackClipping = false;
|
||||
public static final boolean EnableTaskStackClipping = true;
|
||||
// Enables tapping on the TaskBar to launch the task
|
||||
public static final boolean EnableTaskBarTouchEvents = true;
|
||||
// Enables app-info pane on long-pressing the icon
|
||||
|
||||
@@ -78,6 +78,7 @@ public class RecentsConfiguration {
|
||||
public int taskViewEnterFromHomeDelay;
|
||||
public int taskViewEnterFromHomeDuration;
|
||||
public int taskViewEnterFromHomeStaggerDelay;
|
||||
public int taskViewEnterFromHomeStaggerDuration;
|
||||
public int taskViewExitToHomeDuration;
|
||||
public int taskViewRemoveAnimDuration;
|
||||
public int taskViewRemoveAnimTranslationXPx;
|
||||
@@ -219,6 +220,8 @@ public class RecentsConfiguration {
|
||||
res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
|
||||
taskViewEnterFromHomeStaggerDelay =
|
||||
res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_delay);
|
||||
taskViewEnterFromHomeStaggerDuration =
|
||||
res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_duration);
|
||||
taskViewExitToHomeDuration =
|
||||
res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
|
||||
taskViewRemoveAnimDuration =
|
||||
|
||||
@@ -18,11 +18,14 @@ package com.android.systemui.recents.misc;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/* Common code */
|
||||
public class Utilities {
|
||||
@@ -68,6 +71,80 @@ public class Utilities {
|
||||
}
|
||||
}
|
||||
|
||||
/** Maps a coorindate in a descendant view into the parent. */
|
||||
public static float mapCoordInDescendentToSelf(View descendant, View root,
|
||||
float[] coord, boolean includeRootScroll) {
|
||||
ArrayList<View> ancestorChain = new ArrayList<View>();
|
||||
|
||||
float[] pt = {coord[0], coord[1]};
|
||||
|
||||
View v = descendant;
|
||||
while(v != root && v != null) {
|
||||
ancestorChain.add(v);
|
||||
v = (View) v.getParent();
|
||||
}
|
||||
ancestorChain.add(root);
|
||||
|
||||
float scale = 1.0f;
|
||||
int count = ancestorChain.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View v0 = ancestorChain.get(i);
|
||||
// For TextViews, scroll has a meaning which relates to the text position
|
||||
// which is very strange... ignore the scroll.
|
||||
if (v0 != descendant || includeRootScroll) {
|
||||
pt[0] -= v0.getScrollX();
|
||||
pt[1] -= v0.getScrollY();
|
||||
}
|
||||
|
||||
v0.getMatrix().mapPoints(pt);
|
||||
pt[0] += v0.getLeft();
|
||||
pt[1] += v0.getTop();
|
||||
scale *= v0.getScaleX();
|
||||
}
|
||||
|
||||
coord[0] = pt[0];
|
||||
coord[1] = pt[1];
|
||||
return scale;
|
||||
}
|
||||
|
||||
/** Maps a coordinate in the root to a descendent. */
|
||||
public static float mapCoordInSelfToDescendent(View descendant, View root,
|
||||
float[] coord, Matrix tmpInverseMatrix) {
|
||||
ArrayList<View> ancestorChain = new ArrayList<View>();
|
||||
|
||||
float[] pt = {coord[0], coord[1]};
|
||||
|
||||
View v = descendant;
|
||||
while(v != root) {
|
||||
ancestorChain.add(v);
|
||||
v = (View) v.getParent();
|
||||
}
|
||||
ancestorChain.add(root);
|
||||
|
||||
float scale = 1.0f;
|
||||
int count = ancestorChain.size();
|
||||
tmpInverseMatrix.set(Matrix.IDENTITY_MATRIX);
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
View ancestor = ancestorChain.get(i);
|
||||
View next = i > 0 ? ancestorChain.get(i-1) : null;
|
||||
|
||||
pt[0] += ancestor.getScrollX();
|
||||
pt[1] += ancestor.getScrollY();
|
||||
|
||||
if (next != null) {
|
||||
pt[0] -= next.getLeft();
|
||||
pt[1] -= next.getTop();
|
||||
next.getMatrix().invert(tmpInverseMatrix);
|
||||
tmpInverseMatrix.mapPoints(pt);
|
||||
scale *= next.getScaleX();
|
||||
}
|
||||
}
|
||||
|
||||
coord[0] = pt[0];
|
||||
coord[1] = pt[1];
|
||||
return scale;
|
||||
}
|
||||
|
||||
/** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
|
||||
public static float computeContrastBetweenColors(int bg, int fg) {
|
||||
float bgR = Color.red(bg) / 255f;
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
|
||||
/* An outline provider that has a clip and outline that can be animated. */
|
||||
@@ -29,8 +30,10 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
|
||||
RecentsConfiguration mConfig;
|
||||
|
||||
View mSourceView;
|
||||
TaskView mSourceView;
|
||||
Rect mTmpRect = new Rect();
|
||||
Rect mClipRect = new Rect();
|
||||
Rect mClipBounds = new Rect();
|
||||
Rect mOutlineClipRect = new Rect();
|
||||
int mCornerRadius;
|
||||
float mAlpha = 1f;
|
||||
@@ -40,7 +43,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
ObjectAnimator mClipRightAnimator;
|
||||
ObjectAnimator mClipBottomAnimator;
|
||||
|
||||
public AnimateableViewBounds(View source, int cornerRadius) {
|
||||
public AnimateableViewBounds(TaskView source, int cornerRadius) {
|
||||
mConfig = RecentsConfiguration.getInstance();
|
||||
mSourceView = source;
|
||||
mCornerRadius = cornerRadius;
|
||||
@@ -53,8 +56,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
|
||||
|
||||
// TODO: This doesn't work with fake shadows.
|
||||
outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left),
|
||||
Math.max(mClipRect.top, mOutlineClipRect.top),
|
||||
mSourceView.getWidth() - Math.max(mClipRect.right, mOutlineClipRect.right),
|
||||
@@ -90,6 +91,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
if (top != mClipRect.top) {
|
||||
mClipRect.top = top;
|
||||
mSourceView.invalidateOutline();
|
||||
updateClipBounds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +117,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
if (right != mClipRect.right) {
|
||||
mClipRect.right = right;
|
||||
mSourceView.invalidateOutline();
|
||||
updateClipBounds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +143,11 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
if (bottom != mClipRect.bottom) {
|
||||
mClipRect.bottom = bottom;
|
||||
mSourceView.invalidateOutline();
|
||||
updateClipBounds();
|
||||
if (!mConfig.useHardwareLayers) {
|
||||
mSourceView.mThumbnailView.updateVisibility(
|
||||
bottom - mSourceView.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,4 +168,11 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
public int getOutlineClipBottom() {
|
||||
return mOutlineClipRect.bottom;
|
||||
}
|
||||
|
||||
private void updateClipBounds() {
|
||||
mClipBounds.set(mClipRect.left, mClipRect.top,
|
||||
mSourceView.getWidth() - mClipRect.right,
|
||||
mSourceView.getHeight() - mClipRect.bottom);
|
||||
mSourceView.setClipBounds(mClipBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,21 +16,23 @@
|
||||
|
||||
package com.android.systemui.recents.views;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.misc.DozeTrigger;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.RecentsPackageMonitor;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
@@ -76,16 +78,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// Optimizations
|
||||
int mStackViewsAnimationDuration;
|
||||
boolean mStackViewsDirty = true;
|
||||
boolean mStackViewsClipDirty = true;
|
||||
boolean mAwaitingFirstLayout = true;
|
||||
boolean mStartEnterAnimationRequestedAfterLayout;
|
||||
boolean mStartEnterAnimationCompleted;
|
||||
ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
|
||||
int[] mTmpVisibleRange = new int[2];
|
||||
float[] mTmpCoord = new float[2];
|
||||
Matrix mTmpMatrix = new Matrix();
|
||||
Rect mTmpRect = new Rect();
|
||||
TaskViewTransform mTmpTransform = new TaskViewTransform();
|
||||
HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>();
|
||||
LayoutInflater mInflater;
|
||||
|
||||
// A convenience update listener to request updating clipping of tasks
|
||||
ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
requestUpdateStackViewsClip();
|
||||
}
|
||||
};
|
||||
|
||||
// A convenience runnable to return all views to the pool
|
||||
Runnable mReturnAllViewsToPoolRunnable = new Runnable() {
|
||||
@Override
|
||||
@@ -152,6 +166,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
}
|
||||
|
||||
/** Requests that the views clipping be updated. */
|
||||
void requestUpdateStackViewsClip() {
|
||||
if (!mStackViewsClipDirty) {
|
||||
invalidate();
|
||||
mStackViewsClipDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds the child view given a specific task. */
|
||||
public TaskView getChildViewForTask(Task t) {
|
||||
int childCount = getChildCount();
|
||||
@@ -301,7 +323,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
|
||||
// Animate the task into place
|
||||
tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex),
|
||||
mStackViewsAnimationDuration);
|
||||
mStackViewsAnimationDuration, mRequestUpdateClippingListener);
|
||||
|
||||
// Request accessibility focus on the next view if we removed the task
|
||||
// that previously held accessibility focus
|
||||
@@ -319,6 +341,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// Reset the request-synchronize params
|
||||
mStackViewsAnimationDuration = 0;
|
||||
mStackViewsDirty = false;
|
||||
mStackViewsClipDirty = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -349,10 +372,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// stacked and we can make assumptions about the visibility of the this
|
||||
// task relative to the ones in front of it.
|
||||
if (nextTv != null) {
|
||||
// We can reuse the current task transforms to find the task rects
|
||||
TaskViewTransform transform = mCurrentTaskTransforms.get(mStack.indexOfTask(tv.getTask()));
|
||||
TaskViewTransform nextTransform = mCurrentTaskTransforms.get(mStack.indexOfTask(nextTv.getTask()));
|
||||
clipBottom = transform.rect.bottom - nextTransform.rect.top;
|
||||
// Map the top edge of next task view into the local space of the current
|
||||
// task view to find the clip amount in local space
|
||||
mTmpCoord[0] = mTmpCoord[1] = 0;
|
||||
Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
|
||||
Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
|
||||
clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
|
||||
- nextTv.getPaddingTop() - 1);
|
||||
}
|
||||
}
|
||||
tv.getViewBounds().setClipBottom(clipBottom);
|
||||
@@ -363,6 +389,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
tv.getViewBounds().setClipBottom(0);
|
||||
}
|
||||
}
|
||||
mStackViewsClipDirty = false;
|
||||
}
|
||||
|
||||
/** The stack insets to apply to the stack contents */
|
||||
@@ -665,6 +692,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
|
||||
ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
|
||||
launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
|
||||
ctx.updateListener = mRequestUpdateClippingListener;
|
||||
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), ctx.currentTaskTransform, null);
|
||||
tv.startEnterRecentsAnimation(ctx);
|
||||
}
|
||||
@@ -1003,7 +1031,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
|
||||
@Override
|
||||
public void onTaskViewClipStateChanged(TaskView tv) {
|
||||
invalidate();
|
||||
if (!mStackViewsDirty) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,12 +20,7 @@ import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.util.AttributeSet;
|
||||
@@ -74,6 +69,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
AnimateableViewBounds mViewBounds;
|
||||
Paint mLayerPaint = new Paint();
|
||||
|
||||
View mContent;
|
||||
TaskViewThumbnail mThumbnailView;
|
||||
TaskViewHeader mHeaderView;
|
||||
TaskViewFooter mFooterView;
|
||||
@@ -134,15 +130,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
// Bind the views
|
||||
mContent = findViewById(R.id.task_view_content);
|
||||
mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
|
||||
mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
mActionButtonView = findViewById(R.id.lock_to_app_fab);
|
||||
mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
// Set the outline to match the FAB background
|
||||
outline.setOval(0, 0, mActionButtonView.getWidth(),
|
||||
mActionButtonView.getHeight());
|
||||
outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
|
||||
}
|
||||
});
|
||||
if (mFooterView != null) {
|
||||
@@ -157,6 +154,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
|
||||
int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
|
||||
|
||||
// Measure the content
|
||||
mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY));
|
||||
|
||||
// Measure the bar view, thumbnail, and footer
|
||||
mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
|
||||
@@ -186,6 +188,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
/** Synchronizes this view's properties with the task's transform */
|
||||
void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
|
||||
updateViewPropertiesToTaskTransform(toTransform, duration, null);
|
||||
}
|
||||
|
||||
void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
|
||||
ValueAnimator.AnimatorUpdateListener updateCallback) {
|
||||
// If we are a full screen view, then only update the Z to keep it in order
|
||||
// XXX: Also update/animate the dim as well
|
||||
if (mIsFullScreenView) {
|
||||
@@ -198,7 +205,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
// Apply the transform
|
||||
toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false,
|
||||
!mConfig.fakeShadows);
|
||||
!mConfig.fakeShadows, updateCallback);
|
||||
|
||||
// Update the task progress
|
||||
if (mTaskProgressAnimator != null) {
|
||||
@@ -331,8 +338,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mViewBounds.setClipRight(0);
|
||||
// Reset the bar translation
|
||||
mHeaderView.setTranslationY(0);
|
||||
// Enable the thumbnail clip
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
// Animate the footer into view (if it is the front most task)
|
||||
animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration);
|
||||
|
||||
@@ -349,9 +354,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
})
|
||||
.start();
|
||||
} else {
|
||||
// Otherwise, just enable the thumbnail clip
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
|
||||
// Animate the footer into view
|
||||
animateFooterVisibility(true, 0);
|
||||
}
|
||||
@@ -359,8 +361,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
} else if (mConfig.launchedFromAppWithThumbnail) {
|
||||
if (mTask.isLaunchTarget) {
|
||||
// Enable the task bar clip
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
// Animate the dim/overlay
|
||||
if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
|
||||
// Animate the thumbnail alpha before the dim animation (to prevent updating the
|
||||
@@ -392,8 +392,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
.withLayer()
|
||||
.start();
|
||||
} else {
|
||||
// Enable the task bar clip
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
// Animate the task up if it was occluding the launch target
|
||||
if (ctx.currentTaskOccludesLaunchTarget) {
|
||||
setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx);
|
||||
@@ -407,7 +405,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
.withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
// Decrement the post animation trigger
|
||||
ctx.postAnimationTrigger.decrement();
|
||||
}
|
||||
@@ -421,8 +418,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
} else if (mConfig.launchedFromHome) {
|
||||
// Animate the tasks up
|
||||
int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
|
||||
int delay = mConfig.taskViewEnterFromHomeDelay +
|
||||
frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
|
||||
float fraction = (float) frontIndex / (ctx.currentStackViewCount - 1);
|
||||
fraction = (float) Math.pow(fraction, 0.85f);
|
||||
int delay = (int) (mConfig.taskViewEnterFromHomeDelay +
|
||||
fraction * mConfig.taskViewEnterFromHomeStaggerDelay);
|
||||
long delayIncrease = (long) (fraction * mConfig.taskViewEnterFromHomeStaggerDuration);
|
||||
if (!mConfig.fakeShadows) {
|
||||
animate().translationZ(transform.translationZ);
|
||||
}
|
||||
@@ -431,13 +431,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
.scaleY(transform.scale)
|
||||
.translationY(transform.translationY)
|
||||
.setStartDelay(delay)
|
||||
.setUpdateListener(null)
|
||||
.setUpdateListener(ctx.updateListener)
|
||||
.setInterpolator(mConfig.quintOutInterpolator)
|
||||
.setDuration(mConfig.taskViewEnterFromHomeDuration)
|
||||
.setDuration(mConfig.taskViewEnterFromHomeDuration + delayIncrease)
|
||||
.withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
// Decrement the post animation trigger
|
||||
ctx.postAnimationTrigger.decrement();
|
||||
}
|
||||
@@ -450,9 +449,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
startDelay = delay;
|
||||
|
||||
} else {
|
||||
// Otherwise, just enable the thumbnail clip
|
||||
mThumbnailView.enableTaskBarClip(mHeaderView);
|
||||
|
||||
// Animate the footer into view
|
||||
animateFooterVisibility(true, 0);
|
||||
}
|
||||
@@ -484,8 +480,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
|
||||
boolean occludesLaunchTarget, boolean lockToTask) {
|
||||
if (isLaunchingTask) {
|
||||
// Disable the thumbnail clip
|
||||
mThumbnailView.disableTaskBarClip();
|
||||
// Animate the thumbnail alpha back into full opacity for the window animation out
|
||||
mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);
|
||||
|
||||
@@ -662,7 +656,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
int inverse = 255 - mDim;
|
||||
mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse));
|
||||
mLayerPaint.setColorFilter(mDimColorFilter);
|
||||
setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint);
|
||||
mContent.setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint);
|
||||
}
|
||||
} else {
|
||||
float dimAlpha = mDim / 255.0f;
|
||||
|
||||
@@ -259,6 +259,14 @@ public class TaskViewHeader extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] onCreateDrawableState(int extraSpace) {
|
||||
|
||||
// Don't forward our state to the drawable - we do it manually in onTaskViewFocusChanged.
|
||||
// This is to prevent layer trashing when the view is pressed.
|
||||
return new int[] {};
|
||||
}
|
||||
|
||||
/** Notifies the associated TaskView has been focused. */
|
||||
void onTaskViewFocusChanged(boolean focused) {
|
||||
boolean isRunning = false;
|
||||
|
||||
@@ -52,6 +52,8 @@ public class TaskViewThumbnail extends View {
|
||||
private BitmapShader mBitmapShader;
|
||||
private float mBitmapAlpha;
|
||||
private float mDimAlpha;
|
||||
private View mTaskBar;
|
||||
private boolean mInvisible;
|
||||
private ValueAnimator mAlphaAnimator;
|
||||
private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
|
||||
= new ValueAnimator.AnimatorUpdateListener() {
|
||||
@@ -85,6 +87,9 @@ public class TaskViewThumbnail extends View {
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mInvisible) {
|
||||
return;
|
||||
}
|
||||
canvas.drawRoundRect(0,
|
||||
0,
|
||||
getWidth(),
|
||||
@@ -101,6 +106,9 @@ public class TaskViewThumbnail extends View {
|
||||
}
|
||||
|
||||
private void updateFilter() {
|
||||
if (mInvisible) {
|
||||
return;
|
||||
}
|
||||
int mul = (int) ((1.0f - mDimAlpha) * mBitmapAlpha * 255);
|
||||
int add = (int) ((1.0f - mDimAlpha) * (1 - mBitmapAlpha) * 255);
|
||||
if (mBitmapShader != null) {
|
||||
@@ -118,16 +126,22 @@ public class TaskViewThumbnail extends View {
|
||||
|
||||
/** Updates the clip rect based on the given task bar. */
|
||||
void enableTaskBarClip(View taskBar) {
|
||||
mTaskBar = taskBar;
|
||||
int top = (int) Math.max(0, taskBar.getTranslationY() +
|
||||
taskBar.getMeasuredHeight() - 1);
|
||||
mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
|
||||
setClipBounds(mClipRect);
|
||||
}
|
||||
|
||||
/** Disables the task bar clipping. */
|
||||
void disableTaskBarClip() {
|
||||
mClipRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
setClipBounds(mClipRect);
|
||||
void updateVisibility(int clipBottom) {
|
||||
boolean invisible = mTaskBar != null && getHeight() - clipBottom < mTaskBar.getHeight();
|
||||
if (invisible != mInvisible) {
|
||||
mInvisible = invisible;
|
||||
if (!mInvisible) {
|
||||
updateFilter();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/** Binds the thumbnail view to the screenshot. */
|
||||
|
||||
@@ -78,7 +78,7 @@ public class TaskViewTransform {
|
||||
|
||||
/** Applies this transform to a view. */
|
||||
public void applyToTaskView(View v, int duration, Interpolator interp, boolean allowLayers,
|
||||
boolean allowShadows) {
|
||||
boolean allowShadows, ValueAnimator.AnimatorUpdateListener updateCallback) {
|
||||
// Check to see if any properties have changed, and update the task view
|
||||
if (duration > 0) {
|
||||
ViewPropertyAnimator anim = v.animate();
|
||||
@@ -104,6 +104,11 @@ public class TaskViewTransform {
|
||||
if (requiresLayers && allowLayers) {
|
||||
anim.withLayer();
|
||||
}
|
||||
if (updateCallback != null) {
|
||||
anim.setUpdateListener(updateCallback);
|
||||
} else {
|
||||
anim.setUpdateListener(null);
|
||||
}
|
||||
anim.setStartDelay(startDelay)
|
||||
.setDuration(duration)
|
||||
.setInterpolator(interp)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.recents.views;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Rect;
|
||||
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
|
||||
|
||||
@@ -27,6 +28,8 @@ public class ViewAnimation {
|
||||
// A trigger to run some logic when all the animations complete. This works around the fact
|
||||
// that it is difficult to coordinate ViewPropertyAnimators
|
||||
ReferenceCountedTrigger postAnimationTrigger;
|
||||
// An update listener to notify as the enter animation progresses (used for the home transition)
|
||||
ValueAnimator.AnimatorUpdateListener updateListener;
|
||||
|
||||
// These following properties are updated for each task view we start the enter animation on
|
||||
|
||||
|
||||
Reference in New Issue
Block a user