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