SecondLevelIndicatorControlBar.java revision ef525b617650c1a6d5968e0ff5c539990705d67f
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 mOrientation = 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 (mOrientation != 0) setOrientation(mOrientation);
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 x, int width) {
77        // If the current touch location is on close icon and above.
78        if (x > mCloseIcon.getLeft()) 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 baselineX = firstIndicatorButton.getRight() + (ICON_SPACING / 2);
86        if (x > baselineX) return -1;
87        int iconWidth = firstIndicatorButton.getMeasuredWidth();
88        int buttonRange = iconWidth + ICON_SPACING;
89        return (mNonIndicatorButtonCount + ((baselineX - x) / buttonRange));
90    }
91
92    private void dispatchRelativeTouchEvent(View view, MotionEvent event) {
93        event.offsetLocation(-view.getLeft(), -view.getTop());
94        view.dispatchTouchEvent(event);
95        event.offsetLocation(view.getLeft(), view.getTop());
96    }
97
98    @Override
99    public boolean dispatchTouchEvent(MotionEvent event) {
100        if (!onFilterTouchEventForSecurity(event)) return false;
101
102        int action = event.getAction();
103        if (!isEnabled()) return false;
104
105        double x = (double) event.getX();
106        double y = (double) event.getY();
107        int width = getWidth();
108        if (width == 0) return false; // the event is sent before onMeasure()
109        if (x > width) x = width;
110        if (y >= getHeight()) y = getHeight() - 1;
111
112        int index = getTouchViewIndex((int) x, width);
113        if (index == -1) return true;
114        View b = getChildAt(index);
115        dispatchRelativeTouchEvent(b, event);
116        if ((mSelectedIndex != -1) && (index != mSelectedIndex)) {
117            View v = getChildAt(mSelectedIndex);
118            if (v instanceof AbstractIndicatorButton) {
119                AbstractIndicatorButton c = (AbstractIndicatorButton) v;
120                event.setAction(MotionEvent.ACTION_CANCEL);
121                dispatchRelativeTouchEvent(c, event);
122                c.dismissPopup();
123            }
124
125            if (action == MotionEvent.ACTION_MOVE) {
126                event.setAction(MotionEvent.ACTION_DOWN);
127                dispatchRelativeTouchEvent(b, event);
128            }
129        }
130        mSelectedIndex = index;
131        return true;
132    }
133
134    @Override
135    public IndicatorButton addIndicator(Context context, IconListPreference pref) {
136        IndicatorButton b = super.addIndicator(context, pref);
137        b.setIndicatorChangeListener(this);
138        return b;
139    }
140
141    @Override
142    public OtherSettingIndicatorButton addOtherSettingIndicator(Context context,
143            int resId, String[] keys) {
144        OtherSettingIndicatorButton b =
145                super.addOtherSettingIndicator(context, resId, keys);
146        b.setIndicatorChangeListener(this);
147        return b;
148    }
149
150    @Override
151    public void onShowIndicator(View view, boolean showed) {
152        // Ignore those events if not current popup.
153        if (!showed && (mPopupedIndicator != view)) return;
154        mPopupedIndicator = (showed ? view : null);
155        // Show or dismiss the side indicator highlight.
156        requestLayout();
157    }
158
159    @Override
160    public void setOrientation(int orientation) {
161        mOrientation = orientation;
162        super.setOrientation(orientation);
163    }
164
165    @Override
166    protected void onLayout(
167            boolean changed, int left, int top, int right, int bottom) {
168        int count = getChildCount();
169        if (count == 0) return;
170        int width = right - left;
171        int height = bottom - top;
172        int iconWidth = mCloseIcon.getMeasuredWidth();
173        int padding = getPaddingLeft();
174
175        // Layout from the last icon up.
176        int offsetX = padding;
177        int increment = iconWidth + ICON_SPACING;
178        for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
179            getChildAt(i).layout(offsetX, 0, offsetX + iconWidth, height);
180            offsetX += increment;
181        }
182
183        // And layout the divider line.
184        offsetX = width - iconWidth - 2 * padding;
185        mDivider.layout(offsetX, padding, (offsetX + mDivider.getMeasuredWidth()),
186                (height - padding));
187
188        offsetX = width - iconWidth - padding;
189        // The first icon is close button.
190        mCloseIcon.layout(offsetX, 0, (offsetX + iconWidth), height);
191
192        // Hightlight the selected indicator if exists.
193        if (mPopupedIndicator == null) {
194            mIndicatorHighlight.setVisibility(View.GONE);
195        } else {
196            mIndicatorHighlight.setVisibility(View.VISIBLE);
197            // Keep the top and bottom of the hightlight the same as
198            // the 'active' indicator button.
199            mIndicatorHighlight.layout(mPopupedIndicator.getLeft(), 0,
200                    mPopupedIndicator.getRight(),
201                    mIndicatorHighlight.getLayoutParams().height);
202        }
203   }
204
205    @Override
206    public void setEnabled(boolean enabled) {
207        super.setEnabled(enabled);
208        if (mCurrentMode == MODE_VIDEO) {
209            mCloseIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
210        }
211        mCloseIcon.setEnabled(enabled);
212    }
213}
214