SecondLevelIndicatorControlBar.java revision 26d88fce15a24362644123af5f0cce79ea572e7b
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(16);
38    private View 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        mCloseIcon = findViewById(R.id.back_to_first_level);
58        mCloseIcon.setOnClickListener(this);
59    }
60
61    public void initialize(Context context, PreferenceGroup group,
62            String[] keys, String[] otherSettingKeys) {
63
64        setPreferenceGroup(group);
65        mNonIndicatorButtonCount = getChildCount();
66        addControls(keys, otherSettingKeys);
67        if (mDegree != 0) setDegree(mDegree);
68    }
69
70    public void onClick(View view) {
71        dismissSettingPopup();
72        mOnIndicatorEventListener.onIndicatorEvent(
73                    OnIndicatorEventListener.EVENT_LEAVE_SECOND_LEVEL_INDICATOR_BAR);
74    }
75
76    private int getTouchViewIndex(int y, int height) {
77        // If the current touch location is on close icon and above.
78        if (y < mCloseIcon.getBottom()) return indexOfChild(mCloseIcon);
79
80        // Calculate if the touch event is on the indicator buttons.
81        int count = getChildCount();
82        if (count == mNonIndicatorButtonCount) return -1;
83        // The baseline will be the first indicator button's top minus spacing.
84        View firstIndicatorButton = getChildAt(mNonIndicatorButtonCount);
85        int baselineY = firstIndicatorButton.getTop() - (ICON_SPACING / 2);
86        if (y < baselineY) return -1;
87        int iconHeight = firstIndicatorButton.getMeasuredHeight();
88        int buttonRange = iconHeight + ICON_SPACING;
89        return (mNonIndicatorButtonCount + (y - baselineY) / buttonRange);
90    }
91
92    @Override
93    public boolean dispatchTouchEvent(MotionEvent event) {
94        if (!onFilterTouchEventForSecurity(event)) return false;
95
96        int action = event.getAction();
97        if (!isEnabled()) return false;
98
99        double x = (double) event.getX();
100        double y = (double) event.getY();
101        int height = getHeight();
102        if (height == 0) return false; // the event is sent before onMeasure()
103        if (x > getWidth()) x = getWidth();
104        if (y >= height) y = height - 1;
105
106        int index = getTouchViewIndex((int) y, height);
107        if (index == -1) return true;
108        View b = getChildAt(index);
109        b.dispatchTouchEvent(event);
110        if ((mSelectedIndex != -1) && (index != mSelectedIndex)) {
111            View v = getChildAt(mSelectedIndex);
112            if (v instanceof AbstractIndicatorButton) {
113                AbstractIndicatorButton c = (AbstractIndicatorButton) v;
114                event.setAction(MotionEvent.ACTION_CANCEL);
115                c.dispatchTouchEvent(event);
116                c.dismissPopup();
117            }
118
119            if (action == MotionEvent.ACTION_MOVE) {
120                event.setAction(MotionEvent.ACTION_DOWN);
121                b.dispatchTouchEvent(event);
122            }
123        }
124        mSelectedIndex = index;
125        return true;
126    }
127
128    @Override
129    public IndicatorButton addIndicator(Context context, IconListPreference pref) {
130        IndicatorButton b = super.addIndicator(context, pref);
131        b.setIndicatorChangeListener(this);
132        return b;
133    }
134
135    @Override
136    public OtherSettingIndicatorButton addOtherSettingIndicator(Context context,
137            int resId, String[] keys) {
138        OtherSettingIndicatorButton b =
139                super.addOtherSettingIndicator(context, resId, keys);
140        b.setIndicatorChangeListener(this);
141        return b;
142    }
143
144    @Override
145    public void onShowIndicator(View view, boolean showed) {
146        // Ignore those events if not current popup.
147        if (!showed && (mPopupedIndicator != view)) return;
148        mPopupedIndicator = (showed ? view : null);
149        // Show or dismiss the side indicator highlight.
150        requestLayout();
151    }
152
153    @Override
154    public void setDegree(int degree) {
155        mDegree = degree;
156        super.setDegree(degree);
157    }
158
159    @Override
160    protected void onLayout(
161            boolean changed, int left, int top, int right, int bottom) {
162        int count = getChildCount();
163        if (count == 0) return;
164        int width = right - left;
165        int height = bottom - top;
166        int iconHeight = mCloseIcon.getMeasuredHeight();
167        int padding = getPaddingTop();
168
169        // The first icon is close button.
170        int offsetY = padding;
171        mCloseIcon.layout(0, padding, width, (padding + iconHeight));
172
173        // And layout the divider line.
174        offsetY += (iconHeight + padding);
175        mDivider.layout(padding, offsetY,
176                (width - padding), (offsetY + mDivider.getMeasuredHeight()));
177
178        // Layout from the last icon up.
179        int startY = height - iconHeight - padding;
180        int decrement = iconHeight + ICON_SPACING;
181        for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
182            getChildAt(i).layout(0, startY, width, startY + iconHeight);
183            startY -= decrement;
184        }
185
186        // Hightlight the selected indicator if exists.
187        if (mPopupedIndicator == null) {
188            mIndicatorHighlight.setVisibility(View.GONE);
189        } else {
190            mIndicatorHighlight.setVisibility(View.VISIBLE);
191            // Keep the top and bottom of the hightlight the same as
192            // the 'active' indicator button.
193            mIndicatorHighlight.layout(0, mPopupedIndicator.getTop(),
194                    mIndicatorHighlight.getLayoutParams().width,
195                    mPopupedIndicator.getBottom());
196        }
197   }
198
199    @Override
200    public void setEnabled(boolean enabled) {
201        super.setEnabled(enabled);
202        if (mCurrentMode == MODE_VIDEO) {
203            mCloseIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
204        }
205        mCloseIcon.setEnabled(enabled);
206    }
207}
208