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