Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2012 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.animation.Animator;
     20 import android.animation.Animator.AnimatorListener;
     21 import android.animation.AnimatorListenerAdapter;
     22 import android.content.Context;
     23 import android.content.res.Configuration;
     24 import android.graphics.Canvas;
     25 import android.graphics.drawable.Drawable;
     26 import android.util.AttributeSet;
     27 import android.view.LayoutInflater;
     28 import android.view.MotionEvent;
     29 import android.view.View;
     30 import android.view.View.OnClickListener;
     31 import android.view.View.OnTouchListener;
     32 import android.view.ViewGroup;
     33 import android.widget.LinearLayout;
     34 
     35 import com.android.camera.R;
     36 import com.android.gallery3d.common.ApiHelper;
     37 
     38 public class CameraSwitcher extends RotateImageView
     39         implements OnClickListener, OnTouchListener {
     40 
     41     private static final String TAG = "CAM_Switcher";
     42     private static final int SWITCHER_POPUP_ANIM_DURATION = 200;
     43 
     44     public interface CameraSwitchListener {
     45         public void onCameraSelected(int i);
     46         public void onShowSwitcherPopup();
     47     }
     48 
     49     private CameraSwitchListener mListener;
     50     private int mCurrentIndex;
     51     private int[] mModuleIds;
     52     private int[] mDrawIds;
     53     private int mItemSize;
     54     private View mPopup;
     55     private View mParent;
     56     private boolean mShowingPopup;
     57     private boolean mNeedsAnimationSetup;
     58     private Drawable mIndicator;
     59 
     60     private float mTranslationX = 0;
     61     private float mTranslationY = 0;
     62 
     63     private AnimatorListener mHideAnimationListener;
     64     private AnimatorListener mShowAnimationListener;
     65 
     66     public CameraSwitcher(Context context) {
     67         super(context);
     68         init(context);
     69     }
     70 
     71     public CameraSwitcher(Context context, AttributeSet attrs) {
     72         super(context, attrs);
     73         init(context);
     74     }
     75 
     76     private void init(Context context) {
     77         mItemSize = context.getResources().getDimensionPixelSize(R.dimen.switcher_size);
     78         setOnClickListener(this);
     79         mIndicator = context.getResources().getDrawable(R.drawable.ic_switcher_menu_indicator);
     80     }
     81 
     82     public void setIds(int[] moduleids, int[] drawids) {
     83         mDrawIds = drawids;
     84         mModuleIds = moduleids;
     85     }
     86 
     87     public void setCurrentIndex(int i) {
     88         mCurrentIndex = i;
     89         setImageResource(mDrawIds[i]);
     90     }
     91 
     92     public void setSwitchListener(CameraSwitchListener l) {
     93         mListener = l;
     94     }
     95 
     96     @Override
     97     public void onClick(View v) {
     98         showSwitcher();
     99         mListener.onShowSwitcherPopup();
    100     }
    101 
    102     private void onCameraSelected(int ix) {
    103         hidePopup();
    104         if ((ix != mCurrentIndex) && (mListener != null)) {
    105             setCurrentIndex(ix);
    106             mListener.onCameraSelected(mModuleIds[ix]);
    107         }
    108     }
    109 
    110     @Override
    111     protected void onDraw(Canvas canvas) {
    112         super.onDraw(canvas);
    113         mIndicator.setBounds(getDrawable().getBounds());
    114         mIndicator.draw(canvas);
    115     }
    116 
    117     private void initPopup() {
    118         mParent = LayoutInflater.from(getContext()).inflate(R.layout.switcher_popup,
    119                 (ViewGroup) getParent());
    120         LinearLayout content = (LinearLayout) mParent.findViewById(R.id.content);
    121         mPopup = content;
    122         mPopup.setVisibility(View.INVISIBLE);
    123         mNeedsAnimationSetup = true;
    124         for (int i = mDrawIds.length - 1; i >= 0; i--) {
    125             RotateImageView item = new RotateImageView(getContext());
    126             item.setImageResource(mDrawIds[i]);
    127             item.setBackgroundResource(R.drawable.bg_pressed);
    128             final int index = i;
    129             item.setOnClickListener(new OnClickListener() {
    130                 @Override
    131                 public void onClick(View v) {
    132                     onCameraSelected(index);
    133                 }
    134             });
    135             switch (mDrawIds[i]) {
    136                 case R.drawable.ic_switch_camera:
    137                     item.setContentDescription(getContext().getResources().getString(
    138                             R.string.accessibility_switch_to_camera));
    139                     break;
    140                 case R.drawable.ic_switch_video:
    141                     item.setContentDescription(getContext().getResources().getString(
    142                             R.string.accessibility_switch_to_video));
    143                     break;
    144                 case R.drawable.ic_switch_pan:
    145                     item.setContentDescription(getContext().getResources().getString(
    146                             R.string.accessibility_switch_to_panorama));
    147                     break;
    148                 case R.drawable.ic_switch_photosphere:
    149                     item.setContentDescription(getContext().getResources().getString(
    150                             R.string.accessibility_switch_to_new_panorama));
    151                     break;
    152                 default:
    153                     break;
    154             }
    155             content.addView(item, new LinearLayout.LayoutParams(mItemSize, mItemSize));
    156         }
    157     }
    158 
    159     public boolean showsPopup() {
    160         return mShowingPopup;
    161     }
    162 
    163     public boolean isInsidePopup(MotionEvent evt) {
    164         if (!showsPopup()) return false;
    165         return evt.getX() >= mPopup.getLeft()
    166                 && evt.getX() < mPopup.getRight()
    167                 && evt.getY() >= mPopup.getTop()
    168                 && evt.getY() < mPopup.getBottom();
    169     }
    170 
    171     private void hidePopup() {
    172         mShowingPopup = false;
    173         setVisibility(View.VISIBLE);
    174         if (mPopup != null && !animateHidePopup()) {
    175             mPopup.setVisibility(View.INVISIBLE);
    176         }
    177         mParent.setOnTouchListener(null);
    178     }
    179 
    180     private void showSwitcher() {
    181         mShowingPopup = true;
    182         if (mPopup == null) {
    183             initPopup();
    184         }
    185         mPopup.setVisibility(View.VISIBLE);
    186         if (!animateShowPopup()) {
    187             setVisibility(View.INVISIBLE);
    188         }
    189         mParent.setOnTouchListener(this);
    190     }
    191 
    192     @Override
    193     public boolean onTouch(View v, MotionEvent event) {
    194         closePopup();
    195         return true;
    196     }
    197 
    198     public void closePopup() {
    199         if (showsPopup()) {
    200             hidePopup();
    201         }
    202     }
    203 
    204     @Override
    205     public void setOrientation(int degree, boolean animate) {
    206         super.setOrientation(degree, animate);
    207         ViewGroup content = (ViewGroup) mPopup;
    208         if (content == null) return;
    209         for (int i = 0; i < content.getChildCount(); i++) {
    210             RotateImageView iv = (RotateImageView) content.getChildAt(i);
    211             iv.setOrientation(degree, animate);
    212         }
    213     }
    214 
    215     private void updateInitialTranslations() {
    216         if (getResources().getConfiguration().orientation
    217                 == Configuration.ORIENTATION_PORTRAIT) {
    218             mTranslationX = -getWidth() / 2;
    219             mTranslationY = getHeight();
    220         } else {
    221             mTranslationX = getWidth();
    222             mTranslationY = getHeight() / 2;
    223         }
    224     }
    225     private void popupAnimationSetup() {
    226         if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) {
    227             return;
    228         }
    229         updateInitialTranslations();
    230         mPopup.setScaleX(0.3f);
    231         mPopup.setScaleY(0.3f);
    232         mPopup.setTranslationX(mTranslationX);
    233         mPopup.setTranslationY(mTranslationY);
    234         mNeedsAnimationSetup = false;
    235     }
    236 
    237     private boolean animateHidePopup() {
    238         if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) {
    239             return false;
    240         }
    241         if (mHideAnimationListener == null) {
    242             mHideAnimationListener = new AnimatorListenerAdapter() {
    243                 @Override
    244                 public void onAnimationEnd(Animator animation) {
    245                     // Verify that we weren't canceled
    246                     if (!showsPopup()) {
    247                         mPopup.setVisibility(View.INVISIBLE);
    248                     }
    249                 }
    250             };
    251         }
    252         mPopup.animate()
    253                 .alpha(0f)
    254                 .scaleX(0.3f).scaleY(0.3f)
    255                 .translationX(mTranslationX)
    256                 .translationY(mTranslationY)
    257                 .setDuration(SWITCHER_POPUP_ANIM_DURATION)
    258                 .setListener(mHideAnimationListener);
    259         animate().alpha(1f).setDuration(SWITCHER_POPUP_ANIM_DURATION)
    260                 .setListener(null);
    261         return true;
    262     }
    263 
    264     private boolean animateShowPopup() {
    265         if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) {
    266             return false;
    267         }
    268         if (mNeedsAnimationSetup) {
    269             popupAnimationSetup();
    270         }
    271         if (mShowAnimationListener == null) {
    272             mShowAnimationListener = new AnimatorListenerAdapter() {
    273                 @Override
    274                 public void onAnimationEnd(Animator animation) {
    275                     // Verify that we weren't canceled
    276                     if (showsPopup()) {
    277                         setVisibility(View.INVISIBLE);
    278                     }
    279                 }
    280             };
    281         }
    282         mPopup.animate()
    283                 .alpha(1f)
    284                 .scaleX(1f).scaleY(1f)
    285                 .translationX(0)
    286                 .translationY(0)
    287                 .setDuration(SWITCHER_POPUP_ANIM_DURATION)
    288                 .setListener(null);
    289         animate().alpha(0f).setDuration(SWITCHER_POPUP_ANIM_DURATION)
    290                 .setListener(mShowAnimationListener);
    291         return true;
    292     }
    293 }
    294