SecondLevelIndicatorControlBar.java revision 5f6e354a6e2a77aa935fcefeb33a9baa67d48aaf
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera.ui;
18
19import com.android.camera.IconListPreference;
20import com.android.camera.PreferenceGroup;
21import com.android.camera.R;
22import com.android.camera.Util;
23
24import android.content.Context;
25import android.util.AttributeSet;
26import android.view.MotionEvent;
27import android.view.View;
28import android.widget.ImageView;
29
30/**
31 * A view that contains camera setting indicators which are spread over a
32 * vertical bar in preview frame.
33 */
34public class SecondLevelIndicatorControlBar extends IndicatorControl implements
35        View.OnClickListener, AbstractIndicatorButton.IndicatorChangeListener {
36    private static final String TAG = "SecondLevelIndicatorControlBar";
37    private static int ICON_SPACING = Util.dpToPixel(24);
38    private ImageView mCloseIcon;
39    private View mDivider; // the divider line
40    private View mIndicatorHighlight; // the side highlight bar
41    private View mPopupedIndicator;
42    int mDegree = 0;
43    int mSelectedIndex = -1;
44    // There are some views in the ViewGroup before adding the indicator buttons,
45    // such as Close icon, divider line and the hightlight bar, we need to
46    // remember the count of the non-indicator buttons for getTouchViewIndex().
47    int mNonIndicatorButtonCount;
48
49    public SecondLevelIndicatorControlBar(Context context, AttributeSet attrs) {
50        super(context, attrs);
51    }
52
53    @Override
54    protected void onFinishInflate() {
55        mDivider = findViewById(R.id.divider);
56        mIndicatorHighlight = findViewById(R.id.indicator_highlight);
57    }
58
59    public void initialize(Context context, PreferenceGroup group,
60            String[] keys, String[] otherSettingKeys) {
61        if (mCloseIcon == null) {
62            mCloseIcon = new ColorFilterImageView(context);
63            mCloseIcon.setImageResource(R.drawable.btn_close_settings);
64            mCloseIcon.setOnClickListener(this);
65            addView(mCloseIcon);
66        }
67        setPreferenceGroup(group);
68        mNonIndicatorButtonCount = getChildCount();
69        addControls(keys, otherSettingKeys);
70        if (mDegree != 0) setDegree(mDegree);
71    }
72
73    public void onClick(View view) {
74        dismissSettingPopup();
75        mOnIndicatorEventListener.onIndicatorEvent(
76                    OnIndicatorEventListener.EVENT_LEAVE_SECOND_LEVEL_INDICATOR_BAR);
77    }
78
79    private int getTouchViewIndex(int y, int height) {
80        // If the current touch location is on close icon and above.
81        if (y < mCloseIcon.getBottom()) return indexOfChild(mCloseIcon);
82
83        // Calculate if the touch event is on the indicator buttons.
84        int count = getChildCount();
85        if (count == mNonIndicatorButtonCount) return -1;
86        // The baseline will be the first indicator button's top minus spacing.
87        View firstIndicatorButton = getChildAt(mNonIndicatorButtonCount);
88        int baselineY = firstIndicatorButton.getTop() - (ICON_SPACING / 2);
89        if (y < baselineY) return -1;
90        int iconHeight = firstIndicatorButton.getMeasuredHeight();
91        int buttonRange = iconHeight + ICON_SPACING;
92        return (mNonIndicatorButtonCount + (y - baselineY) / buttonRange);
93    }
94
95    @Override
96    public boolean dispatchTouchEvent(MotionEvent event) {
97        if (!onFilterTouchEventForSecurity(event)) return false;
98
99        int action = event.getAction();
100        if (!isEnabled()) return false;
101
102        double x = (double) event.getX();
103        double y = (double) event.getY();
104        int height = getHeight();
105        if (height == 0) return false; // the event is sent before onMeasure()
106        if (x > getWidth()) x = getWidth();
107        if (y >= height) y = height - 1;
108
109        int index = getTouchViewIndex((int) y, height);
110        if (index == -1) return true;
111        View b = getChildAt(index);
112        b.dispatchTouchEvent(event);
113        if ((mSelectedIndex != -1) && (index != mSelectedIndex)) {
114            View v = getChildAt(mSelectedIndex);
115            if (v instanceof AbstractIndicatorButton) {
116                AbstractIndicatorButton c = (AbstractIndicatorButton) v;
117                event.setAction(MotionEvent.ACTION_CANCEL);
118                c.dispatchTouchEvent(event);
119                c.dismissPopup();
120            }
121
122            if (action == MotionEvent.ACTION_MOVE) {
123                event.setAction(MotionEvent.ACTION_DOWN);
124                b.dispatchTouchEvent(event);
125            }
126        }
127        mSelectedIndex = index;
128        return true;
129    }
130
131    @Override
132    public IndicatorButton addIndicator(Context context, IconListPreference pref) {
133        IndicatorButton b = super.addIndicator(context, pref);
134        b.setIndicatorChangeListener(this);
135        return b;
136    }
137
138    @Override
139    public OtherSettingIndicatorButton addOtherSettingIndicator(Context context,
140            int resId, String[] keys) {
141        OtherSettingIndicatorButton b =
142                super.addOtherSettingIndicator(context, resId, keys);
143        b.setIndicatorChangeListener(this);
144        return b;
145    }
146
147    @Override
148    public void onShowIndicator(View view, boolean showed) {
149        // Ignore those events if not current popup.
150        if (!showed && (mPopupedIndicator != view)) return;
151        mPopupedIndicator = (showed ? view : null);
152        // Show or dismiss the side indicator highlight.
153        requestLayout();
154    }
155
156    @Override
157    public void setDegree(int degree) {
158        mDegree = degree;
159        super.setDegree(degree);
160    }
161
162    @Override
163    protected void onLayout(
164            boolean changed, int left, int top, int right, int bottom) {
165        int count = getChildCount();
166        if (count == 0) return;
167        int width = right - left;
168        int height = bottom - top;
169        int iconHeight = mCloseIcon.getMeasuredHeight();
170        int padding = getPaddingTop();
171
172        // The first icon is close button.
173        int offsetY = padding;
174        mCloseIcon.layout(0, padding, width, (padding + iconHeight));
175
176        // And layout the divider line.
177        offsetY += (iconHeight + padding);
178        mDivider.layout(padding, offsetY,
179                (width - padding), (offsetY + mDivider.getMeasuredHeight()));
180
181        // Layout from the last icon up.
182        int startY = height - iconHeight - padding;
183        int decrement = iconHeight + ICON_SPACING;
184        for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
185            getChildAt(i).layout(0, startY, width, startY + iconHeight);
186            startY -= decrement;
187        }
188
189        // Hightlight the selected indicator if exists.
190        if (mPopupedIndicator == null) {
191            mIndicatorHighlight.setVisibility(View.GONE);
192        } else {
193            mIndicatorHighlight.setVisibility(View.VISIBLE);
194            // Keep the top and bottom of the hightlight the same as
195            // the 'active' indicator button.
196            mIndicatorHighlight.layout(0, mPopupedIndicator.getTop(),
197                    mIndicatorHighlight.getLayoutParams().width,
198                    mPopupedIndicator.getBottom());
199        }
200   }
201
202    @Override
203    public void setEnabled(boolean enabled) {
204        super.setEnabled(enabled);
205        if (mCurrentMode == MODE_VIDEO) {
206            mCloseIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
207        }
208        mCloseIcon.setEnabled(enabled);
209    }
210}
211