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 48 public SecondLevelIndicatorControlBar(Context context, AttributeSet attrs) { 49 super(context, attrs); 50 } 51 52 @Override 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 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 68 public void onClick(View view) { 69 dismissSettingPopup(); 70 mOnIndicatorEventListener.onIndicatorEvent( 71 OnIndicatorEventListener.EVENT_LEAVE_SECOND_LEVEL_INDICATOR_BAR); 72 } 73 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 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 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 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 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 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 166 public void setOrientation(int orientation) { 167 mOrientation = orientation; 168 super.setOrientation(orientation); 169 } 170 171 @Override 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 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