IndicatorControlWheel.java revision 248232e937007384328592e0c269b42cf03c6899
16f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li/*
26f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Copyright (C) 2010 The Android Open Source Project
36f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li *
46f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Licensed under the Apache License, Version 2.0 (the "License");
56f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * you may not use this file except in compliance with the License.
66f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * You may obtain a copy of the License at
76f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li *
86f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li *      http://www.apache.org/licenses/LICENSE-2.0
96f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li *
106f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * Unless required by applicable law or agreed to in writing, software
116f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * distributed under the License is distributed on an "AS IS" BASIS,
126f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * See the License for the specific language governing permissions and
146f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li * limitations under the License.
156f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li */
166f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
176f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Lipackage com.android.camera.ui;
186f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
196f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport com.android.camera.ComboPreferences;
207341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Liimport com.android.camera.IconListPreference;
216f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport com.android.camera.PreferenceGroup;
226f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport com.android.camera.R;
236f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
246f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.content.Context;
25e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyanimport android.content.res.Resources;
2680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.Canvas;
2780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.Paint;
2880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Liimport android.graphics.RectF;
29a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Liimport android.os.Handler;
30a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Liimport android.os.SystemClock;
316f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.util.AttributeSet;
326f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.util.Log;
33d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyanimport android.widget.ImageView;
3422898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Liimport android.view.animation.Animation;
3522898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Liimport android.view.animation.AnimationUtils;
367341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Liimport android.view.LayoutInflater;
37dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Liimport android.view.MotionEvent;
386f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.view.ViewGroup;
396f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport android.view.View;
406f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
416f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Liimport java.lang.Math;
427341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Liimport java.util.ArrayList;
436f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
446f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li/**
4580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li * A view that contains shutter button and camera setting indicators. The
4680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li * indicators are spreaded around the shutter button. The first child is always
4780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li * the shutter button.
486f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li */
497341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Lipublic class IndicatorWheel extends ViewGroup implements
507341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        BasicSettingPopup.Listener, OtherSettingsPopup.Listener {
51f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li    private static final String TAG = "IndicatorWheel";
52e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    // The width of the edges on both sides of the wheel, which has less alpha.
53e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    private static final float EDGE_STROKE_WIDTH = 6f;
54e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    private static final int HIGHLIGHT_WIDTH = 4;
55e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    private static final int HIGHLIGHT_DEGREE = 30;
56a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    private static final int TIME_LAPSE_ARC_WIDTH = 6;
57e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan
58e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    private final int HIGHLIGHT_COLOR;
59e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    private final int DISABLED_COLOR;
60a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    private final int TIME_LAPSE_ARC_COLOR;
61e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan
62dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    private Listener mListener;
6380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    // The center of the shutter button.
64f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li    private int mCenterX, mCenterY;
6580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    // The width of the wheel stroke.
6641ac285a1c97b1df78246456effb80de51033323Hung-ying Tyan    private int mStrokeWidth = 60;
6780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    private View mShutterButton;
68f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li    private double mShutterButtonRadius;
6980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    private double mWheelRadius;
70f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li    private double mSectorInitialRadians[];
7180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    private Paint mBackgroundPaint;
7280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    private RectF mBackgroundRect;
734504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    // The index of the indicator that is currently selected.
7419d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan    private int mSelectedIndex = -1;
754504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    // The index of the indicator that has been just de-selected. If users click
764504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    // on the same indicator, we want to dismiss the popup window without
774504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    // opening it again.
784504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    private int mJustDeselectedIndex = -1;
79dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li
80a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    // Time lapse recording variables.
81a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    private int mTimeLapseInterval;  // in ms
82a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    private long mRecordingStartTime = 0;
83a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    private long mNumberOfFrames = 0;
84a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
857341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private Context mContext;
867341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private PreferenceGroup mPreferenceGroup;
877341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private ArrayList<String> mPreferenceKeys;
887341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private BasicSettingPopup[] mBasicSettingPopups;
897341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private OtherSettingsPopup mOtherSettingsPopup;
907341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
9122898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li    private Animation mFadeIn, mFadeOut;
9222898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li    // The previous view that has the animation. The animation may have stopped.
9322898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li    private View mPrevAnimatingView;
9422898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li
95dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    static public interface Listener {
967341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        public void onSharedPreferenceChanged();
977341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        public void onRestorePreferencesClicked();
987341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        public void onOverriddenPreferencesClicked();
99dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    }
100dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li
101dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    public void setListener(Listener listener) {
102dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li        mListener = listener;
103dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    }
104dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li
10580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    public IndicatorWheel(Context context, AttributeSet attrs) {
10680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        super(context, attrs);
1077341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mContext = context;
108e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        Resources resources = context.getResources();
109e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        HIGHLIGHT_COLOR = resources.getColor(R.color.review_control_pressed_color);
110e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        DISABLED_COLOR = resources.getColor(R.color.icon_disabled_color);
111a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        TIME_LAPSE_ARC_COLOR = resources.getColor(R.color.time_lapse_arc);
11280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        setWillNotDraw(false);
11380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li
11480715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mBackgroundPaint = new Paint();
11580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mBackgroundPaint.setStyle(Paint.Style.STROKE);
11680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mBackgroundPaint.setAntiAlias(true);
11780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li
11880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mBackgroundRect = new RectF();
11922898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li
12022898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        mFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.grow_fade_in_from_right);
12122898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        mFadeOut = AnimationUtils.loadAnimation(mContext, R.anim.shrink_fade_out_from_right);
12280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    }
12380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li
1244504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    public boolean onInterceptTouchEvent(MotionEvent ev) {
1254504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        // If the event will go to shutter button, dismiss the popup window now.
1264504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        // If not, handle it in onTouchEvent.
1274504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
1284504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            float x = ev.getX();
1294504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            float y = ev.getY();
1304504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            float shutterButtonX = mShutterButton.getX();
1314504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            float shutterButtonY = mShutterButton.getY();
1324504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            if (x >= shutterButtonX && y >= shutterButtonY
1334504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                    && (x < shutterButtonX + mShutterButton.getWidth())
1344504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                    && (y < shutterButtonY + mShutterButton.getHeight()))
1354504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                dismissSettingPopup();
1364504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        }
1374504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        return false;
1384504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    }
1394504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li
140dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    @Override
141dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    public boolean onTouchEvent(MotionEvent event) {
1421c62e1b83c2fdda82c726bf712324444136fdc5dHung-ying Tyan        if (!isEnabled()) return false;
1431c62e1b83c2fdda82c726bf712324444136fdc5dHung-ying Tyan
144f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        int count = getChildCount();
1457341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (count <= 1) return false;
146f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li
147f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        // Check if any setting is pressed.
148f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        int action = event.getAction();
1497341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE) {
1507341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            return false;
1517341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
152f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li
1537341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        double dx = event.getX() - mCenterX;
1547341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        double dy = mCenterY - event.getY();
1557341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        double radius = Math.sqrt(dx * dx + dy * dy);
1567341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        // Ignore the event if it's too near to the shutter button or too far
1577341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        // from the shutter button.
1587341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
1597341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (radius >= mShutterButtonRadius && radius <= mWheelRadius + mStrokeWidth) {
160f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            double delta = Math.atan2(dy, dx);
161f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            if (delta < 0) delta += Math.PI * 2;
162f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            // Check which sector is pressed.
163f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            if (delta > mSectorInitialRadians[0]) {
164f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                for (int i = 1; i < count; i++) {
165f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                    if (delta < mSectorInitialRadians[i]) {
1664504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        // If the touch is moving around the same indicator with
1674504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        // popup opened, return now to avoid redundent works.
1684504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        if (action == MotionEvent.ACTION_MOVE && (mSelectedIndex == i - 1)) {
1694504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                            return false;
1704504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        }
1714504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li
1724504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        int selectedIndex = mSelectedIndex;
1734504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        dismissSettingPopup();
1744504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li
17519d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan                        // Do nothing if scene mode overrides the setting.
176823d57389b616091827059ca6401f675e416a53bWu-cheng Li                        View child = getChildAt(i);
177823d57389b616091827059ca6401f675e416a53bWu-cheng Li                        if (child instanceof IndicatorButton) {
17819d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan                            if (((IndicatorButton) child).isOverridden()) {
179fba0439b62f19a2a19ff6559c1ae055e910400dbWu-cheng Li                                // Do not notify in ACTION_MOVE to avoid lots of
180fba0439b62f19a2a19ff6559c1ae055e910400dbWu-cheng Li                                // toast being displayed.
1817341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                                if (action == MotionEvent.ACTION_DOWN && mListener != null) {
1827341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                                    mListener.onOverriddenPreferencesClicked();
183fba0439b62f19a2a19ff6559c1ae055e910400dbWu-cheng Li                                }
18419d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan                                return true;
185823d57389b616091827059ca6401f675e416a53bWu-cheng Li                            }
186823d57389b616091827059ca6401f675e416a53bWu-cheng Li                        }
1874504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        if (action == MotionEvent.ACTION_DOWN
1884504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                                && (selectedIndex == i - 1) && (mJustDeselectedIndex != i - 1)) {
1894504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                            // The same indicator is pressed with popup opened.
1904504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                            mJustDeselectedIndex = i - 1;
1914504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        } else {
1924504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                            if ((mJustDeselectedIndex != i - 1)
1934504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                                    || (selectedIndex == -1 && action == MotionEvent.ACTION_DOWN)) {
1944504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                                showSettingPopup(i - 1);
1954504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                                mJustDeselectedIndex = -1;
1964504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                            }
1974504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                        }
198f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                        return true;
199f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                    }
200f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                }
201dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li            }
202dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li        }
2034504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        dismissSettingPopup();
2044504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        mJustDeselectedIndex = -1;
205dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li        return false;
206dfee7f813adb8de209472d24553b860d2515ea0aWu-cheng Li    }
2076f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
20880715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    @Override
20980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    protected void onFinishInflate() {
21080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        super.onFinishInflate();
21180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        // The first view is shutter button.
21280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mShutterButton = getChildAt(0);
213248232e937007384328592e0c269b42cf03c6899Wu-cheng Li        invalidate();
2146f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    }
2156f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
216fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin    public void removeIndicators() {
217fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin        // Remove everything but the shutter button.
218fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin        int count = getChildCount();
219fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin        if (count > 1) {
220fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin            removeViews(1, count - 1);
221fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin        }
222fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin    }
223fec1720cda1be572610c601ef6a6d929fb37be65Andrei Warkentin
2246f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    @Override
2256f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    protected void onMeasure(int widthSpec, int heightSpec) {
2266f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        // Measure all children.
22780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        int childCount = getChildCount();
2286f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
22980715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        for (int i = 0; i < childCount; i++) {
2306f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            getChildAt(i).measure(freeSpec, freeSpec);
2316f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        }
2326f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
2336f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        // Measure myself.
23441ac285a1c97b1df78246456effb80de51033323Hung-ying Tyan        int desiredWidth = (int)(mShutterButton.getMeasuredWidth() * 3);
23541ac285a1c97b1df78246456effb80de51033323Hung-ying Tyan        int desiredHeight = (int)(mShutterButton.getMeasuredHeight() * 4.5) + 2;
2366f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int widthMode = MeasureSpec.getMode(widthSpec);
2376f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int heightMode = MeasureSpec.getMode(heightSpec);
2386f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int measuredWidth, measuredHeight;
2396f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        if (widthMode == MeasureSpec.UNSPECIFIED) {
2406f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredWidth = desiredWidth;
2416f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        } else if (widthMode == MeasureSpec.AT_MOST) {
2426f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredWidth = Math.min(desiredWidth, MeasureSpec.getSize(widthSpec));
2436f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        } else {  // MeasureSpec.EXACTLY
2446f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredWidth = MeasureSpec.getSize(widthSpec);
2456f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        }
2466f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        if (heightMode == MeasureSpec.UNSPECIFIED) {
2476f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredHeight = desiredHeight;
2486f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        } else if (heightMode == MeasureSpec.AT_MOST) {
2496f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredHeight = Math.min(desiredHeight, MeasureSpec.getSize(heightSpec));
2506f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        } else {  // MeasureSpec.EXACTLY
2516f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            measuredHeight = MeasureSpec.getSize(heightSpec);
2526f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        }
2536f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        setMeasuredDimension(measuredWidth, measuredHeight);
2546f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    }
2556f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
2566f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    @Override
2576f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    protected void onLayout(
2586f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            boolean changed, int left, int top, int right, int bottom) {
2596f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int count = getChildCount();
2606f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        if (count == 0) return;
2616f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
2626f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        // Layout the shutter button.
26380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        int shutterButtonWidth = mShutterButton.getMeasuredWidth();
26441ac285a1c97b1df78246456effb80de51033323Hung-ying Tyan        mShutterButtonRadius = shutterButtonWidth / 2.0;
26580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        int shutterButtonHeight = mShutterButton.getMeasuredHeight();
26674c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan        mStrokeWidth = (int) (mShutterButtonRadius * 1.05);
2679bd6c4687e40d86d5de95c3998eae7b079170d42Wu-cheng Li        int innerRadius = (int) (mShutterButtonRadius + mStrokeWidth * 0.84);
26847335563ade2c03ee37621b49a16d5c6905e3531Wu-cheng Li        // 64 is the requirement by UI design. The distance between the center
26947335563ade2c03ee37621b49a16d5c6905e3531Wu-cheng Li        // and the border is 64 pixels. This has to be consistent with the
27047335563ade2c03ee37621b49a16d5c6905e3531Wu-cheng Li        // background.
27147335563ade2c03ee37621b49a16d5c6905e3531Wu-cheng Li        mCenterX = right - left - 64;
27262776cd28a40b4c6ada4b4aa38683f45572ae266Wu-cheng Li        mCenterY = (bottom - top) / 2;
27380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        mShutterButton.layout(mCenterX - shutterButtonWidth / 2,
27480715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li                mCenterY - shutterButtonHeight / 2,
27580715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li                mCenterX + shutterButtonWidth / 2,
27680715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li                mCenterY + shutterButtonHeight / 2);
2776f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
2786f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        // Layout the settings. The icons are spreaded on the left side of the
2796f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        // shutter button. So the angle starts from 90 to 270 degrees.
2806f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        if (count == 1) return;
28174c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan        mWheelRadius = innerRadius + mStrokeWidth * 0.5;
28219d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan        double intervalDegrees = (count == 2) ? 90.0 : 180.0 / (count - 2);
2836f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        double initialDegrees = 90.0;
2846f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        int index = 0;
285f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        for (int i = 0; i < count; i++) {
2866f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            View view = getChildAt(i);
28780715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li            if (view == mShutterButton) continue;
2886f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            double degree = initialDegrees + intervalDegrees * index;
289f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            double radian = Math.toRadians(degree);
29080715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li            int x = mCenterX + (int)(mWheelRadius * Math.cos(radian));
29180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li            int y = mCenterY - (int)(mWheelRadius * Math.sin(radian));
29280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li            int width = view.getMeasuredWidth();
29380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li            int height = view.getMeasuredHeight();
2946f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            view.layout(x - width / 2, y - height / 2, x + width / 2,
2956f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li                    y + height / 2);
2966f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li            index++;
2976f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li        }
2986f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
299f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        // Store the radian intervals for each icon.
300f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        mSectorInitialRadians = new double[count];
301f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        mSectorInitialRadians[0] = Math.toRadians(
302f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                initialDegrees - intervalDegrees / 2.0);
303f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        for (int i = 1; i < count; i++) {
304f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li            mSectorInitialRadians[i] = mSectorInitialRadians[i - 1]
305f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li                    + Math.toRadians(intervalDegrees);
306f5bffc476b8293b30bb500bed2ab7914bb4ca411Wu-cheng Li        }
3076f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li    }
3086f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li
309a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    public void startTimeLapseAnimation(int timeLapseInterval, long startTime) {
310a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        mTimeLapseInterval = timeLapseInterval;
311a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        mRecordingStartTime = startTime;
312a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        mNumberOfFrames = 0;
313a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        invalidate();
314a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    }
315a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
316a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    public void stopTimeLapseAnimation() {
317a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        mTimeLapseInterval = 0;
318a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        invalidate();
319a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li    }
320a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
32180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    @Override
32280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    protected void onDraw(Canvas canvas) {
32319d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan        // Draw highlight.
32474c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan        float delta = mStrokeWidth * 0.5f;
32574c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan        float radius = (float) (mWheelRadius + mStrokeWidth * 0.5 + EDGE_STROKE_WIDTH);
32674c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan        mBackgroundRect.set((float)(mCenterX - radius),
32774c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan                (float)(mCenterY - radius),
32874c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan                (float)(mCenterX + radius),
32974c5164d19fa213c6904639e6e6b0d9e542cbf66Hung-ying Tyan                (float)(mCenterY + radius));
33019d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan        if (mSelectedIndex >= 0) {
33119d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            int count = getChildCount();
33219d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            float initialDegrees = 90.0f;
33319d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            float intervalDegrees = (count <= 2) ? 0.0f : 180.0f / (count - 2);
33419d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            float degree = initialDegrees + intervalDegrees * mSelectedIndex;
33519d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            mBackgroundPaint.setStrokeWidth(HIGHLIGHT_WIDTH);
33619d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
33719d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            mBackgroundPaint.setColor(HIGHLIGHT_COLOR);
33819d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan            canvas.drawArc(mBackgroundRect, -degree - HIGHLIGHT_DEGREE / 2,
33919d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan                    HIGHLIGHT_DEGREE, false, mBackgroundPaint);
34019d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan        }
34119d029b83d65fb2e124f08aa8b98054974fc3acdHung-ying Tyan
342a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        // Draw arc shaped indicator in time lapse recording.
343a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        if (mTimeLapseInterval != 0) {
344a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            // Setup rectangle and paint.
345a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            mBackgroundRect.set((float)(mCenterX - mShutterButtonRadius),
346a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li                    (float)(mCenterY - mShutterButtonRadius),
347a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li                    (float)(mCenterX + mShutterButtonRadius),
348a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li                    (float)(mCenterY + mShutterButtonRadius));
349a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            mBackgroundRect.inset(3f, 3f);
350a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            mBackgroundPaint.setStrokeWidth(TIME_LAPSE_ARC_WIDTH);
351a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
352a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            mBackgroundPaint.setColor(TIME_LAPSE_ARC_COLOR);
353a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
354a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            // Compute the start angle and sweep angle.
355a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            long timeDelta = SystemClock.uptimeMillis() - mRecordingStartTime;
356a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            long numberOfFrames = timeDelta / mTimeLapseInterval;
357248232e937007384328592e0c269b42cf03c6899Wu-cheng Li            float sweepAngle;
358a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            if (numberOfFrames > mNumberOfFrames) {
359248232e937007384328592e0c269b42cf03c6899Wu-cheng Li                // The arc just acrosses 0 degree. Draw a full circle so it
360248232e937007384328592e0c269b42cf03c6899Wu-cheng Li                // looks better.
361248232e937007384328592e0c269b42cf03c6899Wu-cheng Li                sweepAngle = 360;
362a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li                mNumberOfFrames = numberOfFrames;
363a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            } else {
364248232e937007384328592e0c269b42cf03c6899Wu-cheng Li                sweepAngle = timeDelta % mTimeLapseInterval * 360f / mTimeLapseInterval;
365a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li            }
366a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
367248232e937007384328592e0c269b42cf03c6899Wu-cheng Li            canvas.drawArc(mBackgroundRect, 0, sweepAngle, false, mBackgroundPaint);
368248232e937007384328592e0c269b42cf03c6899Wu-cheng Li            invalidate();
369a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li        }
370a18b115b025fe0c3b046348953946c8db07e12ceWu-cheng Li
37180715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li        super.onDraw(canvas);
37280715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li    }
37380715aae46e5a7a9aa378002301ba9d76f093776Wu-cheng Li
374823d57389b616091827059ca6401f675e416a53bWu-cheng Li    // Scene mode may override other camera settings (ex: flash mode).
375823d57389b616091827059ca6401f675e416a53bWu-cheng Li    public void overrideSettings(String key, String value) {
376823d57389b616091827059ca6401f675e416a53bWu-cheng Li        int count = getChildCount();
377823d57389b616091827059ca6401f675e416a53bWu-cheng Li        for (int j = 1; j < count; j++) {
378823d57389b616091827059ca6401f675e416a53bWu-cheng Li            View v = getChildAt(j);
379823d57389b616091827059ca6401f675e416a53bWu-cheng Li            if (v instanceof IndicatorButton) {  // skip the button of "other settings"
380823d57389b616091827059ca6401f675e416a53bWu-cheng Li                IndicatorButton indicator = (IndicatorButton) v;
381823d57389b616091827059ca6401f675e416a53bWu-cheng Li                if (key.equals(indicator.getKey())) {
382823d57389b616091827059ca6401f675e416a53bWu-cheng Li                    indicator.overrideSettings(value);
383b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan                    setEnabled(indicator, (value == null));
384a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan                    break;
385823d57389b616091827059ca6401f675e416a53bWu-cheng Li                }
386823d57389b616091827059ca6401f675e416a53bWu-cheng Li            }
387823d57389b616091827059ca6401f675e416a53bWu-cheng Li        }
388823d57389b616091827059ca6401f675e416a53bWu-cheng Li    }
389d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan
390d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan    // Sets/unsets highlight on the specified setting icon
391d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan    private void setHighlight(int index, boolean enabled) {
392d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan        if ((index < 0) || (index >= getChildCount() - 1)) return;
393d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan        ImageView child = (ImageView) getChildAt(index + 1);
394d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan        if (enabled) {
395d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan            child.setColorFilter(HIGHLIGHT_COLOR);
396d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan        } else {
397d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan            child.clearColorFilter();
398d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan        }
399d09139b23bc06f8e0ecb90dd4048ab9ee374c253Hung-ying Tyan    }
400e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan
401e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    @Override
402e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    public void setEnabled(boolean enabled) {
403e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        super.setEnabled(enabled);
404e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        int count = getChildCount();
405b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan        for (int i = 1; i < count; i++) {
406b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan            setEnabled((ImageView) getChildAt(i), enabled);
407b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan        }
408b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan    }
409b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan
410b28ff297859deeacd9b70c0bb0299862a8606cbcHung-ying Tyan    private void setEnabled(ImageView view, boolean enabled) {
41174d035db6dc5cc98fa3e53689e469155a35aec66Wu-cheng Li        // Do not enable the button if it is overridden by scene mode.
41274d035db6dc5cc98fa3e53689e469155a35aec66Wu-cheng Li        if ((view instanceof IndicatorButton) && ((IndicatorButton) view).isOverridden()) {
41374d035db6dc5cc98fa3e53689e469155a35aec66Wu-cheng Li            enabled = false;
41474d035db6dc5cc98fa3e53689e469155a35aec66Wu-cheng Li        }
41574d035db6dc5cc98fa3e53689e469155a35aec66Wu-cheng Li
416a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan        // Don't do anything if state is not changed so not to interfere with
417a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan        // the "highlight" state.
418a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan        if (view.isEnabled() ^ enabled) {
419a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan            view.setEnabled(enabled);
420a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan            if (enabled) {
421a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan                view.clearColorFilter();
422a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan            } else {
423a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan                view.setColorFilter(DISABLED_COLOR);
424a25ee04fcb7be1a9aabc8bbccf044da70d4b5e88Hung-ying Tyan            }
425e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan        }
426e50d2553aeb9e55504697e2a72759e8f46ee2992Hung-ying Tyan    }
4277341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4287341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    protected boolean addIndicator(
4297341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            Context context, PreferenceGroup group, String key) {
4307341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        IconListPreference pref = (IconListPreference) group.findPreference(key);
4317341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (pref == null) return false;
4327341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        IndicatorButton b = new IndicatorButton(context, pref);
4337341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        addView(b);
4347341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        return true;
4357341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4367341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4377341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private void addOtherSettingIndicator(Context context) {
4387341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        ImageView b = new ImageView(context);
4397341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        b.setImageResource(R.drawable.ic_viewfinder_settings);
4407341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        b.setClickable(false);
4417341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        addView(b);
4427341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4437341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4447341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public void initialize(Context context, PreferenceGroup group,
4457341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            String[] keys, boolean enableOtherSettings) {
4467341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        // Reset the variables and states.
4477341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        dismissSettingPopup();
4487341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        removeIndicators();
4497341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mOtherSettingsPopup = null;
4507341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mSelectedIndex = -1;
4517341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mPreferenceKeys = new ArrayList<String>();
4527341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4537341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        // Initialize all variables and icons.
4547341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mPreferenceGroup = group;
4557341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        for (int i = 0; i < keys.length; i++) {
4567341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            if (addIndicator(context, group, keys[i])) {
4577341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                mPreferenceKeys.add(keys[i]);
4587341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            }
4597341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
4607341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mBasicSettingPopups = new BasicSettingPopup[mPreferenceKeys.size()];
4617341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4627341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (enableOtherSettings) {
4637341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            addOtherSettingIndicator(context);
4647341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
4657341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        requestLayout();
4667341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4677341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4687341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public void onOtherSettingChanged() {
4697341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mListener != null) {
4707341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            mListener.onSharedPreferenceChanged();
4717341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
4727341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4737341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4747341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public void onRestorePreferencesClicked() {
4757341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mListener != null) {
4767341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            mListener.onRestorePreferencesClicked();
4777341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
4787341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4797341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4807341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public void onSettingChanged() {
4817341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        // Update indicator.
4827341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        IndicatorButton indicator = (IndicatorButton) getChildAt(mSelectedIndex + 1);
4837341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        indicator.reloadPreference();
4847341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mListener != null) {
4857341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            mListener.onSharedPreferenceChanged();
4867341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
4877341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
4887341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4897341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private void initializeSettingPopup(int index) {
4907341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        IconListPreference pref = (IconListPreference)
4917341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                mPreferenceGroup.findPreference(mPreferenceKeys.get(index));
4927341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
4937341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
4947341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                Context.LAYOUT_INFLATER_SERVICE);
4957341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        ViewGroup root = (ViewGroup) getRootView().findViewById(R.id.app_root);
4967341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        BasicSettingPopup popup = (BasicSettingPopup) inflater.inflate(
4977341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                R.layout.basic_setting_popup, root, false);
4987341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mBasicSettingPopups[index] = popup;
4997341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        popup.setSettingChangedListener(this);
5007341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        popup.initialize(pref);
5017341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        root.addView(popup);
5027341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5037341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5047341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    private void initializeOtherSettingPopup() {
5057341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
5067341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                Context.LAYOUT_INFLATER_SERVICE);
5077341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        ViewGroup root = (ViewGroup) getRootView().findViewById(R.id.app_root);
5087341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mOtherSettingsPopup = (OtherSettingsPopup) inflater.inflate(
5097341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                R.layout.other_setting_popup, root, false);
5107341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mOtherSettingsPopup.setOtherSettingChangedListener(this);
5117341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        mOtherSettingsPopup.initialize(mPreferenceGroup);
5127341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        root.addView(mOtherSettingsPopup);
5137341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5147341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5154504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li    private void showSettingPopup(int index) {
5164504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        if (index == mSelectedIndex) return;
5174504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li
5184504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        if (index < mBasicSettingPopups.length) {
5194504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li            if (mBasicSettingPopups[index] == null) {
5204504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li                initializeSettingPopup(index);
5217341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            }
5227341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        } else if (mOtherSettingsPopup == null) {
5237341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            initializeOtherSettingPopup();
5247341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5257341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
52622898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        View popup;
52722898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        if (mPrevAnimatingView != null) mPrevAnimatingView.clearAnimation();
5284504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        if (index == mBasicSettingPopups.length) {
52922898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            popup = mOtherSettingsPopup;
5307341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        } else {
53122898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            popup = mBasicSettingPopups[index];
5327341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
53322898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        popup.startAnimation(mFadeIn);
53422898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        popup.setVisibility(View.VISIBLE);
53522898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li        mPrevAnimatingView = popup;
5364504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        setHighlight(index, true);
5374504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        mSelectedIndex = index;
5384504e5b41a0f647ef3e16b1134e130fe3678aebfWu-cheng Li        invalidate();
5397341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5407341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5417341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public boolean dismissSettingPopup() {
5427341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mSelectedIndex >= 0) {
54322898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            View popup;
54422898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            if (mPrevAnimatingView != null) mPrevAnimatingView.clearAnimation();
5457341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            if (mSelectedIndex == mBasicSettingPopups.length) {
54622898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li                popup = mOtherSettingsPopup;
5477341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            } else {
54822898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li                popup = mBasicSettingPopups[mSelectedIndex];
5497341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            }
55022898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            popup.startAnimation(mFadeOut);
55122898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            popup.setVisibility(View.INVISIBLE);
55222898716834e5c08854a8ee1e71dc81a1ea8355eWu-cheng Li            mPrevAnimatingView = popup;
5537341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            setHighlight(mSelectedIndex, false);
5547341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            mSelectedIndex = -1;
5557341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            invalidate();
5567341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            return true;
5577341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5587341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        return false;
5597341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5607341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5617341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public View getActivePopupWindow() {
5627341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mSelectedIndex >= 0) {
5637341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            if (mSelectedIndex == mBasicSettingPopups.length) {
5647341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                return mOtherSettingsPopup;
5657341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            } else {
5667341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li                return mBasicSettingPopups[mSelectedIndex];
5677341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            }
5687341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        } else {
5697341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            return null;
5707341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5717341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5727341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5737341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    // Scene mode may override other camera settings (ex: flash mode).
5747341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    public void overrideSettings(final String ... keyvalues) {
5757341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (keyvalues.length % 2 != 0) {
5767341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            throw new IllegalArgumentException();
5777341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5787341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5797341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        if (mOtherSettingsPopup == null) {
5807341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            initializeOtherSettingPopup();
5817341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5827341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li
5837341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        for (int i = 0; i < keyvalues.length; i += 2) {
5847341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            String key = keyvalues[i];
5857341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            String value = keyvalues[i + 1];
5867341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            overrideSettings(key, value);
5877341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li            mOtherSettingsPopup.overrideSettings(key, value);
5887341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li        }
5897341b9b5d8194c4ab7140977a8c5218e6d83d516Wu-cheng Li    }
5906f2283fbf049ad1f9870a86474af295604d95600Wu-cheng Li}
591