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 
17 package com.android.camera;
18 
19 import com.android.camera.ui.PopupManager;
20 import com.android.camera.ui.Rotatable;
21 import com.android.camera.ui.RotateImageView;
22 
23 import android.content.Context;
24 import android.graphics.PorterDuff;
25 import android.graphics.drawable.Drawable;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 import android.view.View;
29 import android.view.animation.Animation;
30 import android.view.animation.Animation.AnimationListener;
31 import android.view.animation.AnimationUtils;
32 import android.widget.ImageView;
33 import android.widget.RelativeLayout;
34 
35 /**
36  * A widget that includes three mode selections {@code RotateImageView}'s and
37  * a current mode indicator.
38  */
39 public 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.
onModeChanged(int newMode)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 
ModePicker(Context context, AttributeSet attrs)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 
onFinishInflate()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 
registerOnClickListener()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
onOtherPopupShowed()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 
enableModeSelection(boolean enabled)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 
changeToSelectedMode()150     private void changeToSelectedMode() {
151         if (mListener != null) {
152             if (mListener.onModeChanged(mCurrentMode)) {
153                 Log.e(TAG, "failed:onModeChanged:" + mCurrentMode);
154             }
155         }
156     }
157 
onClick(View view)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 
setOnModeChangeListener(OnModeChangeListener listener)178     public void setOnModeChangeListener(OnModeChangeListener listener) {
179         mListener = listener;
180     }
181 
setCurrentMode(int mode)182     public void setCurrentMode(int mode) {
183         mCurrentMode = mode;
184         updateModeState();
185     }
186 
onModeChanged(int mode)187     public boolean onModeChanged(int mode) {
188         setCurrentMode(mode);
189         return true;
190     }
191 
setOrientation(int orientation)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
setEnabled(boolean enabled)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 
highlightView(ImageView view, boolean enabled)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 
updateModeState()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
onLayout( boolean changed, int left, int top, int right, int bottom)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