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