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 
17 package com.android.camera.ui;
18 
19 import com.android.camera.IconListPreference;
20 import com.android.camera.PreferenceGroup;
21 import com.android.camera.R;
22 import com.android.camera.Util;
23 
24 import android.content.Context;
25 import android.util.AttributeSet;
26 import android.view.MotionEvent;
27 import android.view.View;
28 import 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  */
34 public 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 mPopupedIndicator;
41     int mOrientation = 0;
42     int mSelectedIndex = -1;
43     // There are some views in the ViewGroup before adding the indicator buttons,
44     // such as Close icon, divider line and the hightlight bar, we need to
45     // remember the count of the non-indicator buttons for getTouchViewIndex().
46     int mNonIndicatorButtonCount;
47 
SecondLevelIndicatorControlBar(Context context, AttributeSet attrs)48     public SecondLevelIndicatorControlBar(Context context, AttributeSet attrs) {
49         super(context, attrs);
50     }
51 
52     @Override
onFinishInflate()53     protected void onFinishInflate() {
54         mDivider = findViewById(R.id.divider);
55         mCloseIcon = findViewById(R.id.back_to_first_level);
56         mCloseIcon.setOnClickListener(this);
57     }
58 
initialize(Context context, PreferenceGroup group, String[] keys, String[] otherSettingKeys)59     public void initialize(Context context, PreferenceGroup group,
60             String[] keys, String[] otherSettingKeys) {
61 
62         setPreferenceGroup(group);
63         mNonIndicatorButtonCount = getChildCount();
64         addControls(keys, otherSettingKeys);
65         if (mOrientation != 0) setOrientation(mOrientation);
66     }
67 
onClick(View view)68     public void onClick(View view) {
69         dismissSettingPopup();
70         mOnIndicatorEventListener.onIndicatorEvent(
71                     OnIndicatorEventListener.EVENT_LEAVE_SECOND_LEVEL_INDICATOR_BAR);
72     }
73 
getTouchViewIndex(int x, int width)74     private int getTouchViewIndex(int x, int width) {
75         // If the current touch location is on close icon and above.
76         if (x > mCloseIcon.getLeft()) return indexOfChild(mCloseIcon);
77 
78         // Calculate if the touch event is on the indicator buttons.
79         int count = getChildCount();
80         if (count == mNonIndicatorButtonCount) return -1;
81         // The baseline will be the first indicator button's top minus spacing.
82         View firstIndicatorButton = getChildAt(mNonIndicatorButtonCount);
83         int baselineX = firstIndicatorButton.getRight() + (ICON_SPACING / 2);
84         if (x > baselineX) return -1;
85         int iconWidth = firstIndicatorButton.getMeasuredWidth();
86         int buttonRange = iconWidth + ICON_SPACING;
87         return (mNonIndicatorButtonCount + ((baselineX - x) / buttonRange));
88     }
89 
dispatchRelativeTouchEvent(View view, MotionEvent event)90     private void dispatchRelativeTouchEvent(View view, MotionEvent event) {
91         event.offsetLocation(-view.getLeft(), -view.getTop());
92         view.dispatchTouchEvent(event);
93         event.offsetLocation(view.getLeft(), view.getTop());
94     }
95 
96     @Override
dispatchTouchEvent(MotionEvent event)97     public boolean dispatchTouchEvent(MotionEvent event) {
98         if (!onFilterTouchEventForSecurity(event)) return false;
99 
100         int action = event.getAction();
101         if (!isEnabled()) return false;
102 
103         double x = (double) event.getX();
104         int width = getWidth();
105         if (width == 0) return false; // the event is sent before onMeasure()
106         if (x > width) x = width;
107 
108         int index = getTouchViewIndex((int) x, width);
109 
110         // Cancel the previous target if we moved out of it
111         if ((mSelectedIndex != -1) && (index != mSelectedIndex)) {
112             View p = getChildAt(mSelectedIndex);
113 
114             int oldAction = event.getAction();
115             event.setAction(MotionEvent.ACTION_CANCEL);
116             dispatchRelativeTouchEvent(p, event);
117             event.setAction(oldAction);
118 
119             if (p instanceof AbstractIndicatorButton) {
120                 AbstractIndicatorButton b = (AbstractIndicatorButton) p;
121                 b.dismissPopup();
122             }
123         }
124 
125         // Send event to the target
126         View v = getChildAt(index);
127         if (v == null) return true;
128 
129         // Change MOVE to DOWN if this is a new target
130         if (mSelectedIndex != index && action == MotionEvent.ACTION_MOVE) {
131             event.setAction(MotionEvent.ACTION_DOWN);
132         }
133         dispatchRelativeTouchEvent(v, event);
134         mSelectedIndex = index;
135         return true;
136     }
137 
138     @Override
addIndicator(Context context, IconListPreference pref)139     public IndicatorButton addIndicator(Context context, IconListPreference pref) {
140         IndicatorButton b = super.addIndicator(context, pref);
141         b.setBackgroundResource(R.drawable.bg_pressed);
142         b.setIndicatorChangeListener(this);
143         return b;
144     }
145 
146     @Override
addOtherSettingIndicator(Context context, int resId, String[] keys)147     public OtherSettingIndicatorButton addOtherSettingIndicator(Context context,
148             int resId, String[] keys) {
149         OtherSettingIndicatorButton b =
150                 super.addOtherSettingIndicator(context, resId, keys);
151         b.setBackgroundResource(R.drawable.bg_pressed);
152         b.setIndicatorChangeListener(this);
153         return b;
154     }
155 
156     @Override
onShowIndicator(View view, boolean showed)157     public void onShowIndicator(View view, boolean showed) {
158         // Ignore those events if not current popup.
159         if (!showed && (mPopupedIndicator != view)) return;
160         mPopupedIndicator = (showed ? view : null);
161         // Show or dismiss the side indicator highlight.
162         requestLayout();
163     }
164 
165     @Override
setOrientation(int orientation)166     public void setOrientation(int orientation) {
167         mOrientation = orientation;
168         super.setOrientation(orientation);
169     }
170 
171     @Override
onLayout( boolean changed, int left, int top, int right, int bottom)172     protected void onLayout(
173             boolean changed, int left, int top, int right, int bottom) {
174         int count = getChildCount();
175         if (count == 0) return;
176         int width = right - left;
177         int height = bottom - top;
178         int iconWidth = mCloseIcon.getMeasuredWidth();
179         int padding = getPaddingLeft();
180 
181         // Layout from the last icon up.
182         int offsetX = padding;
183         int increment = iconWidth + ICON_SPACING;
184         for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
185             getChildAt(i).layout(offsetX, 0, offsetX + iconWidth, height);
186             offsetX += increment;
187         }
188 
189         // And layout the divider line.
190         offsetX = width - iconWidth - 2 * padding;
191         mDivider.layout(offsetX, padding, (offsetX + mDivider.getMeasuredWidth()),
192                 (height - padding));
193 
194         offsetX = width - iconWidth - padding;
195         // The first icon is close button.
196         mCloseIcon.layout(offsetX, 0, (offsetX + iconWidth), height);
197    }
198 
199     @Override
setEnabled(boolean enabled)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