All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.holoeverywhere.widget.ProgressBar Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version

package org.holoeverywhere.widget;

import java.util.ArrayList;

import org.holoeverywhere.R;
import org.holoeverywhere.internal._View;
import org.holoeverywhere.util.Pool;
import org.holoeverywhere.util.Poolable;
import org.holoeverywhere.util.PoolableManager;
import org.holoeverywhere.util.Pools;
import org.holoeverywhere.util.ReflectHelper;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RotateDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build.VERSION;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;

public class ProgressBar extends _View {
    private class AccessibilityEventSender implements Runnable {
        @Override
        public void run() {
            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
        }
    }

    private static class RefreshData implements Poolable {
        private static final int POOL_MAX = 24;
        private static final Pool sPool = Pools
                .synchronizedPool(Pools.finitePool(
                        new PoolableManager() {
                            @Override
                            public RefreshData newInstance() {
                                return new RefreshData();
                            }

                            @Override
                            public void onAcquired(RefreshData element) {
                            }

                            @Override
                            public void onReleased(RefreshData element) {
                            }
                        }, RefreshData.POOL_MAX));

        public static RefreshData obtain(int id, int progress, boolean fromUser) {
            RefreshData rd = RefreshData.sPool.acquire();
            rd.id = id;
            rd.progress = progress;
            rd.fromUser = fromUser;
            return rd;
        }

        public boolean fromUser;
        public int id;
        private boolean mIsPooled;
        private RefreshData mNext;

        public int progress;

        @Override
        public RefreshData getNextPoolable() {
            return mNext;
        }

        @Override
        public boolean isPooled() {
            return mIsPooled;
        }

        public void recycle() {
            RefreshData.sPool.release(this);
        }

        @Override
        public void setNextPoolable(RefreshData element) {
            mNext = element;
        }

        @Override
        public void setPooled(boolean isPooled) {
            mIsPooled = isPooled;
        }
    }

    private class RefreshProgressRunnable implements Runnable {
        @Override
        public void run() {
            synchronized (ProgressBar.this) {
                final int count = mRefreshData.size();
                for (int i = 0; i < count; i++) {
                    final RefreshData rd = mRefreshData.get(i);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
                    rd.recycle();
                }
                mRefreshData.clear();
                mRefreshIsPosted = false;
            }
        }
    }

    protected static class SavedState extends BaseSavedState {
        public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
        int progress;

        int secondaryProgress;

        protected SavedState(Parcel in) {
            super(in);
            progress = in.readInt();
            secondaryProgress = in.readInt();
        }

