Home | History | Annotate | Download | only in ui
      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 android.content.Context;
     20 import android.content.res.Configuration;
     21 import android.util.AttributeSet;
     22 import android.view.MotionEvent;
     23 import android.view.View;
     24 
     25 import com.android.camera.IconListPreference;
     26 import com.android.camera.PreferenceGroup;
     27 import com.android.camera.R;
     28 import com.android.camera.Util;
     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     @SuppressWarnings("unused")
     37     private static final String TAG = "SecondLevelIndicatorControlBar";
     38     private static int ICON_SPACING = Util.dpToPixel(16);
     39     private View mCloseIcon;
     40     private View mDivider; // the divider line
     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 highlight 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         mCloseIcon = findViewById(R.id.back_to_first_level);
     57         mCloseIcon.setOnClickListener(this);
     58         mNonIndicatorButtonCount = getChildCount();
     59     }
     60 
     61     public void initialize(Context context, PreferenceGroup group,
     62             String[] keys, String[] otherSettingKeys) {
     63 
     64         setPreferenceGroup(group);
     65 
     66         // Remove the original setting indicators. This happens when switching
     67         // between front and back cameras.
     68         int count = getChildCount() - mNonIndicatorButtonCount;
     69         if (count > 0) removeControls(mNonIndicatorButtonCount, count);
     70 
     71         addControls(keys, otherSettingKeys);
     72         if (mOrientation != 0) setOrientation(mOrientation, false);
     73 
     74         // Do not grey out the icons when taking a picture.
     75         setupFilter(mCurrentMode != MODE_CAMERA);
     76     }
     77 
     78     @Override
     79     public void onClick(View view) {
     80         dismissSettingPopup();
     81         mOnIndicatorEventListener.onIndicatorEvent(
     82                     OnIndicatorEventListener.EVENT_LEAVE_SECOND_LEVEL_INDICATOR_BAR);
     83     }
     84 
     85     private int getTouchViewIndex(int touchPosition, boolean isLandscape) {
     86         // If the current touch location is on close icon and above.
     87         if (isLandscape) {
     88             if (touchPosition < mCloseIcon.getBottom()) return indexOfChild(mCloseIcon);
     89         } else {
     90             if (touchPosition > mCloseIcon.getLeft()) return indexOfChild(mCloseIcon);
     91         }
     92 
     93         // Calculate if the touch event is on the indicator buttons.
     94         int count = getChildCount();
     95         if (count == mNonIndicatorButtonCount) return -1;
     96         // The baseline will be the first indicator button's top minus spacing.
     97         View firstIndicatorButton = getChildAt(mNonIndicatorButtonCount);
     98         if (isLandscape) {
     99             int baseline = firstIndicatorButton.getTop() - (ICON_SPACING / 2);
    100             if (touchPosition < baseline) return -1;
    101             int iconHeight = firstIndicatorButton.getMeasuredHeight();
    102             int buttonRange = iconHeight + ICON_SPACING;
    103             return (mNonIndicatorButtonCount + ((touchPosition - baseline) / buttonRange));
    104         } else {
    105             int baseline = firstIndicatorButton.getRight() + (ICON_SPACING / 2);
    106             if (touchPosition > baseline) return -1;
    107             int iconWidth = firstIndicatorButton.getMeasuredWidth();
    108             int buttonRange = iconWidth + ICON_SPACING;
    109             return (mNonIndicatorButtonCount + ((baseline - touchPosition) / buttonRange));
    110         }
    111     }
    112 
    113     private void dispatchRelativeTouchEvent(View view, MotionEvent event) {
    114         event.offsetLocation(-view.getLeft(), -view.getTop());
    115         view.dispatchTouchEvent(event);
    116         event.offsetLocation(view.getLeft(), view.getTop());
    117     }
    118 
    119     @Override
    120     public boolean dispatchTouchEvent(MotionEvent event) {
    121         if (!onFilterTouchEventForSecurity(event)) return false;
    122 
    123         int action = event.getAction();
    124         if (!isEnabled()) return false;
    125 
    126         int index = 0;
    127         boolean isLandscape = getResources().getConfiguration().orientation
    128                 == Configuration.ORIENTATION_LANDSCAPE;
    129         // the X (Y) of touch point for portrait (landscape) orientation
    130         int touchPosition = (int) (isLandscape ? event.getY() : event.getX());
    131         // second-level indicator control bar width (height) for portrait
    132         // (landscape) orientation
    133         int controlBarLength = isLandscape ? getHeight() : getWidth();
    134         if (controlBarLength == 0) return false; // the event is sent before onMeasure()
    135         if (touchPosition >= controlBarLength) {
    136             touchPosition = controlBarLength - 1;
    137         }
    138         index = getTouchViewIndex(touchPosition, isLandscape);
    139 
    140         // Cancel the previous target if we moved out of it
    141         if ((mSelectedIndex != -1) && (index != mSelectedIndex)) {
    142             View p = getChildAt(mSelectedIndex);
    143 
    144             int oldAction = event.getAction();
    145             event.setAction(MotionEvent.ACTION_CANCEL);
    146             dispatchRelativeTouchEvent(p, event);
    147             event.setAction(oldAction);
    148 
    149             if (p instanceof AbstractIndicatorButton) {
    150                 AbstractIndicatorButton b = (AbstractIndicatorButton) p;
    151                 b.dismissPopup();
    152             }
    153         }
    154 
    155         // Send event to the target
    156         View v = getChildAt(index);
    157         if (v == null) return true;
    158 
    159         // Change MOVE to DOWN if this is a new target
    160         if (mSelectedIndex != index && action == MotionEvent.ACTION_MOVE) {
    161             event.setAction(MotionEvent.ACTION_DOWN);
    162         }
    163         dispatchRelativeTouchEvent(v, event);
    164         mSelectedIndex = index;
    165         return true;
    166     }
    167 
    168     @Override
    169     public IndicatorButton addIndicator(Context context, IconListPreference pref) {
    170         IndicatorButton b = super.addIndicator(context, pref);
    171         b.setBackgroundResource(R.drawable.bg_pressed);
    172         b.setIndicatorChangeListener(this);
    173         return b;
    174     }
    175 
    176     @Override
    177     public OtherSettingIndicatorButton addOtherSettingIndicator(Context context,
    178             int resId, String[] keys) {
    179         OtherSettingIndicatorButton b =
    180                 super.addOtherSettingIndicator(context, resId, keys);
    181         b.setBackgroundResource(R.drawable.bg_pressed);
    182         b.setIndicatorChangeListener(this);
    183         b.setId(R.id.other_setting_indicator);
    184         return b;
    185     }
    186 
    187     @Override
    188     public void onShowIndicator(View view, boolean showed) {
    189         // Ignore those events if not current popup.
    190         if (!showed && (mPopupedIndicator != view)) return;
    191         mPopupedIndicator = (showed ? view : null);
    192         // Show or dismiss the side indicator highlight.
    193         requestLayout();
    194     }
    195 
    196     @Override
    197     public void setOrientation(int orientation, boolean animation) {
    198         mOrientation = orientation;
    199         super.setOrientation(orientation, animation);
    200     }
    201 
    202     @Override
    203     protected void onLayout(
    204             boolean changed, int left, int top, int right, int bottom) {
    205         int count = getChildCount();
    206         if (count == 0) return;
    207         int width = right - left;
    208         int height = bottom - top;
    209 
    210         if (getResources().getConfiguration().orientation
    211                 == Configuration.ORIENTATION_LANDSCAPE) {
    212             int iconSize = mCloseIcon.getMeasuredHeight();
    213             int padding = getPaddingTop();
    214             // The first icon is close button.
    215             int offset = padding;
    216             mCloseIcon.layout(0, offset, width, (offset + iconSize));
    217             // And layout the divider line.
    218             offset += (iconSize + padding);
    219             mDivider.layout(padding, offset, (width - padding),
    220                     (offset + mDivider.getMeasuredHeight()));
    221             // Layout from the last icon up.
    222             int startY = height - iconSize - padding;
    223             int decrement = iconSize + ICON_SPACING;
    224             for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
    225                 getChildAt(i).layout(0, startY, width, startY + iconSize);
    226                 startY -= decrement;
    227             }
    228         } else {
    229             int iconSize = mCloseIcon.getMeasuredWidth();
    230             int padding = getPaddingLeft();
    231             // Layout from the last icon up.
    232             int offset = padding;
    233             int increment = iconSize + ICON_SPACING;
    234             for (int i = count - 1; i >= mNonIndicatorButtonCount; --i) {
    235                 getChildAt(i).layout(offset, 0, offset + iconSize, height);
    236                 offset += increment;
    237             }
    238             // And layout the divider line.
    239             offset = width - iconSize - 2 * padding;
    240             mDivider.layout(offset, padding,
    241                     (offset + mDivider.getMeasuredWidth()), (height - padding));
    242             offset = width - iconSize - padding;
    243             // The first icon is close button.
    244             mCloseIcon.layout(offset, 0, (offset + iconSize), height);
    245         }
    246    }
    247 
    248     @Override
    249     public void setEnabled(boolean enabled) {
    250         super.setEnabled(enabled);
    251         if (mCurrentMode == MODE_VIDEO) {
    252             mCloseIcon.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
    253         }
    254         mCloseIcon.setEnabled(enabled);
    255     }
    256 }
    257