110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes/*
210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Copyright (C) 2015 The Android Open Source Project
310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * you may not use this file except in compliance with the License.
610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * You may obtain a copy of the License at
710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
1010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Unless required by applicable law or agreed to in writing, software
1110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
1210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * See the License for the specific language governing permissions and
1410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * limitations under the License.
1510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes */
1610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
1710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banespackage android.support.v7.widget;
1810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
1910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.Bitmap;
2010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.BitmapShader;
2110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.Shader;
2210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.AnimationDrawable;
2310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.BitmapDrawable;
2410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.ClipDrawable;
2510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.Drawable;
2610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.LayerDrawable;
2710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.ShapeDrawable;
2810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.shapes.RoundRectShape;
2910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.shapes.Shape;
3010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.support.v4.graphics.drawable.DrawableWrapper;
3110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.util.AttributeSet;
3210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.view.Gravity;
3310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.widget.ProgressBar;
3410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesclass AppCompatProgressBarHelper {
3610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private static final int[] TINT_ATTRS = {
3810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            android.R.attr.indeterminateDrawable,
3910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            android.R.attr.progressDrawable
4010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    };
4110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
4210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private final ProgressBar mView;
4310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
4410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private Bitmap mSampleTile;
4510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
464c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes    AppCompatProgressBarHelper(ProgressBar view) {
4710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        mView = view;
4810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
4910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
5010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
5110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
5210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                TINT_ATTRS, defStyleAttr, 0);
5310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
5410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        Drawable drawable = a.getDrawableIfKnown(0);
5510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable != null) {
5610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            mView.setIndeterminateDrawable(tileifyIndeterminate(drawable));
5710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
5810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
5910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        drawable = a.getDrawableIfKnown(1);
6010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable != null) {
6110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            mView.setProgressDrawable(tileify(drawable, false));
6210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
6310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
6410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        a.recycle();
6510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
6610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
6710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    /**
6810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     * Converts a drawable to a tiled version of itself. It will recursively
6910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     * traverse layer and state list drawables.
7010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     */
7110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private Drawable tileify(Drawable drawable, boolean clip) {
7210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable instanceof DrawableWrapper) {
7310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
7410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            if (inner != null) {
7510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                inner = tileify(inner, clip);
7610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                ((DrawableWrapper) drawable).setWrappedDrawable(inner);
7710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            }
7810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        } else if (drawable instanceof LayerDrawable) {
7910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            LayerDrawable background = (LayerDrawable) drawable;
8010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            final int N = background.getNumberOfLayers();
8110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            Drawable[] outDrawables = new Drawable[N];
8210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
8310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            for (int i = 0; i < N; i++) {
8410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                int id = background.getId(i);
8510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                outDrawables[i] = tileify(background.getDrawable(i),
8610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
8710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            }
8810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            LayerDrawable newBg = new LayerDrawable(outDrawables);
8910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
9010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            for (int i = 0; i < N; i++) {
9110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                newBg.setId(i, background.getId(i));
9210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            }
9310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
9410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            return newBg;
9510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
9610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        } else if (drawable instanceof BitmapDrawable) {
977c8ba0f0cd06a684132260d36840658be317d4c7Chris Banes            final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
987c8ba0f0cd06a684132260d36840658be317d4c7Chris Banes            final Bitmap tileBitmap = bitmapDrawable.getBitmap();
9910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            if (mSampleTile == null) {
10010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                mSampleTile = tileBitmap;
10110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            }
10210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
10310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
10410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
10510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
10610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            shapeDrawable.getPaint().setShader(bitmapShader);
1077c8ba0f0cd06a684132260d36840658be317d4c7Chris Banes            shapeDrawable.getPaint().setColorFilter(bitmapDrawable.getPaint().getColorFilter());
10810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
10910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                    ClipDrawable.HORIZONTAL) : shapeDrawable;
11010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
11110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
11210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        return drawable;
11310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
11410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
11510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    /**
11610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     * Convert a AnimationDrawable for use as a barberpole animation.
11710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     * Each frame of the animation is wrapped in a ClipDrawable and
11810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     * given a tiling BitmapShader.
11910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes     */
12010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private Drawable tileifyIndeterminate(Drawable drawable) {
12110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable instanceof AnimationDrawable) {
12210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            AnimationDrawable background = (AnimationDrawable) drawable;
12310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            final int N = background.getNumberOfFrames();
12410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            AnimationDrawable newBg = new AnimationDrawable();
12510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            newBg.setOneShot(background.isOneShot());
12610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
12710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            for (int i = 0; i < N; i++) {
12810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                Drawable frame = tileify(background.getFrame(i), true);
12910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                frame.setLevel(10000);
13010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes                newBg.addFrame(frame, background.getDuration(i));
13110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            }
13210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            newBg.setLevel(10000);
13310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            drawable = newBg;
13410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
13510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        return drawable;
13610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
13710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
13810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private Shape getDrawableShape() {
13910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
14010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        return new RoundRectShape(roundedCorners, null, null);
14110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
14210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
14310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    Bitmap getSampleTime() {
14410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        return mSampleTile;
14510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
14610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
14710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes}
148