1adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang/* 2adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * Copyright (C) 2011 The Android Open Source Project 3adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * 4adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * you may not use this file except in compliance with the License. 6adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * You may obtain a copy of the License at 7adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * 8adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * http://www.apache.org/licenses/LICENSE-2.0 9adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * 10adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * Unless required by applicable law or agreed to in writing, software 11adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS, 12adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * See the License for the specific language governing permissions and 14adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * limitations under the License. 15adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang */ 16adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 17adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangpackage com.android.camera.ui; 18adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 19adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangimport com.android.camera.R; 20d2202f9677fcc5f3f2b3e950c35aefe80da14a8aChung-yih Wangimport com.android.camera.Util; 21adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 22adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangimport android.content.Context; 23adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangimport android.util.AttributeSet; 24adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangimport android.view.MotionEvent; 25adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangimport android.view.View; 26adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 27adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang/** 28adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang * A view that contains camera zoom control and its layout. 29adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang */ 30adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wangpublic class ZoomControlBar extends ZoomControl { 31adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang private static final String TAG = "ZoomControlBar"; 32606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang private static final int THRESHOLD_FIRST_MOVE = Util.dpToPixel(10); // pixels 33606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang // Space between indicator icon and the zoom-in/out icon. 34606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang private static final int ICON_SPACING = Util.dpToPixel(12); 35606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang 36adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang private View mBar; 37b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang private boolean mStartChanging; 3891d70ce513ffee99b216f88a92650e1b63575289Chung-yih Wang private int mSliderPosition = 0; 39606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang private int mSliderLength; 40d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang private int mWidth; 41d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang private int mIconWidth; 42d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang private int mTotalIconWidth; 43adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 44adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang public ZoomControlBar(Context context, AttributeSet attrs) { 45adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang super(context, attrs); 46adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang mBar = new View(context); 47606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang mBar.setBackgroundResource(R.drawable.zoom_slider_bar); 48adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang addView(mBar); 49adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 50adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 51adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang @Override 52606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang public void setActivated(boolean activated) { 53606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang super.setActivated(activated); 54606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang mBar.setActivated(activated); 55606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang } 56adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 57d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang private int getSliderPosition(int x) { 58b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang // Calculate the absolute offset of the slider in the zoom control bar. 59adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // For left-hand users, as the device is rotated for 180 degree for 60adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // landscape mode, the zoom-in bottom should be on the top, so the 61adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // position should be reversed. 62b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang int pos; // the relative position in the zoom slider bar 63d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang if (mOrientation == 90) { 64d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang pos = mWidth - mTotalIconWidth - x; 65adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } else { 66d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang pos = x - mTotalIconWidth; 67adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 68b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang if (pos < 0) pos = 0; 69606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang if (pos > mSliderLength) pos = mSliderLength; 70606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang return pos; 71606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang } 72606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang 73606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang @Override 74b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang protected void onSizeChanged(int w, int h, int oldw, int oldh) { 75d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mWidth = w; 76d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mIconWidth = mZoomIn.getMeasuredWidth(); 77d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mTotalIconWidth = mIconWidth + ICON_SPACING; 78d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mSliderLength = mWidth - (2 * mTotalIconWidth); 79b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang } 80606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang 81b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang @Override 82b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang public boolean dispatchTouchEvent(MotionEvent event) { 83d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang if (!isEnabled() || (mWidth == 0)) return false; 84606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang int action = event.getAction(); 85adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 86adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang switch (action) { 87adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang case MotionEvent.ACTION_OUTSIDE: 88adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang case MotionEvent.ACTION_CANCEL: 89606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang case MotionEvent.ACTION_UP: 90606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang setActivated(false); 91ab2ffa88872149978823c3184d0af162d3cdca13Chung-yih Wang closeZoomControl(); 92adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang break; 93b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang 94b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang case MotionEvent.ACTION_DOWN: 95606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang setActivated(true); 96b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang mStartChanging = false; 97b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang case MotionEvent.ACTION_MOVE: 98d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang int pos = getSliderPosition((int) event.getX()); 99b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang if (!mStartChanging) { 100b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang // Make sure the movement is large enough before we start 101b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang // changing the zoom. 102b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang int delta = mSliderPosition - pos; 103b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang if ((delta > THRESHOLD_FIRST_MOVE) || 104b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang (delta < -THRESHOLD_FIRST_MOVE)) { 105b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang mStartChanging = true; 106b2bb1a1245be62222eb02f09f350b2e77b7bf67cChung-yih Wang } 107b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang } 108b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang if (mStartChanging) { 109606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang performZoom(1.0d * pos / mSliderLength); 110b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang mSliderPosition = pos; 111b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang } 112adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang requestLayout(); 113adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 114adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang return true; 115adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 116adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 117adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang @Override 1183ebe49d8f1b4defb7cfd4850a14e795aada2ebd1Chih-yu Huang public void setOrientation(int orientation) { 119adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // layout for the left-hand camera control 120d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang if ((orientation == 90) || (mOrientation == 90)) requestLayout(); 1213ebe49d8f1b4defb7cfd4850a14e795aada2ebd1Chih-yu Huang super.setOrientation(orientation); 122adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 123adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang 124adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang @Override 125adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang protected void onLayout( 126adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang boolean changed, int left, int top, int right, int bottom) { 127b7d0a0704e437a1892fbf2a6e5138cf36df9fde8Chung-yih Wang if (mZoomMax == 0) return; 128d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang int height = bottom - top; 129d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mBar.layout(mTotalIconWidth, 0, mWidth - mTotalIconWidth, height); 130adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // For left-hand users, as the device is rotated for 180 degree, 131adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang // the zoom-in button should be on the top. 132606093cd434a89f5ca941d3a6d6e8470eb768c67Chung-yih Wang int pos; // slider position 133175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li int sliderPosition; 134175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li if (mSliderPosition != -1) { // -1 means invalid 135175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li sliderPosition = mSliderPosition; 136175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li } else { 137175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li sliderPosition = (int) ((double) mSliderLength * mZoomIndex / mZoomMax); 138175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li } 139d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang if (mOrientation == 90) { 140d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mZoomIn.layout(0, 0, mIconWidth, height); 141d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mZoomOut.layout(mWidth - mIconWidth, 0, mWidth, height); 142d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang pos = mBar.getRight() - sliderPosition; 143adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } else { 144d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mZoomOut.layout(0, 0, mIconWidth, height); 145d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mZoomIn.layout(mWidth - mIconWidth, 0, mWidth, height); 146d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang pos = mBar.getLeft() + sliderPosition; 147adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang } 148d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang int sliderWidth = mZoomSlider.getMeasuredWidth(); 149d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang mZoomSlider.layout((pos - sliderWidth / 2), 0, 150d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang (pos + sliderWidth / 2), height); 151d2202f9677fcc5f3f2b3e950c35aefe80da14a8aChung-yih Wang } 152175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li 153175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li @Override 154175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li public void setZoomIndex(int index) { 155175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li super.setZoomIndex(index); 156175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li mSliderPosition = -1; // -1 means invalid 157175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li requestLayout(); 158175d7d64e2990e92eb1609f8f706b6f568b22800Wu-cheng Li } 159adab2bddc93bf4af535cb58e7167bf8690d97d8cChung-yih Wang} 160