diff options
author | Hyunyoung Song <hyunyoungs@google.com> | 2016-06-15 12:51:30 -0700 |
---|---|---|
committer | Hyunyoung Song <hyunyoungs@google.com> | 2016-06-15 12:51:30 -0700 |
commit | 7d2fc8120e549eaa9542b0985aab67d172cbd682 (patch) | |
tree | 92335d428aa9379039c061bae93188c0b24135a8 /src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java | |
parent | b25b2c41c2fa277e16d708ad827e283efcb86452 (diff) | |
download | android_packages_apps_Trebuchet-7d2fc8120e549eaa9542b0985aab67d172cbd682.tar.gz android_packages_apps_Trebuchet-7d2fc8120e549eaa9542b0985aab67d172cbd682.tar.bz2 android_packages_apps_Trebuchet-7d2fc8120e549eaa9542b0985aab67d172cbd682.zip |
Add caret shaped all app pull up handle to page indicator.
b/28917826
> PageIndicator is also added in landscape
> Touch delegate allows the active touch area to be 36dp
Change-Id: If00f45fc88a13cd5a6759d771313439eb58561e3
Diffstat (limited to 'src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java')
-rw-r--r-- | src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java new file mode 100644 index 000000000..7394426a4 --- /dev/null +++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java @@ -0,0 +1,287 @@ +package com.android.launcher3.pageindicators; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.support.v4.graphics.ColorUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Property; +import android.view.TouchDelegate; +import android.view.View; +import android.view.ViewConfiguration; + +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.dynamicui.ExtractedColors; + +/** + * A PageIndicator that briefly shows a fraction of a line when moving between pages. + * + * The fraction is 1 / number of pages and the position is based on the progress of the page scroll. + */ +public class PageIndicatorLineCaret extends PageIndicator { + private static final String TAG = "PageIndicatorLine"; + + private static final int[] sTempCoords = new int[2]; + + private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration(); + private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay(); + public static final int WHITE_ALPHA = (int) (0.70f * 255); + public static final int BLACK_ALPHA = (int) (0.65f * 255); + + private static final int LINE_ALPHA_ANIMATOR_INDEX = 0; + private static final int NUM_PAGES_ANIMATOR_INDEX = 1; + private static final int TOTAL_SCROLL_ANIMATOR_INDEX = 2; + + private ValueAnimator[] mAnimators = new ValueAnimator[3]; + + private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper()); + + private boolean mShouldAutoHide = true; + + // The alpha of the line when it is showing. + private int mActiveAlpha = 0; + // The alpha that the line is being animated to or already at (either 0 or mActiveAlpha). + private int mToAlpha; + // A float value representing the number of pages, to allow for an animation when it changes. + private float mNumPagesFloat; + private int mCurrentScroll; + private int mTotalScroll; + private Paint mLinePaint; + private Launcher mLauncher; + // all apps pull up handle drawable. + private final Drawable caretDrawable; + private final int mLineHeight; + private final Rect mTouchHitRect = new Rect(); + private final int mTouchExtensionHeight; + + private static final Property<PageIndicatorLineCaret, Integer> PAINT_ALPHA + = new Property<PageIndicatorLineCaret, Integer>(Integer.class, "paint_alpha") { + @Override + public Integer get(PageIndicatorLineCaret obj) { + return obj.mLinePaint.getAlpha(); + } + + @Override + public void set(PageIndicatorLineCaret obj, Integer alpha) { + obj.mLinePaint.setAlpha(alpha); + obj.invalidate(); + } + }; + + private static final Property<PageIndicatorLineCaret, Float> NUM_PAGES + = new Property<PageIndicatorLineCaret, Float>(Float.class, "num_pages") { + @Override + public Float get(PageIndicatorLineCaret obj) { + return obj.mNumPagesFloat; + } + + @Override + public void set(PageIndicatorLineCaret obj, Float numPages) { + obj.mNumPagesFloat = numPages; + obj.invalidate(); + } + }; + + private static final Property<PageIndicatorLineCaret, Integer> TOTAL_SCROLL + = new Property<PageIndicatorLineCaret, Integer>(Integer.class, "total_scroll") { + @Override + public Integer get(PageIndicatorLineCaret obj) { + return obj.mTotalScroll; + } + + @Override + public void set(PageIndicatorLineCaret obj, Integer totalScroll) { + obj.mTotalScroll = totalScroll; + obj.invalidate(); + } + }; + + private Runnable mHideLineRunnable = new Runnable() { + @Override + public void run() { + animateLineToAlpha(0); + } + }; + + public PageIndicatorLineCaret(Context context) { + this(context, null); + } + + public PageIndicatorLineCaret(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PageIndicatorLineCaret(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mLinePaint = new Paint(); + mLinePaint.setAlpha(0); + + mLauncher = (Launcher) context; + setOnTouchListener(mLauncher.getHapticFeedbackTouchListener()); + setOnClickListener(mLauncher); + setOnFocusChangeListener(mLauncher.mFocusHandler); + Resources res = context.getResources(); + caretDrawable = res.getDrawable(R.drawable.ic_allapps_caret); + mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height); + mTouchExtensionHeight = res.getDimensionPixelSize( + R.dimen.dynamic_grid_page_indicator_extra_touch_height); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + int size = bottom - top; + int l = (right - left) / 2 - size / 2; + caretDrawable.setBounds(l, 0, l+ size, size); + + // The touch area is expanded below this view by #mTouchExtensionHeight + // which extends to the top of the hotseat. + View parent = mLauncher.getDragLayer(); + sTempCoords[0] = sTempCoords[1] = 0; + Utilities.getDescendantCoordRelativeToParent(this, parent, sTempCoords, true); + mTouchHitRect.set(sTempCoords[0], sTempCoords[1], sTempCoords[0] + this.getWidth(), + sTempCoords[1] + getHeight() + mTouchExtensionHeight); + parent.setTouchDelegate(new TouchDelegate(mTouchHitRect, this)); + } + + @Override + protected void onDraw(Canvas canvas) { + caretDrawable.draw(canvas); + if (mTotalScroll == 0 || mNumPagesFloat == 0) { + return; + } + + // Compute and draw line rect. + float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f); + int availableWidth = canvas.getWidth(); + int lineWidth = (int) (availableWidth / mNumPagesFloat); + int lineLeft = (int) (progress * (availableWidth - lineWidth)); + int lineRight = lineLeft + lineWidth; + canvas.drawRect(lineLeft, canvas.getHeight() + mLineHeight, lineRight, canvas.getHeight(), + mLinePaint); + } + + @Override + public void setScroll(int currentScroll, int totalScroll) { + if (getAlpha() == 0) { + return; + } + animateLineToAlpha(mActiveAlpha); + + mCurrentScroll = currentScroll; + if (mTotalScroll == 0) { + mTotalScroll = totalScroll; + } else if (mTotalScroll != totalScroll) { + animateToTotalScroll(totalScroll); + } else { + invalidate(); + } + + if (mShouldAutoHide) { + hideAfterDelay(); + } + } + + private void hideAfterDelay() { + mDelayedLineFadeHandler.removeCallbacksAndMessages(null); + mDelayedLineFadeHandler.postDelayed(mHideLineRunnable, LINE_FADE_DELAY); + } + + @Override + public void setActiveMarker(int activePage) { + } + + @Override + protected void onPageCountChanged() { + if (Float.compare(mNumPages, mNumPagesFloat) != 0) { + animateToNumPages(mNumPages); + } + } + + public void setShouldAutoHide(boolean shouldAutoHide) { + mShouldAutoHide = shouldAutoHide; + if (shouldAutoHide && mLinePaint.getAlpha() > 0) { + hideAfterDelay(); + } else if (!shouldAutoHide) { + mDelayedLineFadeHandler.removeCallbacksAndMessages(null); + } + } + + /** + * The line's color will be: + * - mostly opaque white if the hotseat is white (ignoring alpha) + * - mostly opaque black if the hotseat is black (ignoring alpha) + */ + public void updateColor(ExtractedColors extractedColors) { + int originalLineAlpha = mLinePaint.getAlpha(); + int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT); + if (color != Color.TRANSPARENT) { + color = ColorUtils.setAlphaComponent(color, 255); + if (color == Color.BLACK) { + mActiveAlpha = BLACK_ALPHA; + } else if (color == Color.WHITE) { + mActiveAlpha = WHITE_ALPHA; + } else { + Log.e(TAG, "Setting workspace page indicators to an unsupported color: #" + + Integer.toHexString(color)); + } + mLinePaint.setColor(color); + mLinePaint.setAlpha(originalLineAlpha); + } + } + + private void animateLineToAlpha(int alpha) { + if (alpha == mToAlpha) { + // Ignore the new animation if it is going to the same alpha as the current animation. + return; + } + mToAlpha = alpha; + setupAndRunAnimation(ObjectAnimator.ofInt(this, PAINT_ALPHA, alpha), + LINE_ALPHA_ANIMATOR_INDEX); + } + + private void animateToNumPages(int numPages) { + setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages), + NUM_PAGES_ANIMATOR_INDEX); + } + + private void animateToTotalScroll(int totalScroll) { + setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll), + TOTAL_SCROLL_ANIMATOR_INDEX); + } + + /** + * Starts the given animator and stores it in the provided index in {@link #mAnimators} until + * the animation ends. + * + * If an animator is already at the index (i.e. it is already playing), it is canceled and + * replaced with the new animator. + */ + private void setupAndRunAnimation(ValueAnimator animator, final int animatorIndex) { + if (mAnimators[animatorIndex] != null) { + mAnimators[animatorIndex].cancel(); + } + mAnimators[animatorIndex] = animator; + mAnimators[animatorIndex].addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimators[animatorIndex] = null; + } + }); + mAnimators[animatorIndex].setDuration(LINE_ANIMATE_DURATION); + mAnimators[animatorIndex].start(); + } +} |