/* * Copyright (C) 2011 The Android Open Source Project * * 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.android.camera.ui; import com.android.camera.R; import com.android.camera.Util; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * A view that contains camera zoom control and its layout. In addition to the * zoom control, the method {@link #rotate} is added for rotation animation * which is called in switching between first-level and second-level indicators. */ public class ZoomControlWheel extends ZoomControl { private static final String TAG = "ZoomControlWheel"; private static final int HIGHLIGHT_WIDTH = 4; private static final int HIGHLIGHT_DEGREES = 30; private static final int TRAIL_WIDTH = 2; private static final int ZOOM_IN_ICON_DEGREES = 96; private static final int ZOOM_OUT_ICON_DEGREES = 264; private static final int MAX_SLIDER_ANGLE = ZOOM_OUT_ICON_DEGREES - (HIGHLIGHT_DEGREES / 2); private static final int MIN_SLIDER_ANGLE = ZOOM_IN_ICON_DEGREES + (HIGHLIGHT_DEGREES / 2); private static final int DEFAULT_SLIDER_POSITION = MAX_SLIDER_ANGLE; private static final float EDGE_STROKE_WIDTH = 6f; private static final double BUFFER_RADIANS = Math.toRadians(HIGHLIGHT_DEGREES / 2); private static final double SLIDER_RANGE = Math.toRadians(MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE); private double mSliderRadians = DEFAULT_SLIDER_POSITION; private final int HIGHLIGHT_COLOR; private final int TRAIL_COLOR; // The center of the shutter button. private int mCenterX, mCenterY; // The width of the wheel stroke. private int mStrokeWidth; private double mShutterButtonRadius; private double mWheelRadius; private Paint mBackgroundPaint; private RectF mBackgroundRect; private double mRotateAngle; public ZoomControlWheel(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); mBackgroundPaint = new Paint(); mBackgroundPaint.setStyle(Paint.Style.STROKE); mBackgroundPaint.setAntiAlias(true); mBackgroundRect = new RectF(); Resources resources = context.getResources(); HIGHLIGHT_COLOR = resources.getColor(R.color.review_control_pressed_color); TRAIL_COLOR = resources.getColor(R.color.icon_disabled_color); mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS; mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH); mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5; } @Override public boolean dispatchTouchEvent(MotionEvent event) { if (!onFilterTouchEventForSecurity(event) || !isEnabled()) return false; 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. double angle = Math.atan2(dy, dx); if (angle < 0) angle += (2 * Math.PI); mSliderRadians = getSliderDrawAngle(angle); // We assume the slider button is pressed all the time when the // zoom control is active. So we take care of the following events // only. switch (action) { case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: closeZoomControl(); break; case MotionEvent.ACTION_MOVE: performZoom((Math.toRadians(MAX_SLIDER_ANGLE) - mSliderRadians) / SLIDER_RANGE); requestLayout(); } return true; } @Override public void startZoomControl() { super.startZoomControl(); mSliderRadians = Math.toRadians(DEFAULT_SLIDER_POSITION); } private void layoutIcon(View view, double radian) { // Rotate the wheel with the angle when the wheel is rotating or // the indicator control is in the second-level. radian += mRotateAngle; int x = mCenterX + (int)(mWheelRadius * Math.cos(radian)); int y = mCenterY - (int)(mWheelRadius * Math.sin(radian)); int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); view.layout(x - width / 2, y - height / 2, x + width / 2, y + height / 2); } private double getSliderDrawAngle(double sliderAngle) { if (sliderAngle > Math.toRadians(MAX_SLIDER_ANGLE)) { return Math.toRadians(MAX_SLIDER_ANGLE); } else if (sliderAngle < Math.toRadians(MIN_SLIDER_ANGLE)) { return Math.toRadians(MIN_SLIDER_ANGLE); } return sliderAngle; } @Override protected void onLayout( boolean changed, int left, int top, int right, int bottom) { mCenterX = right - left - Util.dpToPixel( IndicatorControlWheelContainer.FULL_WHEEL_RADIUS); mCenterY = (bottom - top) / 2; layoutIcon(mZoomIn, Math.toRadians(ZOOM_IN_ICON_DEGREES)); layoutIcon(mZoomOut, Math.toRadians(ZOOM_OUT_ICON_DEGREES)); layoutIcon(mZoomSlider, getSliderDrawAngle(mSliderRadians)); } private double getZoomIndexAngle() { if (mZoomMax == 0) return Math.PI; return Math.toRadians(MAX_SLIDER_ANGLE - (MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE) * mZoomIndex / mZoomMax); } private void drawArc(Canvas canvas, int startAngle, int sweepAngle, double radius, int color, int width) { mBackgroundRect.set((float) (mCenterX - radius), (float) (mCenterY - radius), (float) (mCenterX + radius), (float) (mCenterY + radius)); mBackgroundPaint.setStrokeWidth(width); mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); mBackgroundPaint.setColor(color); canvas.drawArc(mBackgroundRect, startAngle, sweepAngle, false, mBackgroundPaint); } @Override protected void onDraw(Canvas canvas) { // Draw the slider trail. int startAngle = -MAX_SLIDER_ANGLE - (int) Math.toDegrees(mRotateAngle); int radians = (MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE); if ((startAngle + radians) > 0) radians = -startAngle; drawArc(canvas, startAngle, radians, mWheelRadius, TRAIL_COLOR, TRAIL_WIDTH); super.onDraw(canvas); } public void rotate(double angle) { mRotateAngle = angle; requestLayout(); } }