IndicatorControlWheel.java revision b1ce29490ec61847602ece16f3745417787d3d8f
16f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li/* 26f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Copyright (C) 2010 The Android Open Source Project 36f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * 46f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Licensed under the Apache License, Version 2.0 (the "License"); 56f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * you may not use this file except in compliance with the License. 66f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * You may obtain a copy of the License at 76f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * 86f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * http://www.apache.org/licenses/LICENSE-2.0 96f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * 106f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Unless required by applicable law or agreed to in writing, software 116f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * distributed under the License is distributed on an "AS IS" BASIS, 126f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * See the License for the specific language governing permissions and 146f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * limitations under the License. 156f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li */ 166f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 176f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Lipackage com.android.camera.ui; 186f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 1995788ace8ad3630312f2f94544690c448c935f9eChung-yih Wangimport com.android.camera.PreferenceGroup; 206f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport com.android.camera.R; 2116ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Liimport com.android.camera.Util; 226f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 236f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.content.Context; 24e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyanimport android.content.res.Resources; 2580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.Canvas; 2680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.Paint; 2780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.RectF; 28ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wangimport android.os.Handler; 29a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Liimport android.os.SystemClock; 306f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.util.AttributeSet; 31dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Liimport android.view.MotionEvent; 326f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.view.View; 33ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wangimport android.widget.ImageView; 346f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 356f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li/** 36ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang * A view that contains camera setting indicators in two levels. The first-level 37ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang * indicators including the zoom, camera picker, flash and second-level control. 38ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang * The second-level indicators are the merely for the camera settings. 396f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li */ 40ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wangpublic class IndicatorControlWheel extends IndicatorControl implements 41ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang View.OnClickListener { 42ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang public static final int HIGHLIGHT_WIDTH = 4; 43ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 44ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private static final String TAG = "IndicatorControlWheel"; 45ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int HIGHLIGHT_DEGREES = 30; 46ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final double HIGHLIGHT_RADIANS = Math.toRadians(HIGHLIGHT_DEGREES); 47ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 48ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The following angles are based in the zero degree on the right. Here we 49ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // have the fix 45 degrees for each sector in the first-level as we have to 50ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // align the zoom button exactly at degree 180. For second-level indicators, 51ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // the indicators located evenly between start and end angle. In addition, 52ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // these indicators for the second-level hidden in the same wheel with 53ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // larger angle values are visible after rotation. 54ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int FIRST_LEVEL_END_DEGREES = 270; 55ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int FIRST_LEVEL_SECTOR_DEGREES = 45; 56ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int SECOND_LEVEL_START_DEGREES = 60; 57ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int SECOND_LEVEL_END_DEGREES = 300; 58ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int CLOSE_ICON_DEFAULT_DEGREES = 315; 59ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang private static final int ZOOM_ICON_DEFAULT_DEGREES = 180; 60ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 61ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private static final int ANIMATION_TIME = 300; // milliseconds 62bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang 63e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan // The width of the edges on both sides of the wheel, which has less alpha. 64e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan private static final float EDGE_STROKE_WIDTH = 6f; 65a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li private static final int TIME_LAPSE_ARC_WIDTH = 6; 66e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan 67e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan private final int HIGHLIGHT_COLOR; 68a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li private final int TIME_LAPSE_ARC_COLOR; 69e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan 7080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li // The center of the shutter button. 71f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li private int mCenterX, mCenterY; 7280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li // The width of the wheel stroke. 73ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private int mStrokeWidth; 74f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li private double mShutterButtonRadius; 7580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li private double mWheelRadius; 76ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private double mChildRadians[]; 7780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li private Paint mBackgroundPaint; 7880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li private RectF mBackgroundRect; 79e5fe56fec047dec5ccb12c2001bacfd9455352daWu-cheng Li // The index of the child that is being pressed. -1 means no child is being 80e5fe56fec047dec5ccb12c2001bacfd9455352daWu-cheng Li // pressed. 81039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li private int mPressedIndex = -1; 82dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li 83a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Time lapse recording variables. 84a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li private int mTimeLapseInterval; // in ms 85a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li private long mRecordingStartTime = 0; 86a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li private long mNumberOfFrames = 0; 87a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 88ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Remember the last event for event cancelling if out of bound. 89ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private MotionEvent mLastMotionEvent; 90ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 91ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView mSecondLevelIcon; 92ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView mCloseIcon; 93ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 94ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Variables for animation. 95ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private long mAnimationStartTime; 96ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private boolean mInAnimation = false; 97ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private Handler mHandler = new Handler(); 98ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private final Runnable mRunnable = new Runnable() { 99ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void run() { 100ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 101ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 102ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang }; 103ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 104ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Variables for level control. 105ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int mCurrentLevel = 0; 106ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int mSecondLevelStartIndex = -1; 107ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mStartVisibleRadians[] = new double[2]; 108ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mEndVisibleRadians[] = new double[2]; 109ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mSectorRadians[] = new double[2]; 110ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mTouchSectorRadians[] = new double[2]; 111ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 112b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang private ImageView mZoomIcon; 113ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 114ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang public IndicatorControlWheel(Context context, AttributeSet attrs) { 11580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li super(context, attrs); 116e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan Resources resources = context.getResources(); 117e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan HIGHLIGHT_COLOR = resources.getColor(R.color.review_control_pressed_color); 118a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li TIME_LAPSE_ARC_COLOR = resources.getColor(R.color.time_lapse_arc); 119bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang 12080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li setWillNotDraw(false); 12180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 12280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint = new Paint(); 12380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint.setStyle(Paint.Style.STROKE); 12480715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint.setAntiAlias(true); 12580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 12680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundRect = new RectF(); 127ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 128ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 129ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int getChildCountByLevel(int level) { 130ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Get current child count by level. 131ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (level == 1) { 132ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (getChildCount() - mSecondLevelStartIndex); 133ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } else { 134ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return mSecondLevelStartIndex; 135ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 136ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 137ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 138ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang @Override 139ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void onClick(View view) { 140ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (view == mZoomIcon) return; 141ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mPressedIndex = -1; 142ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang dismissSettingPopup(); 143ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mInAnimation = true; 144ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mAnimationStartTime = SystemClock.uptimeMillis(); 145ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 14680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li } 14780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 14895788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang public void initialize(Context context, PreferenceGroup group, 149ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang String flashSetting, boolean isZoomSupported, String[] keys, 150ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang String[] otherSettingKeys) { 151ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS; 152ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH); 153ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5; 154ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 155ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang setPreferenceGroup(group); 156ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 157ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add first-level controls. 158ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang addControls(new String[] {flashSetting}, null); 159ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 160ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Add Zoom Icon. 161ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (isZoomSupported) { 162ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mZoomIcon = (ImageView) addImageButton(context, R.drawable.ic_zoom_holo_light, false); 163ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 1640935e09bb12a1886a801713bbd78bbc20bf4ea4eChih-yu Huang 165ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Add CameraPicker. 166ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang initializeCameraPicker(); 1670935e09bb12a1886a801713bbd78bbc20bf4ea4eChih-yu Huang 168ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add second-level Indicator Icon. 169ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon = addImageButton(context, R.drawable.ic_settings_holo_light, true); 170ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelStartIndex = getChildCount(); 171ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 172ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add second-level buttons. 173ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon = addImageButton(context, R.drawable.btn_wheel_close_settings, false); 174ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang addControls(keys, otherSettingKeys); 175ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 176ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The angle(in radians) of each icon for touch events. 177ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mChildRadians = new double[getChildCount()]; 178ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang presetFirstLevelChildRadians(); 179ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang presetSecondLevelChildRadians(); 180ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 181ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 182ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView addImageButton(Context context, int resourceId, boolean rotatable) { 183b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang ImageView view; 184b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang if (rotatable) { 185b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang view = new RotateImageView(context); 186b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang } else { 187b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang view = new ColorFilterImageView(context); 188b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang } 189ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setImageResource(resourceId); 190ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setOnClickListener(this); 191ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang addView(view); 192ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return view; 193ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 194ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 195ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private int getTouchIndicatorIndex(double delta) { 196ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The delta is the angle of touch point in radians. 197ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mInAnimation) return -1; 198ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(mCurrentLevel); 199ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (count == 0) return -1; 200ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = (mCurrentLevel == 0) ? 0 : mSecondLevelStartIndex; 201ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang int sectors = count - 1; 202ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Check which indicator is touched. 203ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((delta >= (mStartVisibleRadians[mCurrentLevel] - HIGHLIGHT_RADIANS / 2)) && 204ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang (delta <= (mEndVisibleRadians[mCurrentLevel] + HIGHLIGHT_RADIANS / 2))) { 205ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int index = (int) ((delta - mStartVisibleRadians[mCurrentLevel]) 206ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang / mSectorRadians[mCurrentLevel]); 207ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 208ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // greater than the center of ending indicator 209ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (index > sectors) return (startIndex + sectors); 210ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // less than the center of starting indicator 211ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (index < 0) return startIndex; 212ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 213ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (delta <= (mChildRadians[startIndex + index] 214ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang + mTouchSectorRadians[mCurrentLevel] / 2)) { 215ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (startIndex + index); 216ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 217ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (delta >= (mChildRadians[startIndex + index + 1] 218ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang - mTouchSectorRadians[mCurrentLevel] / 2)) { 219ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (startIndex + index + 1); 220ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 221ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 222ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return -1; 223ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 224ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 225ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private void injectMotionEvent(int viewIndex, MotionEvent event, int action) { 226ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang View v = getChildAt(viewIndex); 227ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang event.setAction(action); 228ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang v.dispatchTouchEvent(event); 22995788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang } 23095788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang 23195788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang @Override 232039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li public boolean dispatchTouchEvent(MotionEvent event) { 233039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li if (!onFilterTouchEventForSecurity(event)) return false; 234ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mLastMotionEvent = event; 235f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li int action = event.getAction(); 236039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 23716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double dx = event.getX() - mCenterX; 23816ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double dy = mCenterY - event.getY(); 23916ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double radius = Math.sqrt(dx * dx + dy * dy); 24016ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li 241ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Ignore the event if too far from the shutter button. 242ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((radius <= (mWheelRadius + mStrokeWidth)) && (radius > mShutterButtonRadius)) { 243f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li double delta = Math.atan2(dy, dx); 244f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li if (delta < 0) delta += Math.PI * 2; 245ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang int index = getTouchIndicatorIndex(delta); 246ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Move over from one indicator to another. 247ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != mPressedIndex) || (action == MotionEvent.ACTION_DOWN)) { 248ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 249ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(mPressedIndex, event, MotionEvent.ACTION_CANCEL); 250ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } else { 251ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Cancel the popup if it is different from the selected. 252ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (getSelectedIndicatorIndex() != index) dismissSettingPopup(); 253ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 254ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != -1) && (action == MotionEvent.ACTION_MOVE)) { 255ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(index, event, MotionEvent.ACTION_DOWN); 256f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li } 257dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 258ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != -1) && (action != MotionEvent.ACTION_MOVE)) { 259ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang View view = getChildAt(index); 260ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Switch to zoom control only if a touch down event is received. 261ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if ((view == mZoomIcon) && (action == MotionEvent.ACTION_DOWN)) { 262ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mPressedIndex = -1; 263ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mOnIndicatorEventListener.onIndicatorEvent( 264ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang OnIndicatorEventListener.EVENT_ENTER_ZOOM_CONTROL); 265ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang return true; 266ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } else { 267ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang getChildAt(index).dispatchTouchEvent(event); 268ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 269ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 270ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Once the button is up, reset the press index. 271ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mPressedIndex = (action == MotionEvent.ACTION_UP) ? -1 : index; 272ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang invalidate(); 273ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return true; 274dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 275039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li // The event is not on any of the child. 276ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang onTouchOutBound(); 277dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li return false; 278dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 2796f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 280ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void rotateWheel() { 281ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int totalDegrees = CLOSE_ICON_DEFAULT_DEGREES - SECOND_LEVEL_START_DEGREES; 282ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startAngle = ((mCurrentLevel == 0) ? CLOSE_ICON_DEFAULT_DEGREES 283ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : SECOND_LEVEL_START_DEGREES); 284ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mCurrentLevel == 0) totalDegrees = -totalDegrees; 285ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 286ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int elapsedTime = (int) (SystemClock.uptimeMillis() - mAnimationStartTime); 287ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (elapsedTime >= ANIMATION_TIME) { 288ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang elapsedTime = ANIMATION_TIME; 289ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCurrentLevel = (mCurrentLevel == 0) ? 1 : 0; 290ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mInAnimation = false; 291ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 292ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 293ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int expectedAngle = startAngle + (totalDegrees * elapsedTime / ANIMATION_TIME); 294ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double increment = Math.toRadians(expectedAngle) 295ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang - mChildRadians[mSecondLevelStartIndex]; 296ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0 ; i < getChildCount(); ++i) mChildRadians[i] += increment; 297ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 298ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 299ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 30080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li @Override 3016f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li protected void onLayout( 3026f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li boolean changed, int left, int top, int right, int bottom) { 303ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mInAnimation) { 304ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang rotateWheel(); 305ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mHandler.post(mRunnable); 306ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 307ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mCenterX = right - left - Util.dpToPixel( 308ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang IndicatorControlWheelContainer.FULL_WHEEL_RADIUS); 30962776cd28a40b4c6ada4b4aa38683f45572ae266Wu-cheng Li mCenterY = (bottom - top) / 2; 3106f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 311ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Layout the indicators based on the current level. 312ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The icons are spreaded on the left side of the shutter button. 313ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < getChildCount(); ++i) { 3146f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li View view = getChildAt(i); 315b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang if (!view.isEnabled()) continue; 316ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double radian = mChildRadians[i]; 317ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double startVisibleRadians = mInAnimation 318ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ? mStartVisibleRadians[1] 319ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : mStartVisibleRadians[mCurrentLevel]; 320ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double endVisibleRadians = mInAnimation 321ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ? mEndVisibleRadians[1] 322ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : mEndVisibleRadians[mCurrentLevel]; 323ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((radian < (startVisibleRadians - HIGHLIGHT_RADIANS / 2)) || 324ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang (radian > (endVisibleRadians + HIGHLIGHT_RADIANS / 2))) { 325ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setVisibility(View.GONE); 326ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang continue; 327ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 328ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setVisibility(View.VISIBLE); 32980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int x = mCenterX + (int)(mWheelRadius * Math.cos(radian)); 33080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int y = mCenterY - (int)(mWheelRadius * Math.sin(radian)); 33180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int width = view.getMeasuredWidth(); 33280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int height = view.getMeasuredHeight(); 3336f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li view.layout(x - width / 2, y - height / 2, x + width / 2, 3346f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li y + height / 2); 335f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li } 3366f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li } 3376f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 338ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void presetFirstLevelChildRadians() { 339ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(0); 340ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int sectors = (count <= 1) ? 0 : (count - 1); 341ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double sectorDegrees = FIRST_LEVEL_SECTOR_DEGREES; 342ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSectorRadians[0] = Math.toRadians(sectorDegrees); 343ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang int zoomIndex = indexOfChild(mZoomIcon); 344ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang double degrees; 345ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 346ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Make sure the zoom button is located at 180 degrees. If there are 347ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // more buttons than we could show in the visible angle from 90 degrees 348ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // to 270 degrees, the modification of FIRST_LEVEL_SECTOR_DEGREES is 349ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // required then. 350ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (zoomIndex >= 0) { 351ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang degrees = ZOOM_ICON_DEFAULT_DEGREES - (zoomIndex * sectorDegrees); 352ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } else { 353ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang degrees = FIRST_LEVEL_END_DEGREES - (sectors * sectorDegrees); 354ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 355ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mStartVisibleRadians[0] = Math.toRadians(degrees); 356ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 357ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = 0; 358ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < count; i++) { 359ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mChildRadians[startIndex + i] = Math.toRadians(degrees); 360ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang degrees += sectorDegrees; 361ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 362ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 363ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The radians for the touch sector of an indicator. 364ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mTouchSectorRadians[0] = HIGHLIGHT_RADIANS; 365ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mEndVisibleRadians[0] = Math.toRadians(FIRST_LEVEL_END_DEGREES); 366ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 367ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 368ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void presetSecondLevelChildRadians() { 369ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(1); 370ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int sectors = (count <= 1) ? 0 : (count - 1); 371ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double sectorDegrees = 372ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ((SECOND_LEVEL_END_DEGREES - SECOND_LEVEL_START_DEGREES) / sectors); 373ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSectorRadians[1] = Math.toRadians(sectorDegrees); 374ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 375ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double degrees = CLOSE_ICON_DEFAULT_DEGREES; 376ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mStartVisibleRadians[1] = Math.toRadians(SECOND_LEVEL_START_DEGREES); 377ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 378ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = mSecondLevelStartIndex; 379ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < count; i++) { 380ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mChildRadians[startIndex + i] = Math.toRadians(degrees); 381ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang degrees += sectorDegrees; 382ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 383ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 384ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The radians for the touch sector of an indicator. 385ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mTouchSectorRadians[1] = 386ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang Math.min(HIGHLIGHT_RADIANS, Math.toRadians(sectorDegrees)); 387ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 388ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mEndVisibleRadians[1] = Math.toRadians(SECOND_LEVEL_END_DEGREES); 389ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 390ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 391a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li public void startTimeLapseAnimation(int timeLapseInterval, long startTime) { 392a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mTimeLapseInterval = timeLapseInterval; 393a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mRecordingStartTime = startTime; 394a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mNumberOfFrames = 0; 395a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li invalidate(); 396a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 397a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 398a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li public void stopTimeLapseAnimation() { 399a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mTimeLapseInterval = 0; 400a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li invalidate(); 401a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 402a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 403039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li private int getSelectedIndicatorIndex() { 404039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li for (int i = 0; i < mIndicators.size(); i++) { 405039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li AbstractIndicatorButton b = mIndicators.get(i); 406039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li if (b.getPopupWindow() != null) { 407039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li return indexOfChild(b); 408039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 409039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 410ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 411ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang View v = getChildAt(mPressedIndex); 412ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (!(v instanceof AbstractIndicatorButton) && v.isEnabled()) { 413ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return mPressedIndex; 414ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 415ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 416039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li return -1; 417039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 418039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 41980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li @Override 42080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li protected void onDraw(Canvas canvas) { 42119d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan // Draw highlight. 42274c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan float delta = mStrokeWidth * 0.5f; 42374c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan float radius = (float) (mWheelRadius + mStrokeWidth * 0.5 + EDGE_STROKE_WIDTH); 424039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li mBackgroundRect.set(mCenterX - radius, mCenterY - radius, mCenterX + radius, 425039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li mCenterY + radius); 426039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 427039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li int selectedIndex = getSelectedIndicatorIndex(); 428039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 429039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li // Draw the highlight arc if an indicator is selected or being pressed. 430ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (selectedIndex >= 0) { 431ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int degree = (int) Math.toDegrees(mChildRadians[selectedIndex]); 43219d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setStrokeWidth(HIGHLIGHT_WIDTH); 43319d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); 43419d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setColor(HIGHLIGHT_COLOR); 435ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang canvas.drawArc(mBackgroundRect, -degree - HIGHLIGHT_DEGREES / 2, 436ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang HIGHLIGHT_DEGREES, false, mBackgroundPaint); 43719d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan } 43819d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan 439a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Draw arc shaped indicator in time lapse recording. 440a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li if (mTimeLapseInterval != 0) { 441a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Setup rectangle and paint. 442a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundRect.set((float)(mCenterX - mShutterButtonRadius), 443a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterY - mShutterButtonRadius), 444a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterX + mShutterButtonRadius), 445a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterY + mShutterButtonRadius)); 446a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundRect.inset(3f, 3f); 447a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setStrokeWidth(TIME_LAPSE_ARC_WIDTH); 448a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); 449a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setColor(TIME_LAPSE_ARC_COLOR); 450a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 451a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Compute the start angle and sweep angle. 452a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li long timeDelta = SystemClock.uptimeMillis() - mRecordingStartTime; 453a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li long numberOfFrames = timeDelta / mTimeLapseInterval; 454248232e937007384328592e0c269b42cf03c6899Wu-cheng Li float sweepAngle; 455a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li if (numberOfFrames > mNumberOfFrames) { 456248232e937007384328592e0c269b42cf03c6899Wu-cheng Li // The arc just acrosses 0 degree. Draw a full circle so it 457248232e937007384328592e0c269b42cf03c6899Wu-cheng Li // looks better. 458248232e937007384328592e0c269b42cf03c6899Wu-cheng Li sweepAngle = 360; 459a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mNumberOfFrames = numberOfFrames; 460a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } else { 461248232e937007384328592e0c269b42cf03c6899Wu-cheng Li sweepAngle = timeDelta % mTimeLapseInterval * 360f / mTimeLapseInterval; 462a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 463a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 464248232e937007384328592e0c269b42cf03c6899Wu-cheng Li canvas.drawArc(mBackgroundRect, 0, sweepAngle, false, mBackgroundPaint); 465248232e937007384328592e0c269b42cf03c6899Wu-cheng Li invalidate(); 466a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 467a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 46880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li super.onDraw(canvas); 46980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li } 470ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 471ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang @Override 472ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void setEnabled(boolean enabled) { 473ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang super.setEnabled(enabled); 474b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang if (mCurrentMode == MODE_VIDEO) { 475b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang mSecondLevelIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); 476b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang mCloseIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); 477b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang requestLayout(); 478ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } else { 479b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang // We also disable the zoom button during snapshot. 480b1ce29490ec61847602ece16f3745417787d3d8fChung-yih Wang if (mZoomIcon != null) mZoomIcon.setEnabled(enabled); 481ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 482ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon.setEnabled(enabled); 483ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon.setEnabled(enabled); 484ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 485ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 486ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang public void onTouchOutBound() { 487ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang dismissSettingPopup(); 488ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 489ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(mPressedIndex, mLastMotionEvent, MotionEvent.ACTION_CANCEL); 490ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mPressedIndex = -1; 491ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang invalidate(); 492ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 493ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 4946f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li} 495