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 {
onCameraSelected(int i)45         public void onCameraSelected(int i);
onShowSwitcherPopup()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 
CameraSwitcher(Context context)66     public CameraSwitcher(Context context) {
67         super(context);
68         init(context);
69     }
70 
CameraSwitcher(Context context, AttributeSet attrs)71     public CameraSwitcher(Context context, AttributeSet attrs) {
72         super(context, attrs);
73         init(context);
74     }
75 
init(Context context)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 
setIds(int[] moduleids, int[] drawids)82     public void setIds(int[] moduleids, int[] drawids) {
83         mDrawIds = drawids;
84         mModuleIds = moduleids;
85     }
86 
setCurrentIndex(int i)87     public void setCurrentIndex(int i) {
88         mCurrentIndex = i;
89         setImageResource(mDrawIds[i]);
90     }
91 
setSwitchListener(CameraSwitchListener l)92     public void setSwitchListener(CameraSwitchListener l) {
93         mListener = l;
94     }
95 
96     @Override
onClick(View v)97     public void onClick(View v) {
98         showSwitcher();
99         mListener.onShowSwitcherPopup();
100     }
101 
onCameraSelected(int ix)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
onDraw(Canvas canvas)111     protected void onDraw(Canvas canvas) {
112         super.onDraw(canvas);
113         mIndicator.setBounds(getDrawable().getBounds());
114         mIndicator.draw(canvas);
115     }
116 
initPopup()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 
showsPopup()159     public boolean showsPopup() {
160         return mShowingPopup;
161     }
162 
isInsidePopup(MotionEvent evt)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 
hidePopup()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 
showSwitcher()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
onTouch(View v, MotionEvent event)193     public boolean onTouch(View v, MotionEvent event) {
194         closePopup();
195         return true;
196     }
197 
closePopup()198     public void closePopup() {
199         if (showsPopup()) {
200             hidePopup();
201         }
202     }
203 
204     @Override
setOrientation(int degree, boolean animate)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 
updateInitialTranslations()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     }
popupAnimationSetup()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 
animateHidePopup()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 
animateShowPopup()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