content: /*
   * Copyright (C) 2016 Abhay Raj Singh Yadav
   *
   * Licensed 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 com.arsy.maps_library;
  
  import android.animation.ValueAnimator;
  import android.content.Context;
  import android.graphics.Color;
  import android.graphics.drawable.GradientDrawable;
  import android.os.Handler;
  import android.support.v4.content.ContextCompat;
  
  import com.google.android.gms.maps.GoogleMap;
  import com.google.android.gms.maps.model.BitmapDescriptor;
  import com.google.android.gms.maps.model.GroundOverlay;
  import com.google.android.gms.maps.model.GroundOverlayOptions;
  import com.google.android.gms.maps.model.LatLng;
  
  /**
   * Created by abhay yadav on 12-Jan-17.
   */
  public class MapRadar {
      private GoogleMap mGoogleMap;
      private LatLng mLatLng, mPrevLatLng;
      private BitmapDescriptor mBackgroundImageDescriptor, mBackgroundImageSweepDescriptor;             //ripple image.
      private float mTransparency = 0.5f;                                 //transparency of image.
      private volatile int mDistance = 2000;                              //distance to which ripple should be shown in metres
      private int mFillColor = Color.TRANSPARENT;                         //fill color of circle
      private int mStrokeColor = 0x38728f;                                //border color of circle
      private int mStrokeWidth = 4;                                       //border width of circle
      private GradientDrawable mOuterDrawable;
      private boolean isAnimationRunning = false;
      private Handler mSweepHandler, mOuterHandler;
      private int mRotationAngle = 0;
      private boolean isThreeSixty = false;
      private GroundOverlay mGroundOverlaySweep, mGroundOverlay;
      private ValueAnimator mAnimatorSweep;
      private float mSweepTransparency = 0.5f;                            //transparency of image.
      private boolean mSweepAnimationClockwiseAnticlockwise = false;
      private int mSweepAnimationClockwiseAnticlockwiseDuration = 1;
      private int mSweepSpeed = 2;                                        //increase this to increase speed
      private int mCurrentAngle = 0;
      private int mColors[] = {0x0038728f, 0xff38728f};                   //sweep animation colors
  
      public MapRadar(GoogleMap googleMap, LatLng latLng, Context context) {
          mGoogleMap = googleMap;
          mLatLng = latLng;
          mPrevLatLng = latLng;
          mOuterDrawable = (GradientDrawable) ContextCompat.getDrawable(context, R.drawable.background);
      }
  
      /**
       * @return current duration of animation
       */
      public int getClockwiseAnticlockwiseDuration() {
          return mSweepAnimationClockwiseAnticlockwiseDuration;
      }
  
      /**
       * @return current radar rotation speed
       */
      public int getRadarSpeed() {
          return mSweepSpeed;
      }
  
      /**
       * @return current state of both side rotation
       */
      public boolean isRadarAnimationClockWiseAnticlockwise() {
          return mSweepAnimationClockwiseAnticlockwise;
      }
  
      /**
       * @return current state of animation
       */
      public boolean isAnimationRunning() {
          return isAnimationRunning;
      }
  
      /**
       * @param transparency sets end transparency for circle
       */
      public MapRadar withOuterCircleTransparency(float transparency) {
          mTransparency = transparency;
          return this;
      }
  
      /**
       * @param transparency sets transparency for background of circle
       */
      public MapRadar withRadarTransparency(float transparency) {
          mSweepTransparency = transparency;
          return this;
      }
  
      /**
       * @param sweepAnimationClockWiseAnticlockwise enable both side rotation
       */
      public MapRadar withClockwiseAnticlockwise(boolean sweepAnimationClockWiseAnticlockwise) {
          mSweepAnimationClockwiseAnticlockwise = sweepAnimationClockWiseAnticlockwise;
          return this;
      }
  
      /**
       * @deprecated use {@link #withClockwiseAnticlockwise(boolean)} instead
       */
      @Deprecated
      public void withClockWiseAnticlockwise(boolean sweepAnimationClockWiseAnticlockwise) {
          withClockwiseAnticlockwise(sweepAnimationClockWiseAnticlockwise);
      }
  
      /**
       * @param sweepAnimationClockWiseAnticlockwiseDuration duration of animation
       */
      public MapRadar withClockwiseAnticlockwiseDuration(int sweepAnimationClockWiseAnticlockwiseDuration) {
          mSweepAnimationClockwiseAnticlockwiseDuration = sweepAnimationClockWiseAnticlockwiseDuration;
          return this;
      }
  
      /**
       * @param startColor start color of radar gradient
       * @param tailColor  end color of radar gradient
       */
      public MapRadar withRadarColors(int startColor, int tailColor) {
          mColors[0] = startColor;
          mColors[1] = tailColor;
          return this;
      }
  
      /**
       * @param sweepSpeed radar rotation speed
       */
      public MapRadar withRadarSpeed(int sweepSpeed) {
          mSweepSpeed = sweepSpeed;
          return this;
      }
  
      /**
       * @param distance sets radius distance for circle
       */
      public MapRadar withDistance(int distance) {
          if (distance < 200) {
              distance = 200;
          }
          mDistance = distance;
          return this;
      }
  
      /**
       * @param latLng sets position for center of circle
       */
      public MapRadar withLatLng(LatLng latLng) {
          mPrevLatLng = mLatLng;
          mLatLng = latLng;
          return this;
      }
  
      /**
       * @param fillColor inner color of circle
       */
      public MapRadar withOuterCircleFillColor(int fillColor) {
          mFillColor = fillColor;
          return this;
      }
  
      /**
       * @param strokeColor color of circle stroke
       */
      public MapRadar withOuterCircleStrokeColor(int strokeColor) {
          mStrokeColor = strokeColor;
          return this;
      }
  
      @Deprecated
      public void withOuterCircleStrokewidth(int strokeWidth) {
          withOuterCircleStrokeWidth(strokeWidth);
      }
  
      /**
       * @param strokeWidth width of circle stroke
       */
      public MapRadar withOuterCircleStrokeWidth(int strokeWidth) {
          mStrokeWidth = strokeWidth;
          return this;
      }
  
      private final Runnable mSweepRunnable = new Runnable() {
          @Override
          public void run() {
              mGroundOverlaySweep = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
                      .position(mLatLng, mDistance)
                      .transparency(mSweepTransparency)
                      .image(mBackgroundImageSweepDescriptor));
              AnimateSweep();
          }
      };
  
      private final Runnable mRadarRunnable = new Runnable() {
          @Override
          public void run() {
              mGroundOverlay = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
                      .position(mLatLng, mDistance + mStrokeWidth)
                      .transparency(mTransparency)
                      .image(mBackgroundImageDescriptor));
          }
      };
  
      private void AnimateSweep() {
          mAnimatorSweep = ValueAnimator.ofInt(0, 360);
          mAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE);
          mAnimatorSweep.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator valueAnimator) {
                  if (mSweepAnimationClockwiseAnticlockwise) {
                      if ((mCurrentAngle) >= (360 * 2 * mSweepAnimationClockwiseAnticlockwiseDuration)) {
                          isThreeSixty = true;
                      }
                      if (mCurrentAngle <= 0) {
                          isThreeSixty = false;
                      }
                      if (isThreeSixty) {
                          mRotationAngle = (mRotationAngle - mSweepSpeed) % 360;
                          mCurrentAngle = mCurrentAngle - mSweepSpeed;
                      } else {
                          mRotationAngle = (mRotationAngle + mSweepSpeed) % 360;
                          mCurrentAngle = mCurrentAngle + mSweepSpeed;
                      }
                  } else {
                      mRotationAngle = (mRotationAngle + mSweepSpeed) % 360;
                  }
                  mGroundOverlaySweep.setBearing(mRotationAngle);
                  if (mLatLng != mPrevLatLng) {
                      mGroundOverlaySweep.setPosition(mLatLng);
                  }
              }
          });
          mAnimatorSweep.start();
      }
  
      private void setDrawableAndBitmap() {
          mOuterDrawable.setColor(mFillColor);
          mOuterDrawable.setStroke(UiUtil.dpToPx(mStrokeWidth), mStrokeColor);
          mBackgroundImageDescriptor = UiUtil.drawableToBitmapDescriptor(mOuterDrawable);
          GradientDrawable radarDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, mColors);
          radarDrawable.setGradientType(GradientDrawable.SWEEP_GRADIENT);
          radarDrawable.setShape(GradientDrawable.OVAL);
          radarDrawable.setSize(1200, 1200);
          mBackgroundImageSweepDescriptor = UiUtil.drawableToBitmapDescriptor(radarDrawable);
      }
  
      /**
       * Starts animation
       */
      public void startRadarAnimation() {
          setDrawableAndBitmap();
          if (!isAnimationRunning) {
              mSweepHandler = new Handler();
              mSweepHandler.post(mSweepRunnable);
              mOuterHandler = new Handler();
              mOuterHandler.post(mRadarRunnable);
              isAnimationRunning = true;
          }
      }
  
      /**
       * Stops current animation if it's running
       */
      public void stopRadarAnimation() {
          if (isAnimationRunning) {
              mSweepHandler.removeCallbacks(mSweepRunnable);
              mAnimatorSweep.cancel();
              mGroundOverlaySweep.remove();
              mOuterHandler.removeCallbacks(mRadarRunnable);
              mGroundOverlay.remove();
              isAnimationRunning = false;
          }
      }
  }
  