public void onIndicatorEvent(int event) {
    switch (event) {
      case OnIndicatorEventListener.EVENT_ENTER_ZOOM_CONTROL:
        mIndicatorControlWheel.setVisibility(View.GONE);
        mZoomControlWheel.setVisibility(View.VISIBLE);
        mZoomControlWheel.startZoomControl();
        break;

      case OnIndicatorEventListener.EVENT_LEAVE_ZOOM_CONTROL:
        mZoomControlWheel.setVisibility(View.GONE);
        mIndicatorControlWheel.setVisibility(View.VISIBLE);
        break;
    }
  }
  @Override
  protected void onMeasure(int widthSpec, int heightSpec) {
    // Measure all children.
    int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    mShutterButton.measure(freeSpec, freeSpec);
    mIndicatorControlWheel.measure(freeSpec, freeSpec);
    mZoomControlWheel.measure(freeSpec, freeSpec);

    // Measure myself. Add some buffer for highlight arc.
    int desiredWidth =
        mShutterButton.getMeasuredWidth() + IndicatorControlWheel.HIGHLIGHT_WIDTH * 4;
    int desiredHeight =
        mShutterButton.getMeasuredHeight() + IndicatorControlWheel.HIGHLIGHT_WIDTH * 4;
    int widthMode = MeasureSpec.getMode(widthSpec);
    int heightMode = MeasureSpec.getMode(heightSpec);
    int measuredWidth, measuredHeight;
    if (widthMode == MeasureSpec.UNSPECIFIED) {
      measuredWidth = desiredWidth;
    } else if (widthMode == MeasureSpec.AT_MOST) {
      measuredWidth = Math.min(desiredWidth, MeasureSpec.getSize(widthSpec));
    } else { // MeasureSpec.EXACTLY
      measuredWidth = MeasureSpec.getSize(widthSpec);
    }
    if (heightMode == MeasureSpec.UNSPECIFIED) {
      measuredHeight = desiredHeight;
    } else if (heightMode == MeasureSpec.AT_MOST) {
      measuredHeight = Math.min(desiredHeight, MeasureSpec.getSize(heightSpec));
    } else { // MeasureSpec.EXACTLY
      measuredHeight = MeasureSpec.getSize(heightSpec);
    }
    setMeasuredDimension(measuredWidth, measuredHeight);
  }
  public void initialize(
      Context context,
      PreferenceGroup group,
      boolean isZoomSupported,
      String[] keys,
      String[] otherSettingKeys) {
    mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS;
    mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH);
    mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5;

    setPreferenceGroup(group);

    // Add the ZoomControl if supported.
    if (isZoomSupported) {
      mZoomControl = (ZoomControlWheel) findViewById(R.id.zoom_control);
      mZoomControl.setVisibility(View.VISIBLE);
    }

    // Add CameraPicker.
    initializeCameraPicker();

    // Add second-level Indicator Icon.
    mSecondLevelIcon = addImageButton(context, R.drawable.ic_settings_holo_light, true);
    mSecondLevelStartIndex = getChildCount();

    // Add second-level buttons.
    mCloseIcon = addImageButton(context, R.drawable.btn_wheel_close_settings, false);
    addControls(keys, otherSettingKeys);

    // The angle(in radians) of each icon for touch events.
    mChildRadians = new double[getChildCount()];
    presetFirstLevelChildRadians();
    presetSecondLevelChildRadians();
    mInitialized = true;
  }
  @Override
  protected void onFinishInflate() {
    mShutterButton = findViewById(R.id.shutter_button);
    mShutterButtonRadius = Util.dpToPixel(SHUTTER_BUTTON_RADIUS);

    mZoomControlWheel = (ZoomControlWheel) findViewById(R.id.zoom_control);
    mZoomControlWheel.setOnIndicatorEventListener(this);

    mIndicatorControlWheel = (IndicatorControlWheel) findViewById(R.id.indicator_control_wheel);
  }
  @Override
  public boolean dispatchTouchEvent(MotionEvent event) {
    if (!onFilterTouchEventForSecurity(event)) return false;
    mLastMotionEvent = event;
    int action = event.getAction();

    double dx = event.getX() - mCenterX;
    double dy = mCenterY - event.getY();
    double radius = Math.sqrt(dx * dx + dy * dy);

    // Ignore the event if too far from the shutter button.
    if ((radius <= (mWheelRadius + mStrokeWidth)) && (radius > mShutterButtonRadius)) {
      double delta = Math.atan2(dy, dx);
      if (delta < 0) delta += Math.PI * 2;
      int index = getTouchIndicatorIndex(delta);
      // Check if the touch event is for zoom control.
      if ((mZoomControl != null) && (index == 0)) {
        mZoomControl.dispatchTouchEvent(event);
      }
      // Move over from one indicator to another.
      if ((index != mPressedIndex) || (action == MotionEvent.ACTION_DOWN)) {
        if (mPressedIndex != -1) {
          injectMotionEvent(mPressedIndex, event, MotionEvent.ACTION_CANCEL);
        } else {
          // Cancel the popup if it is different from the selected.
          if (getSelectedIndicatorIndex() != index) dismissSettingPopup();
        }
        if ((index != -1) && (action == MotionEvent.ACTION_MOVE)) {
          if (mCurrentLevel != 0) {
            injectMotionEvent(index, event, MotionEvent.ACTION_DOWN);
          }
        }
      }
      if ((index != -1) && (action != MotionEvent.ACTION_MOVE)) {
        getChildAt(index).dispatchTouchEvent(event);
      }
      // Do not highlight the CameraPicker or Settings icon if we
      // touch from the zoom control to one of them.
      if ((mCurrentLevel == 0) && (index != 0) && (action == MotionEvent.ACTION_MOVE)) {
        return true;
      }
      // Once the button is up, reset the press index.
      mPressedIndex = (action == MotionEvent.ACTION_UP) ? -1 : index;
      invalidate();
      return true;
    }
    // The event is not on any of the child.
    onTouchOutBound();
    return false;
  }
  @Override
  public boolean dispatchTouchEvent(MotionEvent event) {
    if (!onFilterTouchEventForSecurity(event)) return false;

    int action = event.getAction();

    double dx = event.getX() - mCenterX;
    double dy = mCenterY - event.getY();
    double radius = Math.sqrt(dx * dx + dy * dy);

    // Check if the event should be dispatched to the shutter button.
    if (radius <= mShutterButtonRadius) {
      if (mIndicatorControlWheel.getVisibility() == View.VISIBLE) {
        mIndicatorControlWheel.onTouchOutBound();
      } else {
        return mZoomControlWheel.dispatchTouchEvent(event);
      }
      if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP) {
        return mShutterButton.dispatchTouchEvent(event);
      }
      return false;
    }

    if (mShutterButton.isPressed()) {
      // Send cancel to the shutter button if it was pressed.
      event.setAction(MotionEvent.ACTION_CANCEL);
      mShutterButton.dispatchTouchEvent(event);
      return true;
    }

    if (mIndicatorControlWheel.getVisibility() == View.VISIBLE) {
      return mIndicatorControlWheel.dispatchTouchEvent(event);
    } else {
      return mZoomControlWheel.dispatchTouchEvent(event);
    }
  }
  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

    // Layout the shutter button.
    int shutterButtonWidth = mShutterButton.getMeasuredWidth();
    int shutterButtonHeight = mShutterButton.getMeasuredHeight();
    mCenterX = right - left - Util.dpToPixel(FULL_WHEEL_RADIUS);
    mCenterY = (bottom - top) / 2;
    mShutterButton.layout(
        right - left - shutterButtonWidth,
        mCenterY - shutterButtonHeight / 2,
        right - left,
        mCenterY + shutterButtonHeight - shutterButtonHeight / 2);
    // Layout the control wheel.
    mIndicatorControlWheel.layout(0, 0, right - left, bottom - top);
    mZoomControlWheel.layout(0, 0, right - left, bottom - top);
  }
  private void rotateWheel() {
    int totalDegrees = CLOSE_ICON_DEFAULT_DEGREES - SECOND_LEVEL_START_DEGREES;
    int startAngle =
        ((mCurrentLevel == 0) ? CLOSE_ICON_DEFAULT_DEGREES : SECOND_LEVEL_START_DEGREES);
    if (mCurrentLevel == 0) totalDegrees = -totalDegrees;

    int elapsedTime = (int) (SystemClock.uptimeMillis() - mAnimationStartTime);
    if (elapsedTime >= ANIMATION_TIME) {
      elapsedTime = ANIMATION_TIME;
      mCurrentLevel = (mCurrentLevel == 0) ? 1 : 0;
      mInAnimation = false;
    }

    int expectedAngle = startAngle + (totalDegrees * elapsedTime / ANIMATION_TIME);
    double increment = Math.toRadians(expectedAngle) - mChildRadians[mSecondLevelStartIndex];
    for (int i = 0; i < getChildCount(); ++i) mChildRadians[i] += increment;
    // We also need to rotate the zoom control wheel as well.
    if (mZoomControl != null) {
      mZoomControl.rotate(mChildRadians[0] - Math.toRadians(MAX_ZOOM_CONTROL_DEGREES));
    }
  }
 @Override
 public void setEnabled(boolean enabled) {
   mIndicatorControlWheel.setEnabled(enabled);
   mZoomControlWheel.setEnabled(enabled);
 }
 @Override
 public void setDegree(int degree) {
   mIndicatorControlWheel.setDegree(degree);
   mZoomControlWheel.setDegree(degree);
 }
 public void enableZoom(boolean enabled) {
   if (mZoomControl != null) mZoomControl.setEnabled(enabled);
 }