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