content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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 org.apache.weex.ui.view.refresh.circlebar;
  
  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.RadialGradient;
  import android.graphics.Shader;
  import android.graphics.drawable.ShapeDrawable;
  import android.graphics.drawable.shapes.OvalShape;
  import android.support.v4.view.ViewCompat;
  import android.util.AttributeSet;
  import android.view.animation.Animation;
  import android.widget.ImageView;
  
  /**
   * Modify of android.support.v4
   */
  @SuppressLint("AppCompatCustomView")
  public class CircleProgressBar extends ImageView {
  
    private static final int KEY_SHADOW_COLOR = 0x1E000000;
    private static final int FILL_SHADOW_COLOR = 0x3D000000;
    private static final float X_OFFSET = 0f;
    private static final float Y_OFFSET = 1.75f;
    private static final float SHADOW_RADIUS = 3.5f;
    private static final int SHADOW_ELEVATION = 4;
  
    public static final int DEFAULT_CIRCLE_BG_LIGHT = 0xFFFAFAFA;
    public static final int DEFAULT_CIRCLE_COLOR = 0xFFF00000;
    private static final int DEFAULT_CIRCLE_DIAMETER = 40;
    private static final int STROKE_WIDTH_LARGE = 3;
  
    private Animation.AnimationListener mListener;
    private int mShadowRadius;
    private int mBackGroundColor;
    private int mProgressColor;
    private int mProgressStokeWidth;
    private int mArrowWidth;
    private int mArrowHeight;
    private int mProgress;
    private int mMax;
    private int mDiameter;
    private int mInnerRadius;
    private boolean mShowArrow;
    public MaterialProgressDrawable mProgressDrawable;
    private ShapeDrawable mBgCircle;
    private boolean mCircleBackgroundEnabled;
    private int[] mColors = new int[]{Color.BLACK};
  
    public CircleProgressBar(Context context) {
      super(context);
      init(context, null, 0);
  
    }
  
    public CircleProgressBar(Context context, AttributeSet attrs) {
      super(context, attrs);
      init(context, attrs, 0);
  
    }
  
    public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init(context, attrs, defStyleAttr);
    }
  
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
  
      final float density = getContext().getResources().getDisplayMetrics().density;
      mBackGroundColor = DEFAULT_CIRCLE_BG_LIGHT;
      mProgressColor = DEFAULT_CIRCLE_COLOR;
      mColors = new int[]{mProgressColor};
      mInnerRadius = -1;
      mProgressStokeWidth = (int) (STROKE_WIDTH_LARGE * density);
      mArrowWidth =  -1;
      mArrowHeight = -1;
      mShowArrow = true;
      mCircleBackgroundEnabled = true;
      mProgress = 0;
      mMax = 100;
      mProgressDrawable = new MaterialProgressDrawable(getContext(), this);
      super.setImageDrawable(mProgressDrawable);
    }
  
    public void setProgressBackGroundColor(int color) {
      this.mBackGroundColor = color;
    }
  
    private boolean elevationSupported() {
      return android.os.Build.VERSION.SDK_INT >= 21;
    }
  
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      if (!elevationSupported()) {
        setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight()
                                                                     + mShadowRadius * 2);
      }
    }
  
    public int getProgressStokeWidth() {
      return mProgressStokeWidth;
    }
  
    public void setProgressStokeWidth(int mProgressStokeWidth) {
      final float density = getContext().getResources().getDisplayMetrics().density;
      this.mProgressStokeWidth = (int) (mProgressStokeWidth * density);
    }
  
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
      super.onLayout(changed, left, top, right, bottom);
      final float density = getContext().getResources().getDisplayMetrics().density;
      mDiameter = Math.min(getMeasuredWidth(), getMeasuredHeight());
      if (mDiameter <= 0) {
        mDiameter = (int) density * DEFAULT_CIRCLE_DIAMETER;
      }
      if (getBackground() == null && mCircleBackgroundEnabled) {
        final int shadowYOffset = (int) (density * Y_OFFSET);
        final int shadowXOffset = (int) (density * X_OFFSET);
        mShadowRadius = (int) (density * SHADOW_RADIUS);
  
        if (elevationSupported()) {
          if(mBgCircle == null) {
            mBgCircle = new ShapeDrawable(new OvalShape());
          }
          ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
        } else {
          if(!(mBgCircle != null &&
              mBgCircle.getShape() instanceof  OvalShadow &&
              ((OvalShadow) mBgCircle.getShape()).mCircleDiameter == (mDiameter - mShadowRadius * 2) &&
              ((OvalShadow) mBgCircle.getShape()).mShadowRadius == mShadowRadius)) {
            OvalShape oval = new OvalShadow(mShadowRadius, mDiameter - mShadowRadius * 2);
            mBgCircle = new ShapeDrawable(oval);
          }
          ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, mBgCircle.getPaint());
          mBgCircle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
                                              KEY_SHADOW_COLOR);
          final int padding = (int) mShadowRadius;
          // set padding so the inner image sits correctly within the shadow.
          setPadding(padding, padding, padding, padding);
        }
        mBgCircle.getPaint().setColor(mBackGroundColor);
        setBackgroundDrawable(mBgCircle);
      }
      mProgressDrawable.setBackgroundColor(mBackGroundColor);
      mProgressDrawable.setColorSchemeColors(mColors);
      if (isShowArrow()) {
        mProgressDrawable.setArrowScale(1f);
        mProgressDrawable.showArrow(true);
      }
      super.setImageDrawable(null);
      super.setImageDrawable(mProgressDrawable);
      mProgressDrawable.setAlpha(255);
      if (getVisibility() == VISIBLE) {
        mProgressDrawable.setStartEndTrim(0, (float) 0.8);
      }
    }
  
    public boolean isShowArrow() {
      return mShowArrow;
    }
  
    public void setShowArrow(boolean showArrow) {
      this.mShowArrow = showArrow;
    }
  
    public void setAnimationListener(Animation.AnimationListener listener) {
      mListener = listener;
    }
  
    @Override
    public void onAnimationStart() {
      super.onAnimationStart();
      if (mListener != null) {
        mListener.onAnimationStart(getAnimation());
      }
    }
  
    @Override
    public void onAnimationEnd() {
      super.onAnimationEnd();
      if (mListener != null) {
        mListener.onAnimationEnd(getAnimation());
      }
    }
  
    /**
     * Set the colors used in the progress animation. The first
     * color will also be the color of the bar that grows in response to a user
     * swipe gesture.
     *
     * @param colors
     */
    public void setColorSchemeColors(int... colors) {
      mColors = colors;
      if (mProgressDrawable != null) {
        mProgressDrawable.setColorSchemeColors(colors);
      }
    }
  
    /**
     * Update the background color of the mBgCircle image view.
     */
    public void setBackgroundColorResource(int colorRes) {
      if (getBackground() instanceof ShapeDrawable) {
        final Resources res = getResources();
        ((ShapeDrawable) getBackground()).getPaint().setColor(res.getColor(colorRes));
      }
    }
  
    public void setBackgroundColor(int color) {
      if (getBackground() instanceof ShapeDrawable) {
        ((ShapeDrawable) getBackground()).getPaint().setColor(color);
      }
    }
  
    public int getMax() {
      return mMax;
    }
  
    public void setMax(int max) {
      mMax = max;
    }
  
    public int getProgress() {
      return mProgress;
    }
  
    public void setProgress(int progress) {
      if (getMax() > 0) {
        mProgress = progress;
      }
      invalidate();
    }
  
    public boolean circleBackgroundEnabled() {
      return mCircleBackgroundEnabled;
    }
  
    public void setCircleBackgroundEnabled(boolean enableCircleBackground) {
      this.mCircleBackgroundEnabled = enableCircleBackground;
    }
  
    @Override
    protected void onAttachedToWindow() {
      super.onAttachedToWindow();
      if (mProgressDrawable != null) {
        mProgressDrawable.stop();
        mProgressDrawable.setVisible(getVisibility() == VISIBLE, false);
      }
    }
  
    @Override
    protected void onDetachedFromWindow() {
      super.onDetachedFromWindow();
      if (mProgressDrawable != null) {
        mProgressDrawable.stop();
        mProgressDrawable.setVisible(false, false);
      }
    }
  
    private class OvalShadow extends OvalShape {
  
      private RadialGradient mRadialGradient;
      private int mShadowRadius;
      private Paint mShadowPaint;
      private int mCircleDiameter;
  
      public OvalShadow(int shadowRadius, int circleDiameter) {
        super();
        mShadowPaint = new Paint();
        mShadowRadius = shadowRadius;
        mCircleDiameter = circleDiameter;
        mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
                                             mShadowRadius, new int[]{
            FILL_SHADOW_COLOR, Color.TRANSPARENT
        }, null, Shader.TileMode.CLAMP);
        mShadowPaint.setShader(mRadialGradient);
      }
  
      @Override
      public void draw(Canvas canvas, Paint paint) {
        final int viewWidth = CircleProgressBar.this.getWidth();
        final int viewHeight = CircleProgressBar.this.getHeight();
        canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
                          mShadowPaint);
        canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
      }
    }
  
    public void start() {
      mProgressDrawable.start();
    }
  
    public void setStartEndTrim(float startAngle, float endAngle) {
      mProgressDrawable.setStartEndTrim(startAngle, endAngle);
    }
  
    public void stop() {
      mProgressDrawable.stop();
    }
  
    public void setProgressRotation(float rotation) {
      mProgressDrawable.setProgressRotation(rotation);
    }
  }
  