Should use Activity.onEnterAnimationComplete. (Bug 18031283)
- Additional code cleanup for previous performance CLs Change-Id: I41c9be9b1541d0717e32732823f5bb0bedcf818f
This commit is contained in:
@@ -239,7 +239,7 @@
|
||||
<dimen name="recents_search_bar_space_height">64dp</dimen>
|
||||
|
||||
<!-- The side padding for the task stack as a percentage of the width. -->
|
||||
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.04444</item>
|
||||
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.03333</item>
|
||||
|
||||
<!-- The overscroll percentage allowed on the stack. -->
|
||||
<item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
|
||||
|
||||
@@ -54,7 +54,7 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/** A proxy implementation for the recents component */
|
||||
public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
|
||||
public class AlternateRecentsComponent {
|
||||
|
||||
final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
|
||||
final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome";
|
||||
@@ -63,7 +63,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
|
||||
final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey";
|
||||
|
||||
final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
|
||||
final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
|
||||
final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
|
||||
|
||||
@@ -78,9 +77,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
Context mContext;
|
||||
LayoutInflater mInflater;
|
||||
SystemServicesProxy mSystemServicesProxy;
|
||||
Handler mHandler;
|
||||
boolean mBootCompleted;
|
||||
boolean mStartAnimationTriggered;
|
||||
|
||||
// Task launching
|
||||
RecentsConfiguration mConfig;
|
||||
@@ -106,7 +103,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mContext = context;
|
||||
mSystemServicesProxy = new SystemServicesProxy(context);
|
||||
mHandler = new Handler();
|
||||
mTaskStackBounds = new Rect();
|
||||
}
|
||||
|
||||
@@ -364,30 +360,27 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
* Creates the activity options for a unknown state->recents transition.
|
||||
*/
|
||||
ActivityOptions getUnknownTransitionActivityOptions() {
|
||||
mStartAnimationTriggered = false;
|
||||
return ActivityOptions.makeCustomAnimation(mContext,
|
||||
R.anim.recents_from_unknown_enter,
|
||||
R.anim.recents_from_unknown_exit, mHandler, this);
|
||||
R.anim.recents_from_unknown_exit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the activity options for a home->recents transition.
|
||||
*/
|
||||
ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
|
||||
mStartAnimationTriggered = false;
|
||||
if (fromSearchHome) {
|
||||
return ActivityOptions.makeCustomAnimation(mContext,
|
||||
R.anim.recents_from_search_launcher_enter,
|
||||
R.anim.recents_from_search_launcher_exit, mHandler, this);
|
||||
R.anim.recents_from_search_launcher_exit);
|
||||
}
|
||||
return ActivityOptions.makeCustomAnimation(mContext,
|
||||
R.anim.recents_from_launcher_enter,
|
||||
R.anim.recents_from_launcher_exit, mHandler, this);
|
||||
R.anim.recents_from_launcher_exit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the activity options for an app->recents transition. If this method sets the static
|
||||
* screenshot, then we will use that for the transition.
|
||||
* Creates the activity options for an app->recents transition.
|
||||
*/
|
||||
ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
|
||||
boolean isTopTaskHome) {
|
||||
@@ -411,10 +404,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
c.setBitmap(null);
|
||||
}
|
||||
|
||||
mStartAnimationTriggered = false;
|
||||
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView,
|
||||
thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
|
||||
toTaskRect.height(), this);
|
||||
toTaskRect.height(), null);
|
||||
}
|
||||
|
||||
// If both the screenshot and thumbnail fails, then just fall back to the default transition
|
||||
@@ -551,42 +543,4 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
sRecentsComponentCallbacks.onVisibilityChanged(visible);
|
||||
}
|
||||
}
|
||||
|
||||
/**** OnAnimationStartedListener Implementation ****/
|
||||
|
||||
@Override
|
||||
public void onAnimationStarted() {
|
||||
// Notify recents to start the enter animation
|
||||
if (!mStartAnimationTriggered) {
|
||||
// There can be a race condition between the start animation callback and
|
||||
// the start of the new activity (where we register the receiver that listens
|
||||
// to this broadcast, so we add our own receiver and if that gets called, then
|
||||
// we know the activity has not yet started and we can retry sending the broadcast.
|
||||
BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (getResultCode() == Activity.RESULT_OK) {
|
||||
mStartAnimationTriggered = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule for the broadcast to be sent again after some time
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onAnimationStarted();
|
||||
}
|
||||
}, 75);
|
||||
}
|
||||
};
|
||||
|
||||
// Send the broadcast to notify Recents that the animation has started
|
||||
Intent intent = new Intent(ACTION_START_ENTER_ANIMATION);
|
||||
intent.setPackage(mContext.getPackageName());
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
|
||||
Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
|
||||
fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,14 +141,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
} else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
|
||||
// If we are toggling Recents, then first unfilter any filtered stacks first
|
||||
dismissRecentsToFocusedTaskOrHome(true);
|
||||
} else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) {
|
||||
// Try and start the enter animation (or restart it on configuration changed)
|
||||
ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null);
|
||||
mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
|
||||
onEnterAnimationTriggered();
|
||||
// Notify the fallback receiver that we have successfully got the broadcast
|
||||
// See AlternateRecentsComponent.onAnimationStarted()
|
||||
setResultCode(Activity.RESULT_OK);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -441,7 +433,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
// Try and start the enter animation (or restart it on configuration changed)
|
||||
ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
|
||||
mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
|
||||
onEnterAnimationTriggered();
|
||||
// Animate the SystemUI scrim views
|
||||
mScrimViews.startEnterRecentsAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -469,7 +462,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
|
||||
registerReceiver(mServiceBroadcastReceiver, filter);
|
||||
|
||||
// Register any broadcast receivers for the task loader
|
||||
@@ -511,6 +503,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnterAnimationComplete() {
|
||||
// Try and start the enter animation (or restart it on configuration changed)
|
||||
ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
|
||||
mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
|
||||
|
||||
// Animate the SystemUI scrim views
|
||||
mScrimViews.startEnterRecentsAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
@@ -592,12 +594,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the enter recents animation is triggered. */
|
||||
public void onEnterAnimationTriggered() {
|
||||
// Animate the SystemUI scrim views
|
||||
mScrimViews.startEnterRecentsAnimation();
|
||||
}
|
||||
|
||||
/**** RecentsView.RecentsViewCallbacks Implementation ****/
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.recents.misc;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
@@ -188,4 +189,15 @@ public class Utilities {
|
||||
int flags = intent.getFlags();
|
||||
return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels an animation ensuring that if it has listeners, onCancel and onEnd
|
||||
* are not called.
|
||||
*/
|
||||
public static void cancelAnimationWithoutCallbacks(Animator animator) {
|
||||
if (animator != null) {
|
||||
animator.removeAllListeners();
|
||||
animator.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
mSourceView.invalidateOutline();
|
||||
updateClipBounds();
|
||||
if (!mConfig.useHardwareLayers) {
|
||||
mSourceView.mThumbnailView.updateVisibility(
|
||||
mSourceView.mThumbnailView.updateThumbnailVisibility(
|
||||
bottom - mSourceView.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.widget.OverScroller;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
|
||||
/* The scrolling logic for a TaskStackView */
|
||||
public class TaskStackViewScroller {
|
||||
@@ -161,10 +162,7 @@ public class TaskStackViewScroller {
|
||||
|
||||
/** Aborts any current stack scrolls */
|
||||
void stopBoundScrollAnimation() {
|
||||
if (mScrollAnimator != null) {
|
||||
mScrollAnimator.removeAllListeners();
|
||||
mScrollAnimator.cancel();
|
||||
}
|
||||
Utilities.cancelAnimationWithoutCallbacks(mScrollAnimator);
|
||||
}
|
||||
|
||||
/**** OverScroller ****/
|
||||
|
||||
@@ -28,10 +28,9 @@ import android.view.ViewPropertyAnimator;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.AlternateRecentsComponent;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
@@ -53,11 +52,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
float mTaskProgress;
|
||||
ObjectAnimator mTaskProgressAnimator;
|
||||
ObjectAnimator mDimAnimator;
|
||||
float mMaxDimScale;
|
||||
int mDim;
|
||||
int mDimAlpha;
|
||||
AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1f);
|
||||
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.MULTIPLY);
|
||||
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
|
||||
Paint mDimLayerPaint = new Paint();
|
||||
|
||||
Task mTask;
|
||||
boolean mTaskDataLoaded;
|
||||
@@ -65,7 +64,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
boolean mFocusAnimationsEnabled;
|
||||
boolean mClipViewInStack;
|
||||
AnimateableViewBounds mViewBounds;
|
||||
Paint mLayerPaint = new Paint();
|
||||
|
||||
View mContent;
|
||||
TaskViewThumbnail mThumbnailView;
|
||||
@@ -130,7 +128,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
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);
|
||||
mThumbnailView.updateClipToTaskBar(mHeaderView);
|
||||
mActionButtonView = findViewById(R.id.lock_to_app_fab);
|
||||
mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
@@ -179,10 +177,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
!mConfig.fakeShadows, updateCallback);
|
||||
|
||||
// Update the task progress
|
||||
if (mTaskProgressAnimator != null) {
|
||||
mTaskProgressAnimator.removeAllListeners();
|
||||
mTaskProgressAnimator.cancel();
|
||||
}
|
||||
Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator);
|
||||
if (duration <= 0) {
|
||||
setTaskProgress(toTransform.p);
|
||||
} else {
|
||||
@@ -377,7 +372,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);
|
||||
|
||||
// Animate the dim
|
||||
if (mDim > 0) {
|
||||
if (mDimAlpha > 0) {
|
||||
ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
|
||||
anim.setDuration(mConfig.taskBarExitAnimDuration);
|
||||
anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
|
||||
@@ -495,26 +490,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
/** Returns the current dim. */
|
||||
public void setDim(int dim) {
|
||||
mDim = dim;
|
||||
if (mDimAnimator != null) {
|
||||
mDimAnimator.removeAllListeners();
|
||||
mDimAnimator.cancel();
|
||||
}
|
||||
mDimAlpha = dim;
|
||||
if (mConfig.useHardwareLayers) {
|
||||
// Defer setting hardware layers if we have not yet measured, or there is no dim to draw
|
||||
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
|
||||
if (mDimAnimator != null) {
|
||||
mDimAnimator.removeAllListeners();
|
||||
mDimAnimator.cancel();
|
||||
}
|
||||
|
||||
int inverse = 255 - mDim;
|
||||
mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse));
|
||||
mLayerPaint.setColorFilter(mDimColorFilter);
|
||||
mContent.setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint);
|
||||
mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
|
||||
mDimLayerPaint.setColorFilter(mDimColorFilter);
|
||||
mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
|
||||
}
|
||||
} else {
|
||||
float dimAlpha = mDim / 255.0f;
|
||||
float dimAlpha = mDimAlpha / 255.0f;
|
||||
if (mThumbnailView != null) {
|
||||
mThumbnailView.setDimAlpha(dimAlpha);
|
||||
}
|
||||
@@ -526,7 +511,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
/** Returns the current dim. */
|
||||
public int getDim() {
|
||||
return mDim;
|
||||
return mDimAlpha;
|
||||
}
|
||||
|
||||
/** Animates the dim to the task progress. */
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -56,23 +55,27 @@ public class TaskViewHeader extends FrameLayout {
|
||||
|
||||
RecentsConfiguration mConfig;
|
||||
|
||||
// Header views
|
||||
ImageView mDismissButton;
|
||||
ImageView mApplicationIcon;
|
||||
TextView mActivityDescription;
|
||||
|
||||
RippleDrawable mBackground;
|
||||
GradientDrawable mBackgroundColorDrawable;
|
||||
// Header drawables
|
||||
boolean mCurrentPrimaryColorIsDark;
|
||||
int mCurrentPrimaryColor;
|
||||
int mBackgroundColor;
|
||||
Drawable mLightDismissDrawable;
|
||||
Drawable mDarkDismissDrawable;
|
||||
RippleDrawable mBackground;
|
||||
GradientDrawable mBackgroundColorDrawable;
|
||||
AnimatorSet mFocusAnimator;
|
||||
PorterDuffColorFilter mDimFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
|
||||
|
||||
boolean mCurrentPrimaryColorIsDark;
|
||||
int mCurrentPrimaryColor;
|
||||
|
||||
// Static highlight that we draw at the top of each view
|
||||
static Paint sHighlightPaint;
|
||||
private Paint mDimPaint = new Paint();
|
||||
|
||||
// Header dim, which is only used when task view hardware layers are not used
|
||||
Paint mDimLayerPaint = new Paint();
|
||||
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
|
||||
|
||||
public TaskViewHeader(Context context) {
|
||||
this(context, null);
|
||||
@@ -172,6 +175,16 @@ public class TaskViewHeader extends FrameLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dim alpha, only used when we are not using hardware layers.
|
||||
* (see RecentsConfiguration.useHardwareLayers)
|
||||
*/
|
||||
void setDimAlpha(int alpha) {
|
||||
mDimColorFilter.setColor(Color.argb(alpha, 0, 0, 0));
|
||||
mDimLayerPaint.setColorFilter(mDimColorFilter);
|
||||
setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
|
||||
}
|
||||
|
||||
/** Returns the secondary color for a primary color. */
|
||||
int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
|
||||
int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
|
||||
@@ -266,8 +279,7 @@ public class TaskViewHeader extends FrameLayout {
|
||||
boolean isRunning = false;
|
||||
if (mFocusAnimator != null) {
|
||||
isRunning = mFocusAnimator.isRunning();
|
||||
mFocusAnimator.removeAllListeners();
|
||||
mFocusAnimator.cancel();
|
||||
Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
|
||||
}
|
||||
|
||||
if (focused) {
|
||||
@@ -344,11 +356,4 @@ public class TaskViewHeader extends FrameLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDimAlpha(int alpha) {
|
||||
int color = Color.argb(alpha, 0, 0, 0);
|
||||
mDimFilter.setColor(color);
|
||||
mDimPaint.setColorFilter(mDimFilter);
|
||||
setLayerType(LAYER_TYPE_HARDWARE, mDimPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,37 +33,48 @@ import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
|
||||
|
||||
/** The task thumbnail view */
|
||||
/**
|
||||
* The task thumbnail view. It implements an image view that allows for animating the dim and
|
||||
* alpha of the thumbnail image.
|
||||
*/
|
||||
public class TaskViewThumbnail extends View {
|
||||
|
||||
private final int mCornerRadius;
|
||||
private final Matrix mScaleMatrix = new Matrix();
|
||||
RecentsConfiguration mConfig;
|
||||
|
||||
// Task bar clipping
|
||||
Rect mClipRect = new Rect();
|
||||
// Drawing
|
||||
float mDimAlpha;
|
||||
Matrix mScaleMatrix = new Matrix();
|
||||
Paint mDrawPaint = new Paint();
|
||||
RectF mBitmapRect = new RectF();
|
||||
RectF mLayoutRect = new RectF();
|
||||
BitmapShader mBitmapShader;
|
||||
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
|
||||
private final RectF mBitmapRect = new RectF();
|
||||
private final RectF mLayoutRect = new RectF();
|
||||
private BitmapShader mBitmapShader;
|
||||
private float mBitmapAlpha;
|
||||
private float mDimAlpha;
|
||||
private View mTaskBar;
|
||||
private boolean mInvisible;
|
||||
private ValueAnimator mAlphaAnimator;
|
||||
private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
|
||||
|
||||
// Thumbnail alpha
|
||||
float mThumbnailAlpha;
|
||||
ValueAnimator mThumbnailAlphaAnimator;
|
||||
ValueAnimator.AnimatorUpdateListener mThumbnailAlphaUpdateListener
|
||||
= new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mBitmapAlpha = (float) animation.getAnimatedValue();
|
||||
updateFilter();
|
||||
mThumbnailAlpha = (float) animation.getAnimatedValue();
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
};
|
||||
|
||||
// Task bar clipping, the top of this thumbnail can be clipped against the opaque header
|
||||
// bar that overlaps this thumbnail
|
||||
View mTaskBar;
|
||||
Rect mClipRect = new Rect();
|
||||
|
||||
// Visibility optimization, if the thumbnail height is less than the height of the header
|
||||
// bar for the task view, then just mark this thumbnail view as invisible
|
||||
boolean mInvisible;
|
||||
|
||||
public TaskViewThumbnail(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -79,103 +90,15 @@ public class TaskViewThumbnail extends View {
|
||||
public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mConfig = RecentsConfiguration.getInstance();
|
||||
mCornerRadius = mConfig.taskViewRoundedCornerRadiusPx;
|
||||
mDrawPaint.setColorFilter(mLightingColorFilter);
|
||||
mDrawPaint.setFilterBitmap(true);
|
||||
mDrawPaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mInvisible) {
|
||||
return;
|
||||
}
|
||||
canvas.drawRoundRect(0,
|
||||
0,
|
||||
getWidth(),
|
||||
getHeight(),
|
||||
mCornerRadius,
|
||||
mCornerRadius,
|
||||
mDrawPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
mBitmapAlpha = 0.9f;
|
||||
updateFilter();
|
||||
}
|
||||
|
||||
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) {
|
||||
mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
|
||||
mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add));
|
||||
mDrawPaint.setColorFilter(mLightingColorFilter);
|
||||
mDrawPaint.setColor(0xffffffff);
|
||||
} else {
|
||||
mDrawPaint.setColorFilter(null);
|
||||
int grey = mul + add;
|
||||
mDrawPaint.setColor(Color.argb(255, grey, grey, grey));
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
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. */
|
||||
boolean bindToScreenshot(Bitmap ss) {
|
||||
setImageBitmap(ss);
|
||||
return ss != null;
|
||||
}
|
||||
|
||||
/** Unbinds the thumbnail view from the screenshot. */
|
||||
void unbindFromScreenshot() {
|
||||
setImageBitmap(null);
|
||||
}
|
||||
|
||||
/** Binds the thumbnail view to the task */
|
||||
void rebindToTask(Task t) {
|
||||
if (t.thumbnail != null) {
|
||||
setImageBitmap(t.thumbnail);
|
||||
} else {
|
||||
setImageBitmap(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageBitmap(Bitmap bm) {
|
||||
if (bm != null) {
|
||||
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
|
||||
Shader.TileMode.CLAMP);
|
||||
mDrawPaint.setShader(mBitmapShader);
|
||||
mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight());
|
||||
updateBitmapScale();
|
||||
} else {
|
||||
mBitmapShader = null;
|
||||
mDrawPaint.setShader(null);
|
||||
}
|
||||
updateFilter();
|
||||
mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,25 +106,106 @@ public class TaskViewThumbnail extends View {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (changed) {
|
||||
mLayoutRect.set(0, 0, getWidth(), getHeight());
|
||||
updateBitmapScale();
|
||||
updateThumbnailScale();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBitmapScale() {
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mInvisible) {
|
||||
return;
|
||||
}
|
||||
// Draw the thumbnail with the rounded corners
|
||||
canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
|
||||
mConfig.taskViewRoundedCornerRadiusPx,
|
||||
mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint);
|
||||
}
|
||||
|
||||
/** Sets the thumbnail to a given bitmap. */
|
||||
void setThumbnail(Bitmap bm) {
|
||||
if (bm != null) {
|
||||
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
|
||||
Shader.TileMode.CLAMP);
|
||||
mDrawPaint.setShader(mBitmapShader);
|
||||
mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight());
|
||||
updateThumbnailScale();
|
||||
} else {
|
||||
mBitmapShader = null;
|
||||
mDrawPaint.setShader(null);
|
||||
}
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
/** Updates the paint to draw the thumbnail. */
|
||||
void updateThumbnailPaintFilter() {
|
||||
if (mInvisible) {
|
||||
return;
|
||||
}
|
||||
int mul = (int) ((1.0f - mDimAlpha) * mThumbnailAlpha * 255);
|
||||
int add = (int) ((1.0f - mDimAlpha) * (1 - mThumbnailAlpha) * 255);
|
||||
if (mBitmapShader != null) {
|
||||
mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
|
||||
mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add));
|
||||
mDrawPaint.setColorFilter(mLightingColorFilter);
|
||||
mDrawPaint.setColor(0xffffffff);
|
||||
} else {
|
||||
int grey = mul + add;
|
||||
mDrawPaint.setColorFilter(null);
|
||||
mDrawPaint.setColor(Color.argb(255, grey, grey, grey));
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/** Updates the thumbnail shader's scale transform. */
|
||||
void updateThumbnailScale() {
|
||||
if (mBitmapShader != null) {
|
||||
mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL);
|
||||
mBitmapShader.setLocalMatrix(mScaleMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the clip rect based on the given task bar. */
|
||||
void updateClipToTaskBar(View taskBar) {
|
||||
mTaskBar = taskBar;
|
||||
int top = (int) Math.max(0, taskBar.getTranslationY() +
|
||||
taskBar.getMeasuredHeight() - 1);
|
||||
mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
|
||||
setClipBounds(mClipRect);
|
||||
}
|
||||
|
||||
/** Updates the visibility of the the thumbnail. */
|
||||
void updateThumbnailVisibility(int clipBottom) {
|
||||
boolean invisible = mTaskBar != null && (getHeight() - clipBottom) <= mTaskBar.getHeight();
|
||||
if (invisible != mInvisible) {
|
||||
mInvisible = invisible;
|
||||
if (!mInvisible) {
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dim alpha, only used when we are not using hardware layers.
|
||||
* (see RecentsConfiguration.useHardwareLayers)
|
||||
*/
|
||||
public void setDimAlpha(float dimAlpha) {
|
||||
mDimAlpha = dimAlpha;
|
||||
updateFilter();
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
/** Binds the thumbnail view to the task */
|
||||
void rebindToTask(Task t) {
|
||||
if (t.thumbnail != null) {
|
||||
setThumbnail(t.thumbnail);
|
||||
} else {
|
||||
setThumbnail(null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Unbinds the thumbnail view from the task */
|
||||
void unbindFromTask() {
|
||||
setImageBitmap(null);
|
||||
setThumbnail(null);
|
||||
}
|
||||
|
||||
/** Handles focus changes. */
|
||||
@@ -217,54 +221,46 @@ public class TaskViewThumbnail extends View {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prepares for the enter recents animation. */
|
||||
/**
|
||||
* Prepares for the enter recents animation, this gets called before the the view
|
||||
* is first visible and will be followed by a startEnterRecentsAnimation() call.
|
||||
*/
|
||||
void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) {
|
||||
if (isTaskViewLaunchTargetTask) {
|
||||
mBitmapAlpha = 1f;
|
||||
mThumbnailAlpha = 1f;
|
||||
} else {
|
||||
mBitmapAlpha = mConfig.taskViewThumbnailAlpha;
|
||||
mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
|
||||
}
|
||||
updateFilter();
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
/** Animates this task thumbnail as it enters recents */
|
||||
/** Animates this task thumbnail as it enters Recents. */
|
||||
void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
|
||||
startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
|
||||
mConfig.taskBarEnterAnimDuration, postAnimRunnable);
|
||||
}
|
||||
|
||||
/** Animates this task thumbnail as it exits recents */
|
||||
/** Animates this task thumbnail as it exits Recents. */
|
||||
void startLaunchTaskAnimation(Runnable postAnimRunnable) {
|
||||
startFadeAnimation(1f, 0, mConfig.taskBarExitAnimDuration, postAnimRunnable);
|
||||
}
|
||||
|
||||
/** Animates the thumbnail alpha. */
|
||||
/** Starts a new thumbnail alpha animation. */
|
||||
void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) {
|
||||
if (mAlphaAnimator != null) {
|
||||
mAlphaAnimator.cancel();
|
||||
}
|
||||
mAlphaAnimator = ValueAnimator.ofFloat(mBitmapAlpha, finalAlpha);
|
||||
mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
|
||||
mAlphaAnimator.setStartDelay(delay);
|
||||
mAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
|
||||
mAlphaAnimator.setDuration(duration);
|
||||
mAlphaAnimator.start();
|
||||
Utilities.cancelAnimationWithoutCallbacks(mThumbnailAlphaAnimator);
|
||||
mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
|
||||
mThumbnailAlphaAnimator.setStartDelay(delay);
|
||||
mThumbnailAlphaAnimator.setDuration(duration);
|
||||
mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
|
||||
mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
|
||||
if (postAnimRunnable != null) {
|
||||
mAlphaAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
public boolean mCancelled;
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCancelled = true;
|
||||
}
|
||||
|
||||
mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (!mCancelled) {
|
||||
postAnimRunnable.run();
|
||||
}
|
||||
postAnimRunnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
mThumbnailAlphaAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user