        protected SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(progress);
            out.writeInt(secondaryProgress);
        }
    }

    private static final int MAX_LEVEL = 10000;
    private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
    private AccessibilityEventSender mAccessibilityEventSender;
    private AlphaAnimation mAnimation;
    private boolean mAttached;
    private int mBehavior;
    private Drawable mCurrentDrawable;
    private int mDuration;
    private boolean mHasAnimation;
    private boolean mIndeterminate;
    private Drawable mIndeterminateDrawable;
    private boolean mInDrawing;
    private Interpolator mInterpolator;
    private int mMax;
    protected int mMinWidth, mMaxWidth, mMinHeight, mMaxHeight;
    private boolean mNoInvalidate;
    private boolean mOnlyIndeterminate;
    private int mProgress;
    private Drawable mProgressDrawable;
    private final ArrayList mRefreshData = new ArrayList();
    private boolean mRefreshIsPosted;
    private RefreshProgressRunnable mRefreshProgressRunnable;
    private Bitmap mSampleTile;

    private int mSecondaryProgress;

    private boolean mShouldStartAnimationDrawable;

    private Transformation mTransformation;

    private long mUiThreadId;

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

    public ProgressBar(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.progressBarStyle);
    }

    public ProgressBar(Context context, AttributeSet attrs, int defStyle) {
        this(context, attrs, defStyle, R.style.Holo_ProgressBar);
    }

    public ProgressBar(Context context, AttributeSet attrs, int defStyle,
            int styleRes) {
        super(context, attrs, defStyle);
        mUiThreadId = Thread.currentThread().getId();
        initProgressBar();
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ProgressBar, defStyle, styleRes);
        mNoInvalidate = true;

        Drawable drawable = getDrawable(a,
                R.styleable.ProgressBar_android_progressDrawable);
        if (drawable != null) {
            drawable = tileify(drawable, false);
            setProgressDrawable(drawable);
        }
        mDuration = a.getInt(
                R.styleable.ProgressBar_android_indeterminateDuration,
                mDuration);
        mMinWidth = a.getDimensionPixelSize(
                R.styleable.ProgressBar_android_minWidth, mMinWidth);
        mMaxWidth = a.getDimensionPixelSize(
                R.styleable.ProgressBar_android_maxWidth, mMaxWidth);
        mMinHeight = a.getDimensionPixelSize(
                R.styleable.ProgressBar_android_minHeight, mMinHeight);
        mMaxHeight = a.getDimensionPixelSize(
                R.styleable.ProgressBar_android_maxHeight, mMaxHeight);
        mBehavior = a.getInt(
                R.styleable.ProgressBar_android_indeterminateBehavior,
                mBehavior);
        final int resID = a.getResourceId(
                R.styleable.ProgressBar_android_interpolator,
                android.R.anim.linear_interpolator);
        if (resID > 0) {
            setInterpolator(context, resID);
        }
        setMax(a.getInt(R.styleable.ProgressBar_android_max, mMax));
        setProgress(a.getInt(R.styleable.ProgressBar_android_progress,
                mProgress));
        setSecondaryProgress(a.getInt(
                R.styleable.ProgressBar_android_secondaryProgress,
                mSecondaryProgress));
        drawable = getDrawable(a,
                R.styleable.ProgressBar_android_indeterminateDrawable);
        if (drawable != null) {
            drawable = tileifyIndeterminate(drawable);
            setIndeterminateDrawable(drawable);
        }
        mOnlyIndeterminate = a.getBoolean(
                R.styleable.ProgressBar_android_indeterminateOnly,
                mOnlyIndeterminate);
        mNoInvalidate = false;
        setIndeterminate(mOnlyIndeterminate
                || a.getBoolean(R.styleable.ProgressBar_android_indeterminate,
                        mIndeterminate));
        a.recycle();
    }

    private synchronized void doRefreshProgress(int id, int progress,
            boolean fromUser, boolean callBackToApp) {
        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
        final Drawable d = mCurrentDrawable;
        if (d != null) {
            Drawable progressDrawable = null;
            if (d instanceof LayerDrawable) {
                progressDrawable = ((LayerDrawable) d)
                        .findDrawableByLayerId(id);
            }
            final int level = (int) (scale * ProgressBar.MAX_LEVEL);
            (progressDrawable != null ? progressDrawable : d).setLevel(level);
        } else {
            invalidate();
        }
        if (callBackToApp && id == R.id.progress) {
            onProgressRefresh(scale, fromUser);
        }
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        updateDrawableState();
    }

    protected Drawable getCurrentDrawable() {
        return mCurrentDrawable;
    }

    // Very funny change android.RotateDrawable on custom RotateDrawable,
    // ported from JB
    private Drawable getDrawable(TypedArray a, int attr) {
        Drawable d = a.getDrawable(attr);
        try {
            int id = a.getResourceId(attr, 0);
            if ((id == R.drawable.progress_small_holo
                    || id == R.drawable.progress_medium_holo || id == R.drawable.progress_large_holo)
                    && VERSION.SDK_INT < 14) {
                LayerDrawable layers = (LayerDrawable) d;
                int layersCount = layers.getNumberOfLayers();
                Drawable[] newLayers = new Drawable[layersCount];
                for (int i = 0; i < layersCount; i++) {
                    Drawable layer = layers.getDrawable(i);
                    if (layer instanceof RotateDrawable && (i == 0 || i == 1)) {
                        org.holoeverywhere.drawable.RotateDrawable r = new org.holoeverywhere.drawable.RotateDrawable();
                        Drawable rotatedDrawable = ((RotateDrawable) layer)
                                .getDrawable();
                        if (i == 0) {
                            r.setState(rotatedDrawable, true, true, 0.5f, 0.5f,
                                    0f, 1080f);
                        } else if (i == 1) {
                            r.setState(rotatedDrawable, true, true, 0.5f, 0.5f,
                                    720f, 0f);
                        }
                        layer = r;
                    }
                    newLayers[i] = layer;
                }
                return new LayerDrawable(newLayers);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return d;
    }

    private Shape getDrawableShape() {
        final float[] roundedCorners = new float[] {
                5, 5, 5, 5, 5, 5, 5, 5
        };
        return new RoundRectShape(roundedCorners, null, null);
    }

    public Drawable getIndeterminateDrawable() {
        return mIndeterminateDrawable;
    }

    public Interpolator getInterpolator() {
        return mInterpolator;
    }

    @ViewDebug.ExportedProperty(category = "progress")
    public synchronized int getMax() {
        return mMax;
    }

    @ViewDebug.ExportedProperty(category = "progress")
    public synchronized int getProgress() {
        return mIndeterminate ? 0 : mProgress;
    }

    public Drawable getProgressDrawable() {
        return mProgressDrawable;
    }

    public int getResolvedLayoutDirection() {
        return 0;
    }

    public int getResolvedLayoutDirection(Drawable who) {
        return who == mProgressDrawable || who == mIndeterminateDrawable ? getResolvedLayoutDirection()
                : 0;
    }

    @ViewDebug.ExportedProperty(category = "progress")
    public synchronized int getSecondaryProgress() {
        return mIndeterminate ? 0 : mSecondaryProgress;
    }

    public synchronized final void incrementProgressBy(int diff) {
        setProgress(mProgress + diff);
    }

    public synchronized final void incrementSecondaryProgressBy(int diff) {
        setSecondaryProgress(mSecondaryProgress + diff);
    }

    private void initProgressBar() {
        mMax = 100;
        mProgress = 0;
        mSecondaryProgress = 0;
        mIndeterminate = false;
        mOnlyIndeterminate = false;
        mDuration = 4000;
        mBehavior = Animation.RESTART;
        mMinWidth = 24;
        mMaxWidth = 48;
        mMinHeight = 24;
        mMaxHeight = 48;
    }

    @Override
    public void invalidateDrawable(Drawable dr) {
        if (!mInDrawing) {
            if (verifyDrawable(dr)) {
                final Rect dirty = dr.getBounds();
                final int scrollX = getScrollX() + getPaddingLeft();
                final int scrollY = getScrollY() + getPaddingTop();

                invalidate(dirty.left + scrollX, dirty.top + scrollY,
                        dirty.right + scrollX, dirty.bottom + scrollY);
            } else {
                super.invalidateDrawable(dr);
            }
        }
    }

    @ViewDebug.ExportedProperty(category = "progress")
    public synchronized boolean isIndeterminate() {
        return mIndeterminate;
    }

    @SuppressLint("NewApi")
    @Override
    public void jumpDrawablesToCurrentState() {
        super.jumpDrawablesToCurrentState();
        if (mProgressDrawable != null) {
            mProgressDrawable.jumpToCurrentState();
        }
        if (mIndeterminateDrawable != null) {
            mIndeterminateDrawable.jumpToCurrentState();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mIndeterminate) {
            startAnimation();
        }
        if (mRefreshData != null) {
            synchronized (this) {
                final int count = mRefreshData.size();
                for (int i = 0; i < count; i++) {
                    final RefreshData rd = mRefreshData.get(i);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
                    rd.recycle();
                }
                mRefreshData.clear();
            }
        }
        mAttached = true;
    }

    @Override
    protected void onDetachedFromWindow() {
        if (mIndeterminate) {
            stopAnimation();
        }
        if (mRefreshProgressRunnable != null) {
            removeCallbacks(mRefreshProgressRunnable);
        }
        if (mRefreshProgressRunnable != null && mRefreshIsPosted) {
            removeCallbacks(mRefreshProgressRunnable);
        }
        if (mAccessibilityEventSender != null) {
            removeCallbacks(mAccessibilityEventSender);
        }
        super.onDetachedFromWindow();
        mAttached = false;
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Drawable d = mCurrentDrawable;
        if (d != null) {
            canvas.save();
            canvas.translate(getPaddingLeft(), getPaddingTop());
            long time = getDrawingTime();
            if (mHasAnimation) {
                mAnimation.getTransformation(time, mTransformation);
                float scale = mTransformation.getAlpha();
                try {
                    mInDrawing = true;
                    d.setLevel((int) (scale * ProgressBar.MAX_LEVEL));
                } finally {
                    mInDrawing = false;
                }
                postInvalidate();
            }
            d.draw(canvas);
            canvas.restore();
            if (mShouldStartAnimationDrawable && d instanceof Animatable) {
                ((Animatable) d).start();
                mShouldStartAnimationDrawable = false;
            }
        }
    }

    @SuppressLint("NewApi")
    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        event.setClassName(ProgressBar.class.getName());
        event.setItemCount(mMax);
        event.setCurrentItemIndex(mProgress);
    }

    @Override
    @SuppressLint("NewApi")
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(ProgressBar.class.getName());
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec,
            int heightMeasureSpec) {
        Drawable d = mCurrentDrawable;
        int dw = 0;
        int dh = 0;
        if (d != null) {
            dw = Math
                    .max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
            dh = Math.max(mMinHeight,
                    Math.min(mMaxHeight, d.getIntrinsicHeight()));
        }
        updateDrawableState();
        dw += getPaddingLeft() + getPaddingRight();
        dh += getPaddingTop() + getPaddingBottom();
        setMeasuredDimension(
                _View.supportResolveSizeAndState(dw, widthMeasureSpec, 0),
                _View.supportResolveSizeAndState(dh, heightMeasureSpec, 0));
    }

    protected void onProgressRefresh(float scale, boolean fromUser) {
        try {
            if (((AccessibilityManager) AccessibilityManager.class.getMethod(
                    "getInstance", Context.class).invoke(null, getContext()))
                    .isEnabled()) {
                scheduleAccessibilityEventSender();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        setProgress(ss.progress);
        setSecondaryProgress(ss.secondaryProgress);
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.progress = mProgress;
        ss.secondaryProgress = mSecondaryProgress;
        return ss;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        updateDrawableBounds(w, h);
    }

    @Override
    public void onVisibilityChanged(_View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (mIndeterminate) {
            if (visibility == android.view.View.GONE
                    || visibility == android.view.View.INVISIBLE) {
                stopAnimation();
            } else {
                startAnimation();
            }
        }
    }

    @Override
    public void postInvalidate() {
        if (!mNoInvalidate) {
            super.postInvalidate();
        }
    }

    private synchronized void refreshProgress(int id, int progress,
            boolean fromUser) {
        if (mUiThreadId == Thread.currentThread().getId()) {
            doRefreshProgress(id, progress, fromUser, true);
        } else {
            if (mRefreshProgressRunnable == null) {
                mRefreshProgressRunnable = new RefreshProgressRunnable();
            }

            final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
            mRefreshData.add(rd);
            if (mAttached && !mRefreshIsPosted) {
                post(mRefreshProgressRunnable);
                mRefreshIsPosted = true;
            }
        }
    }

    private void scheduleAccessibilityEventSender() {
        if (mAccessibilityEventSender == null) {
            mAccessibilityEventSender = new AccessibilityEventSender();
        } else {
            removeCallbacks(mAccessibilityEventSender);
        }
        postDelayed(mAccessibilityEventSender,
                ProgressBar.TIMEOUT_SEND_ACCESSIBILITY_EVENT);
    }

    public synchronized void setIndeterminate(boolean indeterminate) {
        if ((!mOnlyIndeterminate || !mIndeterminate)
                && indeterminate != mIndeterminate) {
            mIndeterminate = indeterminate;

            if (indeterminate) {
                // swap between indeterminate and regular backgrounds
                mCurrentDrawable = mIndeterminateDrawable;
                startAnimation();
            } else {
                mCurrentDrawable = mProgressDrawable;
                stopAnimation();
            }
        }
    }

    public void setIndeterminateDrawable(Drawable d) {
        if (d != null) {
            d.setCallback(this);
        }
        mIndeterminateDrawable = d;
        if (mIndeterminate) {
            mCurrentDrawable = d;
            postInvalidate();
        }
    }

    public void setInterpolator(Context context, int resID) {
        setInterpolator(AnimationUtils.loadInterpolator(context, resID));
    }

    public void setInterpolator(Interpolator interpolator) {
        mInterpolator = interpolator;
    }

    public synchronized void setMax(int max) {
        if (max < 0) {
            max = 0;
        }
        if (max != mMax) {
            mMax = max;
            postInvalidate();

            if (mProgress > max) {
                mProgress = max;
            }
            refreshProgress(R.id.progress, mProgress, false);
        }
    }

    public synchronized void setProgress(int progress) {
        setProgress(progress, false);
    }

    synchronized void setProgress(int progress, boolean fromUser) {
        if (mIndeterminate) {
            return;
        }
        if (progress < 0) {
            progress = 0;
        }
        if (progress > mMax) {
            progress = mMax;
        }
        if (progress != mProgress) {
            mProgress = progress;
            refreshProgress(R.id.progress, mProgress, fromUser);
        }
    }

    public void setProgressDrawable(Drawable d) {
        boolean needUpdate;
        if (mProgressDrawable != null && d != mProgressDrawable) {
            mProgressDrawable.setCallback(null);
            needUpdate = true;
        } else {
            needUpdate = false;
        }
        if (d != null) {
            d.setCallback(this);
            int drawableHeight = d.getMinimumHeight();
            if (mMaxHeight < drawableHeight) {
                mMaxHeight = drawableHeight;
                requestLayout();
            }
        }
        mProgressDrawable = d;
        if (!mIndeterminate) {
            mCurrentDrawable = d;
            postInvalidate();
        }
        if (needUpdate) {
            updateDrawableBounds(getWidth(), getHeight());
            updateDrawableState();
            doRefreshProgress(R.id.progress, mProgress, false, false);
            doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress,
                    false, false);
        }
    }

    public synchronized void setSecondaryProgress(int secondaryProgress) {
        if (mIndeterminate) {
            return;
        }
        if (secondaryProgress < 0) {
            secondaryProgress = 0;
        }
        if (secondaryProgress > mMax) {
            secondaryProgress = mMax;
        }
        if (secondaryProgress != mSecondaryProgress) {
            mSecondaryProgress = secondaryProgress;
            refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
        }
    }

    @Override
    public void setVisibility(int v) {
        if (getVisibility() != v) {
            super.setVisibility(v);
            if (mIndeterminate) {
                if (v == android.view.View.GONE
                        || v == android.view.View.INVISIBLE) {
                    stopAnimation();
                } else {
                    startAnimation();
                }
            }
        }
    }

    void startAnimation() {
        if (getVisibility() != android.view.View.VISIBLE) {
            return;
        }
        if (mIndeterminateDrawable instanceof Animatable) {
            mShouldStartAnimationDrawable = true;
            mHasAnimation = false;
        } else {
            mHasAnimation = true;
            if (mInterpolator == null) {
                mInterpolator = new LinearInterpolator();
            }
            if (mTransformation == null) {
                mTransformation = new Transformation();
            } else {
                mTransformation.clear();
            }
            if (mAnimation == null) {
                mAnimation = new AlphaAnimation(0.0f, 1.0f);
            } else {
                mAnimation.reset();
            }
            mAnimation.setRepeatMode(mBehavior);
            mAnimation.setRepeatCount(Animation.INFINITE);
            mAnimation.setDuration(mDuration);
            mAnimation.setInterpolator(mInterpolator);
            mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
        }
        postInvalidate();
    }

    void stopAnimation() {
        mHasAnimation = false;
        if (mIndeterminateDrawable instanceof Animatable) {
            ((Animatable) mIndeterminateDrawable).stop();
            mShouldStartAnimationDrawable = false;
        }
        postInvalidate();
    }

    private Drawable tileify(Drawable drawable, boolean clip) {
        if (drawable instanceof LayerDrawable) {
            LayerDrawable background = (LayerDrawable) drawable;
            final int N = background.getNumberOfLayers();
            Drawable[] outDrawables = new Drawable[N];
            for (int i = 0; i < N; i++) {
                int id = background.getId(i);
                outDrawables[i] = tileify(background.getDrawable(i),
                        id == R.id.progress || id == R.id.secondaryProgress);
            }
            LayerDrawable newBg = new LayerDrawable(outDrawables);
            for (int i = 0; i < N; i++) {
                newBg.setId(i, background.getId(i));
            }
            return newBg;
        } else if (drawable instanceof StateListDrawable) {
            StateListDrawable in = (StateListDrawable) drawable;
            StateListDrawable out = new StateListDrawable();
            int numStates = ReflectHelper
                    .invoke(in, "getStateCount", int.class);
            for (int i = 0; i < numStates; i++) {
                out.addState(
                        ReflectHelper.invoke(in, "getStateSet", int[].class, i),
                        tileify(ReflectHelper.invoke(in, "getStateDrawable",
                                Drawable.class, i), clip));
            }
            return out;
        } else if (drawable instanceof BitmapDrawable) {
            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
            if (mSampleTile == null) {
                mSampleTile = tileBitmap;
            }
            final ShapeDrawable shapeDrawable = new ShapeDrawable(
                    getDrawableShape());
            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
            shapeDrawable.getPaint().setShader(bitmapShader);
            return clip ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
                    ClipDrawable.HORIZONTAL) : shapeDrawable;
        }
        return drawable;
    }

    private Drawable tileifyIndeterminate(Drawable drawable) {
        if (drawable instanceof AnimationDrawable) {
            AnimationDrawable background = (AnimationDrawable) drawable;
            final int N = background.getNumberOfFrames();
            AnimationDrawable newBg = new AnimationDrawable();
            newBg.setOneShot(background.isOneShot());
            for (int i = 0; i < N; i++) {
                Drawable frame = tileify(background.getFrame(i), true);
                frame.setLevel(10000);
                newBg.addFrame(frame, background.getDuration(i));
            }
            newBg.setLevel(10000);
            drawable = newBg;
        }
        return drawable;
    }

    private void updateDrawableBounds(int w, int h) {
        int right = w - getPaddingRight() - getPaddingLeft();
        int bottom = h - getPaddingBottom() - getPaddingTop();
        int top = 0;
        int left = 0;
        if (mIndeterminateDrawable != null) {
            if (mOnlyIndeterminate
                    && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
                final int intrinsicWidth = mIndeterminateDrawable
                        .getIntrinsicWidth();
                final int intrinsicHeight = mIndeterminateDrawable
                        .getIntrinsicHeight();
                final float intrinsicAspect = (float) intrinsicWidth
                        / intrinsicHeight;
                final float boundAspect = (float) w / h;
                if (intrinsicAspect != boundAspect) {
                    if (boundAspect > intrinsicAspect) {
                        final int width = (int) (h * intrinsicAspect);
                        left = (w - width) / 2;
                        right = left + width;
                    } else {
                        final int height = (int) (w * (1 / intrinsicAspect));
                        top = (h - height) / 2;
                        bottom = top + height;
                    }
                }
            }
            mIndeterminateDrawable.setBounds(left, top, right, bottom);
        }
        if (mProgressDrawable != null) {
            mProgressDrawable.setBounds(0, 0, right, bottom);
        }
    }

    private void updateDrawableState() {
        int[] state = getDrawableState();
        if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
            mProgressDrawable.setState(state);
        }
        if (mIndeterminateDrawable != null
                && mIndeterminateDrawable.isStateful()) {
            mIndeterminateDrawable.setState(state);
        }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return who == mProgressDrawable || who == mIndeterminateDrawable
                || super.verifyDrawable(who);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy