am f7093202: Enabling recents stack clipping

* commit 'f709320263f370145780270fdc825cfbc48912d1':
  Enabling recents stack clipping
This commit is contained in:
Winson Chung
2014-09-18 18:44:44 +00:00
committed by Android Git Automerger
12 changed files with 227 additions and 70 deletions

View File

@@ -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>

View File

@@ -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. -->

View File

@@ -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

View File

@@ -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 =

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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. */

View File

@@ -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)

View File

@@ -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