1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera.ui; 18 19 import com.android.camera.R; 20 import com.android.camera.Util; 21 22 import android.content.Context; 23 import android.content.res.Resources; 24 import android.graphics.Canvas; 25 import android.graphics.Paint; 26 import android.graphics.RectF; 27 import android.util.AttributeSet; 28 import android.view.MotionEvent; 29 import android.view.View; 30 31 /** 32 * A view that contains camera zoom control and its layout. In addition to the 33 * zoom control, the method {@link #rotate} is added for rotation animation 34 * which is called in switching between first-level and second-level indicators. 35 */ 36 public class ZoomControlWheel extends ZoomControl { 37 private static final String TAG = "ZoomControlWheel"; 38 private static final int HIGHLIGHT_WIDTH = 4; 39 private static final int HIGHLIGHT_DEGREES = 30; 40 private static final int TRAIL_WIDTH = 2; 41 private static final int ZOOM_IN_ICON_DEGREES = 96; 42 private static final int ZOOM_OUT_ICON_DEGREES = 264; 43 private static final int MAX_SLIDER_ANGLE = 44 ZOOM_OUT_ICON_DEGREES - (HIGHLIGHT_DEGREES / 2); 45 private static final int MIN_SLIDER_ANGLE = 46 ZOOM_IN_ICON_DEGREES + (HIGHLIGHT_DEGREES / 2); 47 private static final int DEFAULT_SLIDER_POSITION = MAX_SLIDER_ANGLE; 48 private static final float EDGE_STROKE_WIDTH = 6f; 49 private static final double BUFFER_RADIANS = Math.toRadians(HIGHLIGHT_DEGREES / 2); 50 private static final double SLIDER_RANGE = 51 Math.toRadians(MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE); 52 private double mSliderRadians = DEFAULT_SLIDER_POSITION; 53 54 private final int HIGHLIGHT_COLOR; 55 private final int TRAIL_COLOR; 56 57 // The center of the shutter button. 58 private int mCenterX, mCenterY; 59 // The width of the wheel stroke. 60 private int mStrokeWidth; 61 private double mShutterButtonRadius; 62 private double mWheelRadius; 63 private Paint mBackgroundPaint; 64 private RectF mBackgroundRect; 65 66 private double mRotateAngle; 67 ZoomControlWheel(Context context, AttributeSet attrs)68 public ZoomControlWheel(Context context, AttributeSet attrs) { 69 super(context, attrs); 70 setWillNotDraw(false); 71 72 mBackgroundPaint = new Paint(); 73 mBackgroundPaint.setStyle(Paint.Style.STROKE); 74 mBackgroundPaint.setAntiAlias(true); 75 76 mBackgroundRect = new RectF(); 77 Resources resources = context.getResources(); 78 HIGHLIGHT_COLOR = resources.getColor(R.color.review_control_pressed_color); 79 TRAIL_COLOR = resources.getColor(R.color.icon_disabled_color); 80 81 mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS; 82 mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH); 83 mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5; 84 } 85 86 @Override dispatchTouchEvent(MotionEvent event)87 public boolean dispatchTouchEvent(MotionEvent event) { 88 if (!onFilterTouchEventForSecurity(event) || !isEnabled()) return false; 89 int action = event.getAction(); 90 91 double dx = event.getX() - mCenterX; 92 double dy = mCenterY - event.getY(); 93 double radius = Math.sqrt(dx * dx + dy * dy); 94 // Ignore the event if too far from the shutter button. 95 double angle = Math.atan2(dy, dx); 96 if (angle < 0) angle += (2 * Math.PI); 97 mSliderRadians = getSliderDrawAngle(angle); 98 99 // We assume the slider button is pressed all the time when the 100 // zoom control is active. So we take care of the following events 101 // only. 102 switch (action) { 103 case MotionEvent.ACTION_OUTSIDE: 104 case MotionEvent.ACTION_UP: 105 case MotionEvent.ACTION_CANCEL: 106 closeZoomControl(); 107 break; 108 case MotionEvent.ACTION_MOVE: 109 performZoom((Math.toRadians(MAX_SLIDER_ANGLE) 110 - mSliderRadians) / SLIDER_RANGE); 111 requestLayout(); 112 } 113 return true; 114 } 115 116 @Override startZoomControl()117 public void startZoomControl() { 118 super.startZoomControl(); 119 mSliderRadians = Math.toRadians(DEFAULT_SLIDER_POSITION); 120 } 121 layoutIcon(View view, double radian)122 private void layoutIcon(View view, double radian) { 123 // Rotate the wheel with the angle when the wheel is rotating or 124 // the indicator control is in the second-level. 125 radian += mRotateAngle; 126 int x = mCenterX + (int)(mWheelRadius * Math.cos(radian)); 127 int y = mCenterY - (int)(mWheelRadius * Math.sin(radian)); 128 int width = view.getMeasuredWidth(); 129 int height = view.getMeasuredHeight(); 130 view.layout(x - width / 2, y - height / 2, x + width / 2, 131 y + height / 2); 132 } 133 getSliderDrawAngle(double sliderAngle)134 private double getSliderDrawAngle(double sliderAngle) { 135 if (sliderAngle > Math.toRadians(MAX_SLIDER_ANGLE)) { 136 return Math.toRadians(MAX_SLIDER_ANGLE); 137 } else if (sliderAngle < Math.toRadians(MIN_SLIDER_ANGLE)) { 138 return Math.toRadians(MIN_SLIDER_ANGLE); 139 } 140 return sliderAngle; 141 } 142 143 @Override onLayout( boolean changed, int left, int top, int right, int bottom)144 protected void onLayout( 145 boolean changed, int left, int top, int right, int bottom) { 146 mCenterX = right - left - Util.dpToPixel( 147 IndicatorControlWheelContainer.FULL_WHEEL_RADIUS); 148 mCenterY = (bottom - top) / 2; 149 layoutIcon(mZoomIn, Math.toRadians(ZOOM_IN_ICON_DEGREES)); 150 layoutIcon(mZoomOut, Math.toRadians(ZOOM_OUT_ICON_DEGREES)); 151 layoutIcon(mZoomSlider, getSliderDrawAngle(mSliderRadians)); 152 } 153 getZoomIndexAngle()154 private double getZoomIndexAngle() { 155 if (mZoomMax == 0) return Math.PI; 156 return Math.toRadians(MAX_SLIDER_ANGLE - 157 (MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE) * mZoomIndex / mZoomMax); 158 } 159 drawArc(Canvas canvas, int startAngle, int sweepAngle, double radius, int color, int width)160 private void drawArc(Canvas canvas, int startAngle, int sweepAngle, 161 double radius, int color, int width) { 162 mBackgroundRect.set((float) (mCenterX - radius), (float) (mCenterY - radius), 163 (float) (mCenterX + radius), (float) (mCenterY + radius)); 164 mBackgroundPaint.setStrokeWidth(width); 165 mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); 166 mBackgroundPaint.setColor(color); 167 canvas.drawArc(mBackgroundRect, startAngle, sweepAngle, false, mBackgroundPaint); 168 } 169 170 @Override onDraw(Canvas canvas)171 protected void onDraw(Canvas canvas) { 172 // Draw the slider trail. 173 int startAngle = -MAX_SLIDER_ANGLE - (int) Math.toDegrees(mRotateAngle); 174 int radians = (MAX_SLIDER_ANGLE - MIN_SLIDER_ANGLE); 175 if ((startAngle + radians) > 0) radians = -startAngle; 176 drawArc(canvas, startAngle, radians, 177 mWheelRadius, TRAIL_COLOR, TRAIL_WIDTH); 178 super.onDraw(canvas); 179 } 180 rotate(double angle)181 public void rotate(double angle) { 182 mRotateAngle = angle; 183 requestLayout(); 184 } 185 } 186