IndicatorControlWheel.java revision ab2ffa88872149978823c3184d0af162d3cdca13
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 protected final int DISABLED_COLOR; 92ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView mSecondLevelIcon; 93ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView mCloseIcon; 94ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 95ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Variables for animation. 96ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private long mAnimationStartTime; 97ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private boolean mInAnimation = false; 98ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private Handler mHandler = new Handler(); 99ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private final Runnable mRunnable = new Runnable() { 100ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void run() { 101ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 102ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 103ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang }; 104ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 105ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Variables for level control. 106ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int mCurrentLevel = 0; 107ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int mSecondLevelStartIndex = -1; 108ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mStartVisibleRadians[] = new double[2]; 109ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mEndVisibleRadians[] = new double[2]; 110ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mSectorRadians[] = new double[2]; 111ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private double mTouchSectorRadians[] = new double[2]; 112ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 113ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang private View mZoomIcon; 114ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 115ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang public IndicatorControlWheel(Context context, AttributeSet attrs) { 11680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li super(context, attrs); 117e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan Resources resources = context.getResources(); 118e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan HIGHLIGHT_COLOR = resources.getColor(R.color.review_control_pressed_color); 119a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li TIME_LAPSE_ARC_COLOR = resources.getColor(R.color.time_lapse_arc); 120bed7386688cd7810cba23732ab71f370fe3222ffChung-yih Wang 12180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li setWillNotDraw(false); 12280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 12380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint = new Paint(); 12480715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint.setStyle(Paint.Style.STROKE); 12580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundPaint.setAntiAlias(true); 12680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 12780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li mBackgroundRect = new RectF(); 128ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang DISABLED_COLOR = context.getResources().getColor(R.color.icon_disabled_color); 129ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 130ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 131ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private int getChildCountByLevel(int level) { 132ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Get current child count by level. 133ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (level == 1) { 134ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (getChildCount() - mSecondLevelStartIndex); 135ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } else { 136ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return mSecondLevelStartIndex; 137ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 138ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 139ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 140ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang @Override 141ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void onClick(View view) { 142ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (view == mZoomIcon) return; 143ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mPressedIndex = -1; 144ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang dismissSettingPopup(); 145ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mInAnimation = true; 146ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mAnimationStartTime = SystemClock.uptimeMillis(); 147ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 14880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li } 14980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li 15095788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang public void initialize(Context context, PreferenceGroup group, 151ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang String flashSetting, boolean isZoomSupported, String[] keys, 152ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang String[] otherSettingKeys) { 153ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS; 154ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH); 155ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5; 156ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 157ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang setPreferenceGroup(group); 158ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 159ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add first-level controls. 160ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang addControls(new String[] {flashSetting}, null); 161ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 162ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Add Zoom Icon. 163ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (isZoomSupported) { 164ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mZoomIcon = (ImageView) addImageButton(context, R.drawable.ic_zoom_holo_light, false); 165ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 1660935e09bb12a1886a801713bbd78bbc20bf4ea4eChih-yu Huang 167ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Add CameraPicker. 168ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang initializeCameraPicker(); 1690935e09bb12a1886a801713bbd78bbc20bf4ea4eChih-yu Huang 170ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add second-level Indicator Icon. 171ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon = addImageButton(context, R.drawable.ic_settings_holo_light, true); 172ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelStartIndex = getChildCount(); 173ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 174ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Add second-level buttons. 175ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon = addImageButton(context, R.drawable.btn_wheel_close_settings, false); 176ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang addControls(keys, otherSettingKeys); 177ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 178ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The angle(in radians) of each icon for touch events. 179ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mChildRadians = new double[getChildCount()]; 180ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang presetFirstLevelChildRadians(); 181ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang presetSecondLevelChildRadians(); 182ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 183ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 184ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private ImageView addImageButton(Context context, int resourceId, boolean rotatable) { 185ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ImageView view = rotatable ? new RotateImageView(context) : new ImageView(context); 186ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setImageResource(resourceId); 187ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setOnClickListener(this); 188ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang addView(view); 189ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return view; 190ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 191ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 192ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private int getTouchIndicatorIndex(double delta) { 193ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The delta is the angle of touch point in radians. 194ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mInAnimation) return -1; 195ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(mCurrentLevel); 196ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (count == 0) return -1; 197ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = (mCurrentLevel == 0) ? 0 : mSecondLevelStartIndex; 198ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang int sectors = count - 1; 199ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Check which indicator is touched. 200ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((delta >= (mStartVisibleRadians[mCurrentLevel] - HIGHLIGHT_RADIANS / 2)) && 201ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang (delta <= (mEndVisibleRadians[mCurrentLevel] + HIGHLIGHT_RADIANS / 2))) { 202ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int index = (int) ((delta - mStartVisibleRadians[mCurrentLevel]) 203ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang / mSectorRadians[mCurrentLevel]); 204ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 205ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // greater than the center of ending indicator 206ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (index > sectors) return (startIndex + sectors); 207ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // less than the center of starting indicator 208ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (index < 0) return startIndex; 209ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 210ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (delta <= (mChildRadians[startIndex + index] 211ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang + mTouchSectorRadians[mCurrentLevel] / 2)) { 212ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (startIndex + index); 213ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 214ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (delta >= (mChildRadians[startIndex + index + 1] 215ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang - mTouchSectorRadians[mCurrentLevel] / 2)) { 216ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang return (startIndex + index + 1); 217ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 218ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 219ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return -1; 220ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 221ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 222ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang private void injectMotionEvent(int viewIndex, MotionEvent event, int action) { 223ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang View v = getChildAt(viewIndex); 224ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang event.setAction(action); 225ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang v.dispatchTouchEvent(event); 22695788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang } 22795788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang 22895788ace8ad3630312f2f94544690c448c935f9eChung-yih Wang @Override 229039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li public boolean dispatchTouchEvent(MotionEvent event) { 230039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li if (!onFilterTouchEventForSecurity(event)) return false; 231ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mLastMotionEvent = event; 232f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li int action = event.getAction(); 233039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 23416ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double dx = event.getX() - mCenterX; 23516ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double dy = mCenterY - event.getY(); 23616ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li double radius = Math.sqrt(dx * dx + dy * dy); 23716ca94d73bfe07f280e381595709b56c2681b2bcWu-cheng Li 238ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Ignore the event if too far from the shutter button. 239ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((radius <= (mWheelRadius + mStrokeWidth)) && (radius > mShutterButtonRadius)) { 240f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li double delta = Math.atan2(dy, dx); 241f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li if (delta < 0) delta += Math.PI * 2; 242ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang int index = getTouchIndicatorIndex(delta); 243ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Move over from one indicator to another. 244ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != mPressedIndex) || (action == MotionEvent.ACTION_DOWN)) { 245ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 246ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(mPressedIndex, event, MotionEvent.ACTION_CANCEL); 247ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } else { 248ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Cancel the popup if it is different from the selected. 249ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (getSelectedIndicatorIndex() != index) dismissSettingPopup(); 250ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 251ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != -1) && (action == MotionEvent.ACTION_MOVE)) { 252ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(index, event, MotionEvent.ACTION_DOWN); 253f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li } 254dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 255ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if ((index != -1) && (action != MotionEvent.ACTION_MOVE)) { 256ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang View view = getChildAt(index); 257ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Switch to zoom control only if a touch down event is received. 258ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if ((view == mZoomIcon) && (action == MotionEvent.ACTION_DOWN)) { 259ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mPressedIndex = -1; 260ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang mOnIndicatorEventListener.onIndicatorEvent( 261ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang OnIndicatorEventListener.EVENT_ENTER_ZOOM_CONTROL); 262ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang return true; 263ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } else { 264ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang getChildAt(index).dispatchTouchEvent(event); 265ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 266ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 267ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang // Once the button is up, reset the press index. 268ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mPressedIndex = (action == MotionEvent.ACTION_UP) ? -1 : index; 269ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang invalidate(); 270ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return true; 271dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 272039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li // The event is not on any of the child. 273ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang onTouchOutBound(); 274dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li return false; 275dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li } 2766f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 277ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void rotateWheel() { 278ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int totalDegrees = CLOSE_ICON_DEFAULT_DEGREES - SECOND_LEVEL_START_DEGREES; 279ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startAngle = ((mCurrentLevel == 0) ? CLOSE_ICON_DEFAULT_DEGREES 280ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : SECOND_LEVEL_START_DEGREES); 281ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mCurrentLevel == 0) totalDegrees = -totalDegrees; 282ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 283ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int elapsedTime = (int) (SystemClock.uptimeMillis() - mAnimationStartTime); 284ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (elapsedTime >= ANIMATION_TIME) { 285ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang elapsedTime = ANIMATION_TIME; 286ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCurrentLevel = (mCurrentLevel == 0) ? 1 : 0; 287ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mInAnimation = false; 288ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 289ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 290ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int expectedAngle = startAngle + (totalDegrees * elapsedTime / ANIMATION_TIME); 291ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double increment = Math.toRadians(expectedAngle) 292ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang - mChildRadians[mSecondLevelStartIndex]; 293ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0 ; i < getChildCount(); ++i) mChildRadians[i] += increment; 294ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang requestLayout(); 295ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 296ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 29780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li @Override 2986f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li protected void onLayout( 2996f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li boolean changed, int left, int top, int right, int bottom) { 300ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (mInAnimation) { 301ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang rotateWheel(); 302ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mHandler.post(mRunnable); 303ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 304ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mCenterX = right - left - Util.dpToPixel( 305ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang IndicatorControlWheelContainer.FULL_WHEEL_RADIUS); 30662776cd28a40b4c6ada4b4aa38683f45572ae266Wu-cheng Li mCenterY = (bottom - top) / 2; 3076f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 308ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // Layout the indicators based on the current level. 309ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The icons are spreaded on the left side of the shutter button. 310ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < getChildCount(); ++i) { 3116f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li View view = getChildAt(i); 312ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double radian = mChildRadians[i]; 313ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double startVisibleRadians = mInAnimation 314ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ? mStartVisibleRadians[1] 315ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : mStartVisibleRadians[mCurrentLevel]; 316ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double endVisibleRadians = mInAnimation 317ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ? mEndVisibleRadians[1] 318ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang : mEndVisibleRadians[mCurrentLevel]; 319ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if ((radian < (startVisibleRadians - HIGHLIGHT_RADIANS / 2)) || 320ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang (radian > (endVisibleRadians + HIGHLIGHT_RADIANS / 2))) { 321ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setVisibility(View.GONE); 322ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang continue; 323ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 324ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang view.setVisibility(View.VISIBLE); 32580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int x = mCenterX + (int)(mWheelRadius * Math.cos(radian)); 32680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int y = mCenterY - (int)(mWheelRadius * Math.sin(radian)); 32780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int width = view.getMeasuredWidth(); 32880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li int height = view.getMeasuredHeight(); 3296f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li view.layout(x - width / 2, y - height / 2, x + width / 2, 3306f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li y + height / 2); 331f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li } 3326f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li } 3336f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li 334ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void presetFirstLevelChildRadians() { 335ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(0); 336ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int sectors = (count <= 1) ? 0 : (count - 1); 337ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double sectorDegrees = FIRST_LEVEL_SECTOR_DEGREES; 338ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSectorRadians[0] = Math.toRadians(sectorDegrees); 339ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang int zoomIndex = indexOfChild(mZoomIcon); 340ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang double degrees; 341ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang 342ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // Make sure the zoom button is located at 180 degrees. If there are 343ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // more buttons than we could show in the visible angle from 90 degrees 344ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // to 270 degrees, the modification of FIRST_LEVEL_SECTOR_DEGREES is 345ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang // required then. 346ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang if (zoomIndex >= 0) { 347ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang degrees = ZOOM_ICON_DEFAULT_DEGREES - (zoomIndex * sectorDegrees); 348ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } else { 349ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang degrees = FIRST_LEVEL_END_DEGREES - (sectors * sectorDegrees); 350ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang } 351ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mStartVisibleRadians[0] = Math.toRadians(degrees); 352ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 353ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = 0; 354ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < count; i++) { 355ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mChildRadians[startIndex + i] = Math.toRadians(degrees); 356ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang degrees += sectorDegrees; 357ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 358ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 359ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The radians for the touch sector of an indicator. 360ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mTouchSectorRadians[0] = HIGHLIGHT_RADIANS; 361ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mEndVisibleRadians[0] = Math.toRadians(FIRST_LEVEL_END_DEGREES); 362ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 363ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 364ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang private void presetSecondLevelChildRadians() { 365ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int count = getChildCountByLevel(1); 366ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int sectors = (count <= 1) ? 0 : (count - 1); 367ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double sectorDegrees = 368ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang ((SECOND_LEVEL_END_DEGREES - SECOND_LEVEL_START_DEGREES) / sectors); 369ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSectorRadians[1] = Math.toRadians(sectorDegrees); 370ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 371ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang double degrees = CLOSE_ICON_DEFAULT_DEGREES; 372ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mStartVisibleRadians[1] = Math.toRadians(SECOND_LEVEL_START_DEGREES); 373ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 374ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int startIndex = mSecondLevelStartIndex; 375ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang for (int i = 0; i < count; i++) { 376ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mChildRadians[startIndex + i] = Math.toRadians(degrees); 377ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang degrees += sectorDegrees; 378ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 379ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 380ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang // The radians for the touch sector of an indicator. 381ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mTouchSectorRadians[1] = 382ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang Math.min(HIGHLIGHT_RADIANS, Math.toRadians(sectorDegrees)); 383ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 384ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mEndVisibleRadians[1] = Math.toRadians(SECOND_LEVEL_END_DEGREES); 385ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 386ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 387a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li public void startTimeLapseAnimation(int timeLapseInterval, long startTime) { 388a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mTimeLapseInterval = timeLapseInterval; 389a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mRecordingStartTime = startTime; 390a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mNumberOfFrames = 0; 391a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li invalidate(); 392a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 393a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 394a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li public void stopTimeLapseAnimation() { 395a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mTimeLapseInterval = 0; 396a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li invalidate(); 397a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 398a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 399039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li private int getSelectedIndicatorIndex() { 400039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li for (int i = 0; i < mIndicators.size(); i++) { 401039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li AbstractIndicatorButton b = mIndicators.get(i); 402039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li if (b.getPopupWindow() != null) { 403039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li return indexOfChild(b); 404039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 405039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 406ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 407ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang View v = getChildAt(mPressedIndex); 408ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (!(v instanceof AbstractIndicatorButton) && v.isEnabled()) { 409ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang return mPressedIndex; 410ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 411ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 412039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li return -1; 413039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li } 414039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 41580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li @Override 41680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li protected void onDraw(Canvas canvas) { 41719d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan // Draw highlight. 41874c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan float delta = mStrokeWidth * 0.5f; 41974c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan float radius = (float) (mWheelRadius + mStrokeWidth * 0.5 + EDGE_STROKE_WIDTH); 420039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li mBackgroundRect.set(mCenterX - radius, mCenterY - radius, mCenterX + radius, 421039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li mCenterY + radius); 422039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 423039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li int selectedIndex = getSelectedIndicatorIndex(); 424039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li 425039f1dc1fd89b5baeed8be05f3f21770cf75d4b3Wu-cheng Li // Draw the highlight arc if an indicator is selected or being pressed. 426ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (selectedIndex >= 0) { 427ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang int degree = (int) Math.toDegrees(mChildRadians[selectedIndex]); 42819d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setStrokeWidth(HIGHLIGHT_WIDTH); 42919d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); 43019d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan mBackgroundPaint.setColor(HIGHLIGHT_COLOR); 431ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang canvas.drawArc(mBackgroundRect, -degree - HIGHLIGHT_DEGREES / 2, 432ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang HIGHLIGHT_DEGREES, false, mBackgroundPaint); 43319d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan } 43419d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan 435a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Draw arc shaped indicator in time lapse recording. 436a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li if (mTimeLapseInterval != 0) { 437a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Setup rectangle and paint. 438a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundRect.set((float)(mCenterX - mShutterButtonRadius), 439a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterY - mShutterButtonRadius), 440a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterX + mShutterButtonRadius), 441a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li (float)(mCenterY + mShutterButtonRadius)); 442a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundRect.inset(3f, 3f); 443a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setStrokeWidth(TIME_LAPSE_ARC_WIDTH); 444a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); 445a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mBackgroundPaint.setColor(TIME_LAPSE_ARC_COLOR); 446a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 447a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li // Compute the start angle and sweep angle. 448a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li long timeDelta = SystemClock.uptimeMillis() - mRecordingStartTime; 449a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li long numberOfFrames = timeDelta / mTimeLapseInterval; 450248232e937007384328592e0c269b42cf03c6899Wu-cheng Li float sweepAngle; 451a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li if (numberOfFrames > mNumberOfFrames) { 452248232e937007384328592e0c269b42cf03c6899Wu-cheng Li // The arc just acrosses 0 degree. Draw a full circle so it 453248232e937007384328592e0c269b42cf03c6899Wu-cheng Li // looks better. 454248232e937007384328592e0c269b42cf03c6899Wu-cheng Li sweepAngle = 360; 455a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li mNumberOfFrames = numberOfFrames; 456a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } else { 457248232e937007384328592e0c269b42cf03c6899Wu-cheng Li sweepAngle = timeDelta % mTimeLapseInterval * 360f / mTimeLapseInterval; 458a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 459a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 460248232e937007384328592e0c269b42cf03c6899Wu-cheng Li canvas.drawArc(mBackgroundRect, 0, sweepAngle, false, mBackgroundPaint); 461248232e937007384328592e0c269b42cf03c6899Wu-cheng Li invalidate(); 462a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li } 463a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li 46480715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li super.onDraw(canvas); 46580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li } 466ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang 467ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang @Override 468ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang public void setEnabled(boolean enabled) { 469ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang super.setEnabled(enabled); 470ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang if (enabled) { 471ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon.clearColorFilter(); 472ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon.clearColorFilter(); 473ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } else { 474ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon.setColorFilter(DISABLED_COLOR); 475ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon.setColorFilter(DISABLED_COLOR); 476ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 477ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mSecondLevelIcon.setEnabled(enabled); 478ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang mCloseIcon.setEnabled(enabled); 479ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang } 480ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang 481ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang public void onTouchOutBound() { 482ed6373cd34393dfdda8d18a03705c83bfff1f535Chung-yih Wang dismissSettingPopup(); 483ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang if (mPressedIndex != -1) { 484ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang injectMotionEvent(mPressedIndex, mLastMotionEvent, MotionEvent.ACTION_CANCEL); 485ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang mPressedIndex = -1; 486ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang invalidate(); 487ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 488ff45331706e2fe361b4ff736d90b0ad4af0e7be9Chung-yih Wang } 4896f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li} 490