/**
   * Get the available 'crop' (zoom) rectangles for this camera that will be reported via a {@code
   * CaptureResult} when a zoom is requested.
   *
   * <p>These crops ignores the underlying preview buffer size, and will always be reported the same
   * values regardless of what configuration of outputs is used.
   *
   * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, where each
   * crop rectangle corresponds to a zoom ratio (and is centered at the middle).
   *
   * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, by
   * shrinking the rectangle if necessary.
   *
   * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} =
   * {@code activeArray size}.
   *
   * @param params non-{@code null} camera api1 parameters
   * @param activeArray active array dimensions, in sensor space
   * @param streamSize stream size dimensions, in pixels
   * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
   */
  public static List<Rect> getAvailableZoomCropRectangles(
      Camera.Parameters params, Rect activeArray) {
    checkNotNull(params, "params must not be null");
    checkNotNull(activeArray, "activeArray must not be null");

    return getAvailableCropRectangles(params, activeArray, ParamsUtils.createSize(activeArray));
  }
  /**
   * Get the available 'crop' (zoom) rectangles for this camera.
   *
   * <p>This is the effective (real) crop that is applied by the camera api1 device when projecting
   * the zoom onto the intermediate preview buffer. Use this when deciding which zoom ratio to
   * apply.
   *
   * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, where each
   * crop rectangle corresponds to a zoom ratio (and is centered at the middle).
   *
   * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, by
   * shrinking the rectangle if necessary.
   *
   * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} =
   * {@code activeArray size}.
   *
   * @param params non-{@code null} camera api1 parameters
   * @param activeArray active array dimensions, in sensor space
   * @param streamSize stream size dimensions, in pixels
   * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
   */
  public static List<Rect> getAvailablePreviewZoomCropRectangles(
      Camera.Parameters params, Rect activeArray, Size previewSize) {
    checkNotNull(params, "params must not be null");
    checkNotNull(activeArray, "activeArray must not be null");
    checkNotNull(previewSize, "previewSize must not be null");

    return getAvailableCropRectangles(params, activeArray, previewSize);
  }
  /**
   * Returns the component-wise zoom ratio (each greater or equal than {@code 1.0}); largest values
   * means more zoom.
   *
   * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
   * @param cropSize size of the crop/zoom
   * @return {@link SizeF} with width/height being the component-wise zoom ratio
   * @throws NullPointerException if any of the args were {@code null}
   * @throws IllegalArgumentException if any component of {@code cropSize} was {@code 0}
   */
  private static SizeF getZoomRatio(Size activeArraySize, Size cropSize) {
    checkNotNull(activeArraySize, "activeArraySize must not be null");
    checkNotNull(cropSize, "cropSize must not be null");
    checkArgumentPositive(cropSize.getWidth(), "cropSize.width must be positive");
    checkArgumentPositive(cropSize.getHeight(), "cropSize.height must be positive");

    float zoomRatioWidth = activeArraySize.getWidth() * 1.0f / cropSize.getWidth();
    float zoomRatioHeight = activeArraySize.getHeight() * 1.0f / cropSize.getHeight();

    return new SizeF(zoomRatioWidth, zoomRatioHeight);
  }
  /**
   * Returns the smallest range that includes this range and the inclusive range specified by {@code
   * [lower, upper]}.
   *
   * <p>See {@link #extend(Range)} for more details.
   *
   * @param lower a non-{@code null} {@code T} reference
   * @param upper a non-{@code null} {@code T} reference
   * @return the extension of this range and the other range.
   * @throws NullPointerException if {@code lower} or {@code upper} was {@code null}
   */
  public Range<T> extend(T lower, T upper) {
    checkNotNull(lower, "lower must not be null");
    checkNotNull(upper, "upper must not be null");

    int cmpLower = lower.compareTo(mLower);
    int cmpUpper = upper.compareTo(mUpper);

    if (cmpLower >= 0 && cmpUpper <= 0) {
      // this inludes other
      return this;
    } else {
      return Range.create(cmpLower >= 0 ? mLower : lower, cmpUpper <= 0 ? mUpper : upper);
    }
  }
  /**
   * Returns the intersection of this range and the inclusive range specified by {@code [lower,
   * upper]}.
   *
   * <p>See {@link #intersect(Range)} for more details.
   *
   * @param lower a non-{@code null} {@code T} reference
   * @param upper a non-{@code null} {@code T} reference
   * @return the intersection of this range and the other range
   * @throws NullPointerException if {@code lower} or {@code upper} was {@code null}
   * @throws IllegalArgumentException if the ranges are disjoint.
   */
  public Range<T> intersect(T lower, T upper) {
    checkNotNull(lower, "lower must not be null");
    checkNotNull(upper, "upper must not be null");

    int cmpLower = lower.compareTo(mLower);
    int cmpUpper = upper.compareTo(mUpper);

    if (cmpLower <= 0 && cmpUpper >= 0) {
      // [lower, upper] includes this
      return this;
    } else {
      return Range.create(cmpLower <= 0 ? mLower : lower, cmpUpper >= 0 ? mUpper : upper);
    }
  }
 private ViewFader(View view) {
   mView = Preconditions.checkNotNull(view);
   mFadeOutAnimation =
       ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(FADE_OUT_DURATION);
   mFadeInAnimation =
       ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(FADE_IN_DURATION);
 }
 /**
  * Initializes a new floating toolbar popup.
  *
  * @param parent A parent view to get the {@link android.view.View#getWindowToken()} token from.
  */
 public FloatingToolbarPopup(View parent) {
   mParent = Preconditions.checkNotNull(parent);
   mContentContainer = createContentContainer(parent.getContext());
   mPopupWindow = createPopupWindow(mContentContainer);
   mShowAnimation = createGrowFadeInFromBottom(mContentContainer);
   mDismissAnimation =
       createShrinkFadeOutFromBottomAnimation(
           mContentContainer,
           new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
               mPopupWindow.dismiss();
               mContentContainer.removeAllViews();
             }
           });
   mHideAnimation =
       createShrinkFadeOutFromBottomAnimation(
           mContentContainer,
           new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
               mPopupWindow.dismiss();
             }
           });
   mMarginHorizontal =
       parent.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
   mMarginVertical =
       parent.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
 }
  /**
   * Checks if the {@code value} is within the bounds of this range.
   *
   * <p>A value is considered to be within this range if it's {@code >=} the lower endpoint
   * <i>and</i> {@code <=} the upper endpoint (using the {@link Comparable} interface.)
   *
   * @param value a non-{@code null} {@code T} reference
   * @return {@code true} if the value is within this inclusive range, {@code false} otherwise
   * @throws NullPointerException if {@code value} was {@code null}
   */
  public boolean contains(T value) {
    checkNotNull(value, "value must not be null");

    boolean gteLower = value.compareTo(mLower) >= 0;
    boolean lteUpper = value.compareTo(mUpper) <= 0;

    return gteLower && lteUpper;
  }
  /**
   * Checks if another {@code range} is within the bounds of this range.
   *
   * <p>A range is considered to be within this range if both of its endpoints are within this
   * range.
   *
   * @param range a non-{@code null} {@code T} reference
   * @return {@code true} if the range is within this inclusive range, {@code false} otherwise
   * @throws NullPointerException if {@code range} was {@code null}
   */
  public boolean contains(Range<T> range) {
    checkNotNull(range, "value must not be null");

    boolean gteLower = range.mLower.compareTo(mLower) >= 0;
    boolean lteUpper = range.mUpper.compareTo(mUpper) <= 0;

    return gteLower && lteUpper;
  }
    /**
     * Puts an advanced (printer specific) option.
     *
     * @param key The option key.
     * @param value The option value.
     */
    public void putAdvancedOption(@NonNull String key, @Nullable String value) {
      Preconditions.checkNotNull(key, "key cannot be null");

      if (mPrototype.mAdvancedOptions == null) {
        mPrototype.mAdvancedOptions = new Bundle();
      }
      mPrototype.mAdvancedOptions.putString(key, value);
    }
  /** Convert a camera API1 list of sizes into a util list of sizes */
  public static List<Size> convertSizeList(List<Camera.Size> sizeList) {
    checkNotNull(sizeList, "sizeList must not be null");

    List<Size> sizes = new ArrayList<>(sizeList.size());
    for (Camera.Size s : sizeList) {
      sizes.add(new Size(s.width, s.height));
    }
    return sizes;
  }
 /** Check if the camera API1 list of sizes contains a size with the given dimens. */
 public static boolean containsSize(List<Camera.Size> sizeList, int width, int height) {
   checkNotNull(sizeList, "sizeList must not be null");
   for (Camera.Size s : sizeList) {
     if (s.height == height && s.width == width) {
       return true;
     }
   }
   return false;
 }
 /** Places the main view panel at the appropriate resting coordinates. */
 private void positionOverflowPanel() {
   Preconditions.checkNotNull(mOverflowPanel);
   float x =
       mPopupWindow.getWidth()
           - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal);
   mContentContainer.setX(x);
   mContentContainer.setY(mMarginVertical);
   setContentAreaAsTouchableSurface();
 }
 private int setOverflowWidth() {
   for (int i = 0; i < mListView.getAdapter().getCount(); i++) {
     MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(i);
     Preconditions.checkNotNull(menuItem);
     mListViewItemWidthCalculator.setText(menuItem.getTitle());
     mListViewItemWidthCalculator.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
     mOverflowWidth = Math.max(mListViewItemWidthCalculator.getMeasuredWidth(), mOverflowWidth);
   }
   return mOverflowWidth;
 }
  /** Convert a camera API1 list of sizes into an array of sizes */
  public static Size[] convertSizeListToArray(List<Camera.Size> sizeList) {
    checkNotNull(sizeList, "sizeList must not be null");

    Size[] array = new Size[sizeList.size()];
    int ctr = 0;
    for (Camera.Size s : sizeList) {
      array[ctr++] = new Size(s.width, s.height);
    }
    return array;
  }
  /**
   * Clamps {@code value} to this range.
   *
   * <p>If the value is within this range, it is returned. Otherwise, if it is {@code <} than the
   * lower endpoint, the lower endpoint is returned, else the upper endpoint is returned.
   * Comparisons are performed using the {@link Comparable} interface.
   *
   * @param value a non-{@code null} {@code T} reference
   * @return {@code value} clamped to this range.
   */
  public T clamp(T value) {
    checkNotNull(value, "value must not be null");

    if (value.compareTo(mLower) < 0) {
      return mLower;
    } else if (value.compareTo(mUpper) > 0) {
      return mUpper;
    } else {
      return value;
    }
  }
 /** Sets the current content to be the overflow view panel. */
 private void setOverflowPanelAsContent() {
   // This should never be called if the overflow panel has not been initialized.
   Preconditions.checkNotNull(mOverflowPanel);
   mContentContainer.removeAllViews();
   Size overflowPanelSize = mOverflowPanel.measure();
   ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
   params.width = overflowPanelSize.getWidth();
   params.height = overflowPanelSize.getHeight();
   mContentContainer.setLayoutParams(params);
   mContentContainer.addView(mOverflowPanel.getView());
   setContentAreaAsTouchableSurface();
 }
    /** Places the main view panel at the appropriate resting coordinates. */
    private void positionMainPanel() {
      Preconditions.checkNotNull(mMainPanel);
      float x =
          mPopupWindow.getWidth() - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal);
      mContentContainer.setX(x);

      float y = mMarginVertical;
      if (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
        y = getHeight() - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
      }
      mContentContainer.setY(y);
      setContentAreaAsTouchableSurface();
    }
  /**
   * Get the available 'crop' (zoom) rectangles for this camera.
   *
   * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size, where each
   * crop rectangle corresponds to a zoom ratio (and is centered at the middle).
   *
   * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize}, by
   * shrinking the rectangle if necessary.
   *
   * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize} =
   * {@code activeArray size}.
   *
   * @param params non-{@code null} camera api1 parameters
   * @param activeArray active array dimensions, in sensor space
   * @param streamSize stream size dimensions, in pixels
   * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
   */
  private static List<Rect> getAvailableCropRectangles(
      Camera.Parameters params, Rect activeArray, Size streamSize) {
    checkNotNull(params, "params must not be null");
    checkNotNull(activeArray, "activeArray must not be null");
    checkNotNull(streamSize, "streamSize must not be null");

    // TODO: change all uses of Rect activeArray to Size activeArray,
    // since we want the crop to be active-array relative, not pixel-array relative

    Rect unzoomedStreamCrop = getPreviewCropRectangleUnzoomed(activeArray, streamSize);

    if (!params.isZoomSupported()) {
      // Trivial case: No zoom -> only support the full size as the crop region
      return new ArrayList<>(Arrays.asList(unzoomedStreamCrop));
    }

    List<Rect> zoomCropRectangles = new ArrayList<>(params.getMaxZoom() + 1);
    Matrix scaleMatrix = new Matrix();
    RectF scaledRect = new RectF();

    for (int zoom : params.getZoomRatios()) {
      float shrinkRatio = ZOOM_RATIO_MULTIPLIER * 1.0f / zoom; // normalize to 1.0 and smaller

      // set scaledRect to unzoomedStreamCrop
      ParamsUtils.convertRectF(unzoomedStreamCrop, /*out*/ scaledRect);

      scaleMatrix.setScale(
          shrinkRatio, shrinkRatio, activeArray.exactCenterX(), activeArray.exactCenterY());

      scaleMatrix.mapRect(scaledRect);

      Rect intRect = ParamsUtils.createRect(scaledRect);

      // Round the rect corners towards the nearest integer values
      zoomCropRectangles.add(intRect);
    }

    return zoomCropRectangles;
  }
 /**
  * Caches the specified token until the specified expiryMillis. The token will be associated with
  * the given token type, package name, and digest of signatures.
  *
  * @param token
  * @param tokenType
  * @param packageName
  * @param sigDigest
  * @param expiryMillis
  */
 public void put(
     Account account,
     String token,
     String tokenType,
     String packageName,
     byte[] sigDigest,
     long expiryMillis) {
   Preconditions.checkNotNull(account);
   if (token == null || System.currentTimeMillis() > expiryMillis) {
     return;
   }
   Key k = new Key(account, tokenType, packageName, sigDigest);
   Value v = new Value(token, expiryMillis);
   mCachedTokens.putToken(k, v);
 }
  /**
   * Returns the smallest range that includes this range and another {@code range}.
   *
   * <p>E.g. if a {@code <} b {@code <} c {@code <} d, the extension of [a, c] and [b, d] ranges is
   * [a, d]. As the endpoints are object references, there is no guarantee which specific endpoint
   * reference is used from the input ranges:
   *
   * <p>E.g. if a {@code ==} a' {@code <} b {@code <} c, the extension of [a, b] and [a', c] ranges
   * could be either [a, c] or ['a, c], where ['a, c] could be either the exact input range, or a
   * newly created range with the same endpoints.
   *
   * @param range a non-{@code null} {@code Range<T>} reference
   * @return the extension of this range and the other range.
   * @throws NullPointerException if {@code range} was {@code null}
   */
  public Range<T> extend(Range<T> range) {
    checkNotNull(range, "range must not be null");

    int cmpLower = range.mLower.compareTo(mLower);
    int cmpUpper = range.mUpper.compareTo(mUpper);

    if (cmpLower <= 0 && cmpUpper >= 0) {
      // other includes this
      return range;
    } else if (cmpLower >= 0 && cmpUpper <= 0) {
      // this inludes other
      return this;
    } else {
      return Range.create(
          cmpLower >= 0 ? mLower : range.mLower, cmpUpper <= 0 ? mUpper : range.mUpper);
    }
  }
    /**
     * Initializes a floating toolbar popup overflow view panel.
     *
     * @param context
     * @param closeOverflow The code that closes the toolbar popup's overflow.
     */
    public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
      mCloseOverflow = Preconditions.checkNotNull(closeOverflow);

      mContentView = new LinearLayout(context);
      mContentView.setOrientation(LinearLayout.VERTICAL);
      mViewFader = new ViewFader(mContentView);

      mBackButton =
          LayoutInflater.from(context).inflate(R.layout.floating_popup_close_overflow_button, null);
      mBackButton.setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              mCloseOverflow.run();
            }
          });
      mBackButtonContainer = new LinearLayout(context);
      mBackButtonContainer.addView(mBackButton);

      mListView = createOverflowListView();
      mListView.setOnItemClickListener(
          new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
              MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position);
              if (mOnMenuItemClickListener != null) {
                mOnMenuItemClickListener.onMenuItemClick(menuItem);
              }
            }
          });

      mContentView.addView(mListView);
      mContentView.addView(mBackButtonContainer);

      mListViewItemWidthCalculator = createOverflowMenuItemButton(context);
      mListViewItemWidthCalculator.setLayoutParams(
          new ViewGroup.LayoutParams(
              ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    }
  /**
   * Convert an api1 face into an active-array based api2 face.
   *
   * <p>Out-of-ranges scores and ids will be clipped to be within range (with a warning).
   *
   * @param face a non-{@code null} api1 face
   * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
   * @param zoomData the calculated zoom data corresponding to this request
   * @return a non-{@code null} api2 face
   * @throws NullPointerException if the {@code face} was {@code null}
   */
  public static Face convertFaceFromLegacy(Camera.Face face, Rect activeArray, ZoomData zoomData) {
    checkNotNull(face, "face must not be null");

    Face api2Face;

    Camera.Area fakeArea = new Camera.Area(face.rect, /*weight*/ 1);

    WeightedRectangle faceRect =
        convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, fakeArea);

    Point leftEye = face.leftEye, rightEye = face.rightEye, mouth = face.mouth;
    if (leftEye != null
        && rightEye != null
        && mouth != null
        && leftEye.x != -2000
        && leftEye.y != -2000
        && rightEye.x != -2000
        && rightEye.y != -2000
        && mouth.x != -2000
        && mouth.y != -2000) {
      leftEye =
          convertCameraPointToActiveArrayPoint(
              activeArray, zoomData, leftEye, /*usePreviewCrop*/ true);
      rightEye =
          convertCameraPointToActiveArrayPoint(
              activeArray, zoomData, leftEye, /*usePreviewCrop*/ true);
      mouth =
          convertCameraPointToActiveArrayPoint(
              activeArray, zoomData, leftEye, /*usePreviewCrop*/ true);

      api2Face = faceRect.toFace(face.id, leftEye, rightEye, mouth);
    } else {
      api2Face = faceRect.toFace();
    }

    return api2Face;
  }
 /**
  * Initializes a floating toolbar popup main view panel.
  *
  * @param context
  * @param openOverflow The code that opens the toolbar popup overflow.
  */
 public FloatingToolbarMainPanel(Context context, Runnable openOverflow) {
   mContext = Preconditions.checkNotNull(context);
   mContentView = new LinearLayout(context);
   viewFader = new ViewFader(mContentView);
   mOpenOverflow = Preconditions.checkNotNull(openOverflow);
 }
 /** Initializes a floating toolbar. */
 public FloatingToolbar(Context context, Window window) {
   mContext = Preconditions.checkNotNull(context);
   mPopup = new FloatingToolbarPopup(window.getDecorView());
 }
 void init(ChartAxis axis) {
   mAxis = Preconditions.checkNotNull(axis, "missing axis");
 }
 void init(ChartAxis horiz, ChartAxis vert) {
   mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
   mVert = Preconditions.checkNotNull(vert, "missing vert");
 }
 public DrawableWrapper(Drawable drawable) {
   mDrawable = Preconditions.checkNotNull(drawable);
   mDrawable.setCallback(this);
 }
 /**
  * Sets the menu to be shown in this floating toolbar. NOTE: Call {@link #updateLayout()} or
  * {@link #show()} to effect visual changes to the toolbar.
  */
 public FloatingToolbar setMenu(Menu menu) {
   mMenu = Preconditions.checkNotNull(menu);
   return this;
 }
 /**
  * Sets the content rectangle. This is the area of the interesting content that this toolbar
  * should avoid obstructing. NOTE: Call {@link #updateLayout()} or {@link #show()} to effect
  * visual changes to the toolbar.
  */
 public FloatingToolbar setContentRect(Rect rect) {
   mContentRect.set(Preconditions.checkNotNull(rect));
   return this;
 }