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
17package com.android.camera.ui;
18
19import android.animation.Animator;
20import android.animation.Animator.AnimatorListener;
21import android.animation.AnimatorListenerAdapter;
22import android.content.Context;
23import android.content.res.Configuration;
24import android.graphics.Canvas;
25import android.graphics.drawable.Drawable;
26import android.util.AttributeSet;
27import android.view.LayoutInflater;
28import android.view.MotionEvent;
29import android.view.View;
30import android.view.View.OnClickListener;
31import android.view.View.OnTouchListener;
32import android.view.ViewGroup;
33import android.widget.LinearLayout;
34
35import com.android.camera.R;
36import com.android.gallery3d.common.ApiHelper;
37
38public 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