org.chromium.chrome.browser.widget.ClipDrawableProgressBar.java Source code

Java tutorial

Introduction

Here is the source code for org.chromium.chrome.browser.widget.ClipDrawableProgressBar.java

Source

// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ColorDrawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

import org.chromium.chrome.R;

/**
 * An alternative progress bar implemented using ClipDrawable for simplicity and performance.
 */
public class ClipDrawableProgressBar extends ImageView {
    /**
     * Structure that has complete {@link ClipDrawableProgressBar} drawing information.
     */
    public static class DrawingInfo {
        public final Rect progressBarRect = new Rect();
        public final Rect progressBarBackgroundRect = new Rect();

        public int progressBarColor;
        public int progressBarBackgroundColor;
    }

    // ClipDrawable's max is a fixed constant 10000.
    // http://developer.android.com/reference/android/graphics/drawable/ClipDrawable.html
    private static final int CLIP_DRAWABLE_MAX = 10000;

    private final ColorDrawable mForegroundDrawable;
    private int mBackgroundColor = Color.TRANSPARENT;
    private float mProgress;
    private int mProgressUpdateCount;
    private int mDesiredVisibility;

    /**
     * Interface for listening to drawing invalidation.
     */
    public interface InvalidationListener {
        /**
         * Called on drawing invalidation.
         * @param dirtyRect Invalidated area.
         */
        void onInvalidation(Rect dirtyRect);
    }

    /**
     * Constructor for inflating from XML.
     */
    public ClipDrawableProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDesiredVisibility = getVisibility();

        assert attrs != null;
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ClipDrawableProgressBar, 0, 0);

        int foregroundColor = a.getColor(R.styleable.ClipDrawableProgressBar_progressBarColor, Color.TRANSPARENT);
        mBackgroundColor = a.getColor(R.styleable.ClipDrawableProgressBar_backgroundColor, Color.TRANSPARENT);
        assert foregroundColor != Color.TRANSPARENT;
        assert Color.alpha(
                foregroundColor) == 255 : "Currently ClipDrawableProgressBar only supports opaque progress bar color.";

        a.recycle();

        mForegroundDrawable = new ColorDrawable(foregroundColor);
        setImageDrawable(new ClipDrawable(mForegroundDrawable, Gravity.START, ClipDrawable.HORIZONTAL));
        setBackgroundColor(mBackgroundColor);
    }

    /**
     * Get the progress bar's current level of progress.
     *
     * @return The current progress, between 0.0 and 1.0.
     */
    public float getProgress() {
        return mProgress;
    }

    /**
     * Set the current progress to the specified value.
     *
     * @param progress The new progress, between 0.0 and 1.0.
     */
    public void setProgress(float progress) {
        assert 0.0f <= progress && progress <= 1.0f;
        if (mProgress == progress)
            return;

        mProgress = progress;
        mProgressUpdateCount += 1;
        getDrawable().setLevel(Math.round(progress * CLIP_DRAWABLE_MAX));
    }

    /**
     * @return Background color of this progress bar.
     */
    public int getProgressBarBackgroundColor() {
        return mBackgroundColor;
    }

    /**
     * @return Foreground color of the progress bar.
     */
    public int getForegroundColor() {
        return mForegroundDrawable.getColor();
    }

    /**
     * Get progress bar drawing information.
     * @param drawingInfoOut An instance that the result will be written.
     */
    public void getDrawingInfo(DrawingInfo drawingInfoOut) {
        int foregroundColor = mForegroundDrawable.getColor();
        float effectiveAlpha = getVisibility() == VISIBLE ? getAlpha() : 0.0f;
        drawingInfoOut.progressBarColor = applyAlpha(foregroundColor, effectiveAlpha);
        drawingInfoOut.progressBarBackgroundColor = applyAlpha(mBackgroundColor, effectiveAlpha);

        if (ViewCompat.getLayoutDirection(this) == LAYOUT_DIRECTION_LTR) {
            drawingInfoOut.progressBarRect.set(getLeft(), getTop(), getLeft() + Math.round(mProgress * getWidth()),
                    getBottom());
            drawingInfoOut.progressBarBackgroundRect.set(drawingInfoOut.progressBarRect.right, getTop(), getRight(),
                    getBottom());
        } else {
            drawingInfoOut.progressBarRect.set(getRight() - Math.round(mProgress * getWidth()), getTop(),
                    getRight(), getBottom());
            drawingInfoOut.progressBarBackgroundRect.set(getLeft(), getTop(), drawingInfoOut.progressBarRect.left,
                    getBottom());
        }
    }

    /**
     * Resets progress update count to 0.
     */
    public void resetProgressUpdateCount() {
        mProgressUpdateCount = 0;
    }

    /**
     * @return Progress update count since reset.
     */
    public int getProgressUpdateCount() {
        return mProgressUpdateCount;
    }

    private void updateInternalVisibility() {
        int oldVisibility = getVisibility();
        int newVisibility = mDesiredVisibility;
        if (getAlpha() == 0 && mDesiredVisibility == VISIBLE)
            newVisibility = INVISIBLE;
        if (oldVisibility != newVisibility)
            super.setVisibility(newVisibility);
    }

    private int applyAlpha(int color, float alpha) {
        return (Math.round(alpha * (color >>> 24)) << 24) | (0x00ffffff & color);
    }

    // View implementations.

    /**
     * Note that this visibility might not be respected for optimization. For example, if alpha
     * is 0, it will remain View#INVISIBLE even if this is called with View#VISIBLE.
     */
    @Override
    public void setVisibility(int visibility) {
        mDesiredVisibility = visibility;
        updateInternalVisibility();
    }

    @Override
    public void setBackgroundColor(int color) {
        if (color == Color.TRANSPARENT) {
            setBackground(null);
        } else {
            super.setBackgroundColor(color);
        }

        mBackgroundColor = color;
    }

    /**
     * Sets the color for the foreground (i.e. the moving part) of the progress bar.
     * @param color The new color of the progress bar foreground.
     */
    public void setForegroundColor(int color) {
        mForegroundDrawable.setColor(color);
    }

    @Override
    protected boolean onSetAlpha(int alpha) {
        updateInternalVisibility();
        return super.onSetAlpha(alpha);
    }
}