content: package com.faceunity.nama.seekbar.internal;
  
  import android.content.Context;
  import android.content.res.ColorStateList;
  import android.content.res.TypedArray;
  import android.graphics.Canvas;
  import android.graphics.drawable.Drawable;
  import android.os.Build;
  import android.support.v4.view.ViewCompat;
  import android.util.AttributeSet;
  import android.util.DisplayMetrics;
  import android.view.Gravity;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.FrameLayout;
  import android.widget.TextView;
  
  
  import com.faceunity.nama.R;
  import com.faceunity.nama.seekbar.internal.compat.SeekBarCompat;
  import com.faceunity.nama.seekbar.internal.drawable.MarkerDrawable;
  
  
  /**
   * {@link ViewGroup} to be used as the real indicator.
   * <p>
   * I've used this to be able to accommodate the TextView
   * and the {@link  MarkerDrawable}
   * with the required positions and offsets
   * </p>
   *
   * @hide
   */
  public class Marker extends ViewGroup implements MarkerDrawable.MarkerAnimationListener {
      private static final int PADDING_DP = 1;
      private static final int ELEVATION_DP = 8;
      //The TextView to show the info
      private TextView mNumber;
      //The max width of this View
      private int mWidth;
      //some distance between the thumb and our bubble marker.
      //This will be added to our measured height
      private int mSeparation;
      MarkerDrawable mMarkerDrawable;
  
      public Marker(Context context, AttributeSet attrs, int defStyleAttr, String maxValue, int thumbSize, int separation) {
          super(context, attrs, defStyleAttr);
          //as we're reading the parent DiscreteSeekBar attributes, it may wrongly set this view's visibility.
          setVisibility(View.VISIBLE);
  
          DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DiscreteSeekBar,
                  R.attr.discreteSeekBarStyle, R.style.Widget_DiscreteSeekBar);
  
          int padding = (int) (PADDING_DP * displayMetrics.density) * 2;
          int textAppearanceId = a.getResourceId(R.styleable.DiscreteSeekBar_dsb_indicatorTextAppearance,
                  R.style.Widget_DiscreteIndicatorTextAppearance);
          mNumber = new TextView(context);
          //Add some padding to this textView so the bubble has some space to breath
          mNumber.setPadding(padding, 0, padding, 0);
          mNumber.setTextAppearance(context, textAppearanceId);
          mNumber.setGravity(Gravity.CENTER);
          mNumber.setText(maxValue);
          mNumber.setMaxLines(1);
          mNumber.setSingleLine(true);
          SeekBarCompat.setTextDirection(mNumber, TEXT_DIRECTION_LOCALE);
          mNumber.setVisibility(View.INVISIBLE);
  
          //add some padding for the elevation shadow not to be clipped
          //I'm sure there are better ways of doing this...
          setPadding(padding, padding, padding, padding);
  
          resetSizes(maxValue);
  
          mSeparation = separation;
          ColorStateList color = a.getColorStateList(R.styleable.DiscreteSeekBar_dsb_indicatorColor);
          mMarkerDrawable = new MarkerDrawable(color, thumbSize);
          mMarkerDrawable.setCallback(this);
          mMarkerDrawable.setMarkerListener(this);
          mMarkerDrawable.setExternalOffset(padding);
  
          //Elevation for anroid 5+
          float elevation = a.getDimension(R.styleable.DiscreteSeekBar_dsb_indicatorElevation, ELEVATION_DP * displayMetrics.density);
          ViewCompat.setElevation(this, elevation);
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
              SeekBarCompat.setOutlineProvider(this, mMarkerDrawable);
          }
          a.recycle();
      }
  
      public void resetSizes(String maxValue) {
          DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
          //Account for negative numbers... is there any proper way of getting the biggest string between our range????
          mNumber.setText("-" + maxValue);
          //Do a first forced measure call for the TextView (with the biggest text content),
          //to calculate the max width and use always the same.
          //this avoids the TextView from shrinking and growing when the text content changes
          int wSpec = MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, MeasureSpec.AT_MOST);
          int hSpec = MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, MeasureSpec.AT_MOST);
          mNumber.measure(wSpec, hSpec);
          mWidth = Math.max(mNumber.getMeasuredWidth(), mNumber.getMeasuredHeight());
          removeView(mNumber);
          addView(mNumber, new FrameLayout.LayoutParams(mWidth, mWidth, Gravity.LEFT | Gravity.TOP));
      }
  
      @Override
      protected void dispatchDraw(Canvas canvas) {
          mMarkerDrawable.draw(canvas);
          super.dispatchDraw(canvas);
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          measureChildren(widthMeasureSpec, heightMeasureSpec);
          int widthSize = mWidth + getPaddingLeft() + getPaddingRight();
          int heightSize = mWidth + getPaddingTop() + getPaddingBottom();
          //This diff is the basic calculation of the difference between
          //a square side size and its diagonal
          //this helps us account for the visual offset created by MarkerDrawable
          //when leaving one of the corners un-rounded
          int diff = (int) ((1.41f * mWidth) - mWidth) / 2;
          setMeasuredDimension(widthSize, heightSize + diff + mSeparation);
      }
  
      @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
          int left = getPaddingLeft();
          int top = getPaddingTop();
          int right = getWidth() - getPaddingRight();
          int bottom = getHeight() - getPaddingBottom();
          //the TetView is always layout at the top
          mNumber.layout(left, top, left + mWidth, top + mWidth);
          //the MarkerDrawable uses the whole view, it will adapt itself...
          // or it seems so...
          mMarkerDrawable.setBounds(left, top, right, bottom);
      }
  
      @Override
      protected boolean verifyDrawable(Drawable who) {
          return who == mMarkerDrawable || super.verifyDrawable(who);
      }
  
      @Override
      protected void onAttachedToWindow() {
          super.onAttachedToWindow();
          //HACK: Sometimes, the animateOpen() call is made before the View is attached
          //so the drawable cannot schedule itself to run the animation
          //I think we can call it here safely.
          //I've seen it happen in android 2.3.7
          animateOpen();
      }
  
      public void setValue(CharSequence value) {
          mNumber.setText(value);
      }
  
      public CharSequence getValue() {
          return mNumber.getText();
      }
  
      public void animateOpen() {
          mMarkerDrawable.stop();
          mMarkerDrawable.animateToPressed();
      }
  
      public void animateClose() {
          mMarkerDrawable.stop();
          mNumber.setVisibility(View.INVISIBLE);
          mMarkerDrawable.animateToNormal();
      }
  
      @Override
      public void onOpeningComplete() {
          mNumber.setVisibility(View.VISIBLE);
          if (getParent() instanceof MarkerDrawable.MarkerAnimationListener) {
              ((MarkerDrawable.MarkerAnimationListener) getParent()).onOpeningComplete();
          }
      }
  
      @Override
      public void onClosingComplete() {
          if (getParent() instanceof MarkerDrawable.MarkerAnimationListener) {
              ((MarkerDrawable.MarkerAnimationListener) getParent()).onClosingComplete();
          }
      }
  
      @Override
      protected void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          mMarkerDrawable.stop();
      }
  
      public void setColors(int startColor, int endColor) {
          mMarkerDrawable.setColors(startColor, endColor);
      }
  }
  