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