1/*
2 * Copyright (C) 2011 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;
18
19import com.android.camera.ui.PopupManager;
20import com.android.camera.ui.Rotatable;
21import com.android.camera.ui.RotateImageView;
22
23import android.content.Context;
24import android.graphics.PorterDuff;
25import android.graphics.drawable.Drawable;
26import android.util.AttributeSet;
27import android.util.Log;
28import android.view.View;
29import android.view.animation.Animation;
30import android.view.animation.Animation.AnimationListener;
31import android.view.animation.AnimationUtils;
32import android.widget.ImageView;
33import android.widget.RelativeLayout;
34
35/**
36 * A widget that includes three mode selections {@code RotateImageView}'s and
37 * a current mode indicator.
38 */
39public class ModePicker extends RelativeLayout implements View.OnClickListener,
40    PopupManager.OnOtherPopupShowedListener, Rotatable {
41    public static final int MODE_CAMERA = 0;
42    public static final int MODE_VIDEO = 1;
43    public static final int MODE_PANORAMA = 2;
44
45    private static final String TAG = "ModePicker";
46    // Total mode number
47    private static final int MODE_NUM = 3;
48
49    /** A callback to be called when the user wants to switch activity. */
50    public interface OnModeChangeListener {
51        // Returns true if the listener agrees that the mode can be changed.
52        public boolean onModeChanged(int newMode);
53    }
54
55    private final int DISABLED_COLOR;
56    private final int CURRENT_MODE_BACKGROUND;
57
58    private OnModeChangeListener mListener;
59    private View mModeSelectionFrame;
60    private RotateImageView mModeSelectionIcon[];
61    private View mCurrentModeFrame;
62    private RotateImageView mCurrentModeIcon[];
63    private View mCurrentModeBar;
64    private boolean mSelectionEnabled;
65
66
67    private int mCurrentMode = 0;
68    private Animation mFadeIn, mFadeOut;
69
70    public ModePicker(Context context, AttributeSet attrs) {
71        super(context, attrs);
72        DISABLED_COLOR = context.getResources().getColor(R.color.icon_disabled_color);
73        CURRENT_MODE_BACKGROUND = R.drawable.btn_mode_background;
74        mFadeIn = AnimationUtils.loadAnimation(
75                context, R.anim.mode_selection_fade_in);
76        mFadeOut = AnimationUtils.loadAnimation(
77                context, R.anim.mode_selection_fade_out);
78        mFadeOut.setAnimationListener(mAnimationListener);
79        PopupManager.getInstance(context).setOnOtherPopupShowedListener(this);
80    }
81
82    protected void onFinishInflate() {
83        super.onFinishInflate();
84
85        mModeSelectionFrame = findViewById(R.id.mode_selection);
86        mModeSelectionIcon = new RotateImageView[MODE_NUM];
87        mModeSelectionIcon[MODE_PANORAMA] =
88                (RotateImageView) findViewById(R.id.mode_panorama);
89        mModeSelectionIcon[MODE_VIDEO] =
90                (RotateImageView) findViewById(R.id.mode_video);
91        mModeSelectionIcon[MODE_CAMERA] =
92                (RotateImageView) findViewById(R.id.mode_camera);
93
94        // The current mode frame is for Phone UI only.
95        mCurrentModeFrame = findViewById(R.id.current_mode);
96        if (mCurrentModeFrame != null) {
97            mCurrentModeIcon = new RotateImageView[MODE_NUM];
98            mCurrentModeIcon[0] = (RotateImageView) findViewById(R.id.mode_0);
99            mCurrentModeIcon[1] = (RotateImageView) findViewById(R.id.mode_1);
100            mCurrentModeIcon[2] = (RotateImageView) findViewById(R.id.mode_2);
101        } else {
102            // current_mode_bar is only for tablet.
103            mCurrentModeBar = findViewById(R.id.current_mode_bar);
104            enableModeSelection(true);
105        }
106        registerOnClickListener();
107    }
108
109    private void registerOnClickListener() {
110        if (mCurrentModeFrame != null) {
111            mCurrentModeFrame.setOnClickListener(this);
112        }
113        for (int i = 0; i < MODE_NUM; ++i) {
114            mModeSelectionIcon[i].setOnClickListener(this);
115        }
116    }
117
118    @Override
119    public void onOtherPopupShowed() {
120        if (mSelectionEnabled) enableModeSelection(false);
121    }
122
123    private AnimationListener mAnimationListener = new AnimationListener() {
124        public void onAnimationEnd(Animation animation) {
125            changeToSelectedMode();
126            mCurrentModeFrame.setVisibility(View.VISIBLE);
127            mModeSelectionFrame.setVisibility(View.GONE);
128        }
129
130        public void onAnimationRepeat(Animation animation) {
131        }
132
133        public void onAnimationStart(Animation animation) {
134        }
135    };
136
137    private void enableModeSelection(boolean enabled) {
138        if (mCurrentModeFrame != null) {
139            mSelectionEnabled = enabled;
140            // Animation Effect is applied on Phone UI only.
141            mModeSelectionFrame.startAnimation(enabled ? mFadeIn : mFadeOut);
142            if (enabled) {
143                mModeSelectionFrame.setVisibility(View.VISIBLE);
144                mCurrentModeFrame.setVisibility(View.GONE);
145            }
146        }
147        updateModeState();
148    }
149
150    private void changeToSelectedMode() {
151        if (mListener != null) {
152            if (mListener.onModeChanged(mCurrentMode)) {
153                Log.e(TAG, "failed:onModeChanged:" + mCurrentMode);
154            }
155        }
156    }
157
158    public void onClick(View view) {
159        if (view == mCurrentModeFrame) {
160            PopupManager.getInstance(getContext()).notifyShowPopup(this);
161            enableModeSelection(true);
162        } else {
163            // Set the selected mode as the current one and switch to it.
164            for (int i = 0; i < MODE_NUM; ++i) {
165                if (view == mModeSelectionIcon[i] && (mCurrentMode != i)) {
166                    setCurrentMode(i);
167                    break;
168                }
169            }
170            if (mCurrentModeBar == null) {
171                enableModeSelection(false);
172            } else {
173                changeToSelectedMode();
174            }
175        }
176    }
177
178    public void setOnModeChangeListener(OnModeChangeListener listener) {
179        mListener = listener;
180    }
181
182    public void setCurrentMode(int mode) {
183        mCurrentMode = mode;
184        updateModeState();
185    }
186
187    public boolean onModeChanged(int mode) {
188        setCurrentMode(mode);
189        return true;
190    }
191
192    public void setOrientation(int orientation) {
193        for (int i = 0; i < MODE_NUM; ++i) {
194            mModeSelectionIcon[i].setOrientation(orientation);
195            if (mCurrentModeFrame != null) {
196                mCurrentModeIcon[i].setOrientation(orientation);
197            }
198        }
199    }
200
201    @Override
202    public void setEnabled(boolean enabled) {
203        super.setEnabled(enabled);
204
205        // Enable or disable the frames.
206        if (mCurrentModeFrame != null) mCurrentModeFrame.setEnabled(enabled);
207        mModeSelectionFrame.setEnabled(enabled);
208
209        // Enable or disable the icons.
210        for (int i = 0; i < MODE_NUM; ++i) {
211            mModeSelectionIcon[i].setEnabled(enabled);
212            if (mCurrentModeFrame != null) mCurrentModeIcon[i].setEnabled(enabled);
213        }
214        if (enabled) updateModeState();
215    }
216
217    private void highlightView(ImageView view, boolean enabled) {
218        if (enabled) {
219            view.clearColorFilter();
220        } else {
221            view.setColorFilter(DISABLED_COLOR, PorterDuff.Mode.SRC_ATOP);
222        }
223    }
224
225    private void updateModeState() {
226        // Grey-out the unselected icons for Phone UI.
227        if (mCurrentModeFrame != null) {
228            for (int i = 0; i < MODE_NUM; ++i) {
229                highlightView(mModeSelectionIcon[i], (i == mCurrentMode));
230            }
231        }
232
233        // Update the current mode icons on the Phone UI. The selected mode
234        // should be in the center of the current mode icon bar.
235        if (mCurrentModeFrame != null) {
236            for (int i = 0, j = 0; i < MODE_NUM; ++i) {
237                int target;
238                if (i == 1) {
239                    // The second icon is always the selected mode.
240                    target = mCurrentMode;
241                } else {
242                    // Set the icons in order of camera, video and panorama.
243                    if (j == mCurrentMode) j++;
244                    target = j++;
245                }
246                mCurrentModeIcon[i].setImageDrawable(
247                        mModeSelectionIcon[target].getDrawable());
248            }
249        }
250    }
251
252    @Override
253    protected void onLayout(
254            boolean changed, int left, int top, int right, int bottom) {
255        super.onLayout(changed, left, top, right, bottom);
256        // Layout the current mode indicator bar.
257        if (mCurrentModeBar != null) {
258            int viewWidth = mModeSelectionIcon[MODE_CAMERA].getWidth();
259            int iconWidth = ((ImageView) mModeSelectionIcon[MODE_CAMERA])
260                    .getDrawable().getIntrinsicWidth();
261            int padding = (viewWidth - iconWidth) / 2;
262            int l = mModeSelectionFrame.getLeft() + mCurrentMode * viewWidth;
263            mCurrentModeBar.layout((l + padding),
264                    (bottom - top - mCurrentModeBar.getHeight()),
265                    (l + padding + iconWidth),
266                    (bottom - top));
267        }
268    }
269}
270