me.lizheng.deckview.views.DeckChildViewHeader.java Source code

Java tutorial

Introduction

Here is the source code for me.lizheng.deckview.views.DeckChildViewHeader.java

Source

/*
 * Copyright (C) 2016 Zheng Li <https://lizheng.me>
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.lizheng.deckview.views;

import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import me.lizheng.deckview.R;
import me.lizheng.deckview.helpers.DeckViewConfig;
import me.lizheng.deckview.utilities.DVUtils;

/* The task bar view */
public class DeckChildViewHeader extends FrameLayout {

    DeckViewConfig mConfig;

    // Header views
    ImageView mDismissButton;
    ImageView mApplicationIcon;
    TextView mActivityDescription;

    // Header drawables
    boolean mCurrentPrimaryColorIsDark;
    int mCurrentPrimaryColor;
    int mBackgroundColor;
    Drawable mLightDismissDrawable;
    Drawable mDarkDismissDrawable;
    GradientDrawable mBackgroundColorDrawable;
    AnimatorSet mFocusAnimator;
    String mDismissContentDescription;

    // Static highlight that we draw at the top of each view
    static Paint sHighlightPaint;

    public DeckChildViewHeader(Context context) {
        this(context, null);
    }

    public DeckChildViewHeader(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DeckChildViewHeader(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mConfig = DeckViewConfig.getInstance();
        setWillNotDraw(false);

        // Load the dismiss resources
        Resources res = context.getResources();
        mLightDismissDrawable = ContextCompat.getDrawable(context, R.drawable.deck_child_view_dismiss_light);
        mDarkDismissDrawable = ContextCompat.getDrawable(context, R.drawable.deck_child_view_dismiss_dark);
        mDismissContentDescription = res.getString(R.string.accessibility_item_will_be_dismissed);

        // Configure the highlight paint
        if (sHighlightPaint == null) {
            sHighlightPaint = new Paint();
            sHighlightPaint.setStyle(Paint.Style.STROKE);
            sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
            sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
            sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
            sHighlightPaint.setAntiAlias(true);
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        // Initialize the icon and description views
        mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
        mActivityDescription = (TextView) findViewById(R.id.activity_description);
        mDismissButton = (ImageView) findViewById(R.id.dismiss_task);

        // Hide the backgrounds if they are ripple drawables
        //        if (!DVConstants.DebugFlags.App.EnableTaskFiltering) {
        //            if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
        //                mApplicationIcon.setBackgroundDrawable(null);
        //            }
        //        }

        mBackgroundColorDrawable = (GradientDrawable) ContextCompat.getDrawable(getContext(),
                R.drawable.deck_child_view_header_bg_color);
        setBackgroundDrawable(mBackgroundColorDrawable);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        // Draw the highlight at the top edge (but put the bottom edge just out of view)
        float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
        float radius = mConfig.taskViewRoundedCornerRadiusPx;
        int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
        canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
        canvas.drawRoundRect(
                new RectF(-offset, 0f, (float) getMeasuredWidth() + offset, getMeasuredHeight() + radius), radius,
                radius, sHighlightPaint);
        canvas.restoreToCount(count);
    }

    @Override
    public boolean hasOverlappingRendering() {
        return false;
    }

    /**
     * Returns the secondary color for a primary color.
     */
    int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
        int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
        return DVUtils.getColorWithOverlay(primaryColor, overlayColor, 0.8f);
    }

    /**
     * Binds the bar view to the task
     */
    public void rebindToTask(Drawable headerIcon, String headerTitle, int headerBgColor) {
        // If an activity icon is defined, then we use that as the primary icon to show in the bar,
        // otherwise, we fall back to the application icon
        mApplicationIcon.setImageDrawable(headerIcon);
        mApplicationIcon.setContentDescription(headerTitle);

        mActivityDescription.setText(headerTitle);

        // Try and apply the system ui tint
        int existingBgColor = (getBackground() instanceof ColorDrawable)
                ? ((ColorDrawable) getBackground()).getColor()
                : 0;
        if (existingBgColor != headerBgColor) {
            mBackgroundColorDrawable.setColor(headerBgColor);
            mBackgroundColor = headerBgColor;
        }
        mCurrentPrimaryColor = headerBgColor;
        //mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor;
        mActivityDescription.setTextColor(mConfig.taskBarViewLightTextColor);
        mDismissButton.setImageDrawable(mLightDismissDrawable);
        mDismissButton.setContentDescription(String.format(mDismissContentDescription, headerTitle));
    }

    /**
     * Unbinds the bar view from the task
     */
    void unbindFromTask() {
        mApplicationIcon.setImageDrawable(null);
    }

    /**
     * Animates this task bar if the user does not interact with the stack after a certain time.
     */
    void startNoUserInteractionAnimation() {
        if (mDismissButton.getVisibility() != View.VISIBLE) {
            mDismissButton.setVisibility(View.VISIBLE);
            mDismissButton.setAlpha(0f);
            mDismissButton.animate().alpha(1f).setStartDelay(0).setInterpolator(mConfig.fastOutLinearInInterpolator)
                    .setDuration(mConfig.taskViewEnterFromAppDuration).start();
        }
    }

    /**
     * Mark this task view that the user does has not interacted with the stack after a certain time.
     */
    void setNoUserInteractionState() {
        if (mDismissButton.getVisibility() != View.VISIBLE) {
            mDismissButton.animate().cancel();
            mDismissButton.setVisibility(View.VISIBLE);
            mDismissButton.setAlpha(1f);
        }
    }

    /**
     * Resets the state tracking that the user has not interacted with the stack after a certain time.
     */
    void resetNoUserInteractionState() {
        mDismissButton.setVisibility(View.INVISIBLE);
    }

    @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 animateFocusedState) {
        // If we are not animating the visible state, just return
        if (!animateFocusedState)
            return;

        boolean isRunning = false;
        if (mFocusAnimator != null) {
            isRunning = mFocusAnimator.isRunning();
            DVUtils.cancelAnimationWithoutCallbacks(mFocusAnimator);
        }

        if (focused) {
            // Pulse the background color
            int currentColor = mBackgroundColor;
            int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
            ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(), currentColor,
                    lightPrimaryColor);

            backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int color = (int) animation.getAnimatedValue();
                    mBackgroundColorDrawable.setColor(color);
                    mBackgroundColor = color;
                }
            });

            backgroundColor.setRepeatCount(ValueAnimator.INFINITE);
            backgroundColor.setRepeatMode(ValueAnimator.REVERSE);

            // Pulse the translation
            ObjectAnimator translation = ObjectAnimator.ofFloat(this, "translationZ", 15f);
            translation.setRepeatCount(ValueAnimator.INFINITE);
            translation.setRepeatMode(ValueAnimator.REVERSE);

            mFocusAnimator = new AnimatorSet();
            mFocusAnimator.playTogether(backgroundColor, translation);
            mFocusAnimator.setStartDelay(750);
            mFocusAnimator.setDuration(750);
            mFocusAnimator.start();
        } else if (isRunning) {
            // Restore the background color
            int currentColor = mBackgroundColor;
            ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(), currentColor,
                    mCurrentPrimaryColor);
            backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int color = (int) animation.getAnimatedValue();
                    mBackgroundColorDrawable.setColor(color);
                    mBackgroundColor = color;
                }
            });

            // Restore the translation
            ObjectAnimator translation = ObjectAnimator.ofFloat(this, "translationZ", 0f);

            mFocusAnimator = new AnimatorSet();
            mFocusAnimator.playTogether(backgroundColor, translation);
            mFocusAnimator.setDuration(150);
            mFocusAnimator.start();
        }
    }
}