1ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin/*
2ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * Copyright (C) 2010 The Android Open Source Project
3ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin *
4ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * you may not use this file except in compliance with the License.
6ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * You may obtain a copy of the License at
7ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin *
8ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin *
10ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * Unless required by applicable law or agreed to in writing, software
11ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * See the License for the specific language governing permissions and
14ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin * limitations under the License.
15ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin */
16ec1dfcb7314d10ff243a922fe4eff66ea699dd77Owen Lin
174de149ceb47f2c251f646419907424bfb67d2b64Owen Linpackage com.android.camera.ui;
184de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
19281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Linimport static com.android.camera.ui.GLRootView.dpToPixel;
201aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07Owen Lin
211aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07Owen Linimport java.util.ArrayList;
221aaf351f6bbaa0b1dc6c08bd5a590e1930e2ef07Owen Lin
234de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.content.Context;
24c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Linimport android.content.SharedPreferences;
25c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Linimport android.content.SharedPreferences.Editor;
26c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Linimport android.content.SharedPreferences.OnSharedPreferenceChangeListener;
274de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.graphics.Rect;
28706bd006d25aa8f322a9807eda6183a3941ad2c6Owen Linimport android.hardware.Camera.Parameters;
294de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.os.Handler;
304de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.os.Message;
314de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.util.DisplayMetrics;
324de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.view.MotionEvent;
334de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.view.View.MeasureSpec;
344de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.view.animation.AlphaAnimation;
354de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport android.view.animation.Animation;
364de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
374de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport com.android.camera.CameraSettings;
381ef634d277d550ed55b5b7089dfd56ed71815bd6Chih-Chung Changimport com.android.camera.ComboPreferences;
394de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport com.android.camera.IconListPreference;
404de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport com.android.camera.ListPreference;
414de149ceb47f2c251f646419907424bfb67d2b64Owen Linimport com.android.camera.PreferenceGroup;
426988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Linimport com.android.camera.R;
434de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
440d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin// This is the UI for the on-screen settings. Since the rendering is run in the
450d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin// GL thread. If any values will be changed in the main thread, it needs to
460d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin// synchronize on the <code>GLRootView</code> instance.
474de149ceb47f2c251f646419907424bfb67d2b64Owen Linpublic class HeadUpDisplay extends GLView {
48c557947a5897106421fec68b082539317e4b25d0Owen Lin    private static final int INDICATOR_BAR_TIMEOUT = 5500;
49c557947a5897106421fec68b082539317e4b25d0Owen Lin    private static final int POPUP_WINDOW_TIMEOUT = 5000;
50281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static final int INDICATOR_BAR_RIGHT_MARGIN = 10;
51281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static final int POPUP_WINDOW_OVERLAP = 20;
52281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static final int POPUP_TRIANGLE_OFFSET = 16;
53281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin
54bef57e1d1fbb1881a7e3a22bb7567e8e7c2f0795Owen Lin    private static final int COLOR_ICONBAR_HIGHLIGHT = 0x9A2B2B2B;
55bef57e1d1fbb1881a7e3a22bb7567e8e7c2f0795Owen Lin
5673304ce337208aa372836afa6edc4222a6dedde7Wu-cheng Li    private static final float MAX_HEIGHT_RATIO = 0.85f;
574de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private static final float MAX_WIDTH_RATIO = 0.8f;
584de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
59c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    private static final int DESELECT_INDICATOR = 0;
604de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private static final int DEACTIVATE_INDICATOR_BAR = 1;
61281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin
62281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static int sIndicatorBarRightMargin = -1;
63281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static int sPopupWindowOverlap;
64281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static int sPopupTriangleOffset;
65281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin
667b783cb800a90b3f301374f354750292bb75f7aaOwen Lin    private static final String TAG = "HeadUpDisplay";
674de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
68469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    protected IndicatorBar mIndicatorBar;
6933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
701ef634d277d550ed55b5b7089dfd56ed71815bd6Chih-Chung Chang    private ComboPreferences mSharedPrefs;
71469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    private PreferenceGroup mPreferenceGroup;
724de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
734de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private PopupWindow mPopupWindow;
744de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
756988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin    private GLView mAnchorView;
764de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private int mOrientation = 0;
77f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin    private boolean mEnabled = true;
784de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
79469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    protected Listener mListener;
804de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
810d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    private Handler mHandler = new Handler() {
820d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        @Override
830d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        public void handleMessage(Message msg) {
840d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            GLRootView root = getGLRootView();
850d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            if (root != null) {
860d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                synchronized (root) {
870d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    handleMessageLocked(msg);
880d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                }
890d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            } else {
900d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                handleMessageLocked(msg);
910d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            }
920d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
930d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin
940d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        private void handleMessageLocked(Message msg) {
950d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            switch(msg.what) {
960d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                case DESELECT_INDICATOR:
970d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE);
980d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    break;
990d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                case DEACTIVATE_INDICATOR_BAR:
1000d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    if (mIndicatorBar != null) {
1010d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                        mIndicatorBar.setActivated(false);
1020d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    }
1030d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                    break;
1040d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            }
1050d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
1060d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    };
1074de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
108c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    private final OnSharedPreferenceChangeListener mSharedPreferenceChangeListener =
109c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin            new OnSharedPreferenceChangeListener() {
110c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        public void onSharedPreferenceChanged(
111c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin                SharedPreferences sharedPreferences, String key) {
112c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin            if (mListener != null) {
113c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin                mListener.onSharedPreferencesChanged();
114c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin            }
115c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        }
116c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    };
117c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin
118281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    public HeadUpDisplay(Context context) {
119281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin        initializeStaticVariables(context);
120c557947a5897106421fec68b082539317e4b25d0Owen Lin    }
1214de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
122281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    private static void initializeStaticVariables(Context context) {
123281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin        if (sIndicatorBarRightMargin >= 0) return;
124281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin
125281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin        sIndicatorBarRightMargin = dpToPixel(context, INDICATOR_BAR_RIGHT_MARGIN);
126281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin        sPopupWindowOverlap = dpToPixel(context, POPUP_WINDOW_OVERLAP);
127281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin        sPopupTriangleOffset = dpToPixel(context, POPUP_TRIANGLE_OFFSET);
128281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin    }
129281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin
130c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    /**
131c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin     * The callback interface. All the callbacks will be called from the
132c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin     * GLThread.
133c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin     */
1344de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    static public interface Listener {
1354de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        public void onPopupWindowVisibilityChanged(int visibility);
136c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        public void onRestorePreferencesClicked();
137c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        public void onSharedPreferencesChanged();
1384de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
1394de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1404de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    public void overrideSettings(final String ... keyvalues) {
1414de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        GLRootView root = getGLRootView();
1424de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (root != null) {
1430d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            synchronized (root) {
1440d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                overrideSettingsLocked(keyvalues);
1454de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            }
1460d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        } else {
1470d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            overrideSettingsLocked(keyvalues);
1480d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
1490d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    }
1500d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin
1510d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    public void overrideSettingsLocked(final String ... keyvalues) {
1520d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (keyvalues.length % 2 != 0) {
1530d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            throw new IllegalArgumentException();
1540d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
1550d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        for (int i = 0, n = keyvalues.length; i < n; i += 2) {
1560d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            mIndicatorBar.overrideSettings(keyvalues[i], keyvalues[i + 1]);
1574de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
1584de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
1594de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1604de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    @Override
1614de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    protected void onLayout(
1624de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            boolean changed, int left, int top, int right, int bottom) {
1634de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int width = right - left;
1644de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int height = bottom - top;
1654de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mIndicatorBar.measure(
1664de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                MeasureSpec.makeMeasureSpec(width / 3, MeasureSpec.AT_MOST),
1674de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
1684de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        DisplayMetrics metrics = getGLRootView().getDisplayMetrics();
1694de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int rightMargin = (int) (metrics.density * INDICATOR_BAR_RIGHT_MARGIN);
1704de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1714de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mIndicatorBar.layout(
1724de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                width - mIndicatorBar.getMeasuredWidth() - rightMargin, 0,
1734de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                width - rightMargin, height);
1744de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1754de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if(mPopupWindow != null
1764de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                && mPopupWindow.getVisibility() == GLView.VISIBLE) {
1776988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin            layoutPopupWindow(mAnchorView);
1784de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
1794de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
1804de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1814de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    public void initialize(Context context, PreferenceGroup preferenceGroup) {
18233be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin        mPreferenceGroup = preferenceGroup;
1831ef634d277d550ed55b5b7089dfd56ed71815bd6Chih-Chung Chang        mSharedPrefs = ComboPreferences.get(context);
1848eaa6919f0d5c10c95c99f2f937d57ea5c4a5bbaWu-cheng Li        mPopupWindow = null;
1858eaa6919f0d5c10c95c99f2f937d57ea5c4a5bbaWu-cheng Li        clearComponents();
1864de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        initializeIndicatorBar(context, preferenceGroup);
1878eaa6919f0d5c10c95c99f2f937d57ea5c4a5bbaWu-cheng Li        requestLayout();
1884de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
1894de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1906988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin    private void layoutPopupWindow(GLView anchorView) {
1916988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin
1926988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        mAnchorView = anchorView;
1936988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        Rect rect = new Rect();
1946988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        getBoundsOf(anchorView, rect);
1956988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin
1966988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        int anchorX = rect.left + sPopupWindowOverlap;
1976988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        int anchorY = (rect.top + rect.bottom) / 2;
1984de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
1994de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int width = (int) (getWidth() * MAX_WIDTH_RATIO + .5);
2004de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int height = (int) (getHeight() * MAX_HEIGHT_RATIO + .5);
2014de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2024de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.measure(
2034de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
2044de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
2054de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2064de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        width = mPopupWindow.getMeasuredWidth();
2074de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        height = mPopupWindow.getMeasuredHeight();
2084de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2094de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int xoffset = Math.max(anchorX - width, 0);
2104de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        int yoffset = Math.max(0, anchorY - height / 2);
2114de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2124de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (yoffset + height > getHeight()) {
2134de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            yoffset = getHeight() - height;
2144de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
2154de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setAnchorPosition(anchorY - yoffset);
2164de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.layout(
2174de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                xoffset, yoffset, xoffset + width, yoffset + height);
2184de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2194de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2206988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin    private void showPopupWindow(GLView anchorView) {
2216988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        layoutPopupWindow(anchorView);
2224de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.popup();
223c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        mSharedPrefs.registerOnSharedPreferenceChangeListener(
224c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin                mSharedPreferenceChangeListener);
2254de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (mListener != null) {
2264de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            mListener.onPopupWindowVisibilityChanged(GLView.VISIBLE);
2274de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
2284de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2294de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
230c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    private void hidePopupWindow() {
231c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        mPopupWindow.popoff();
23298e0be90b938b42814d3ee34e638a3f46c06fed4Wu-cheng Li        // Unregister is important to avoid leaking activities.
23398e0be90b938b42814d3ee34e638a3f46c06fed4Wu-cheng Li        // ComboPreference.sMap->ComboPreference->HeadUpDisplay->Activity
234c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        mSharedPrefs.unregisterOnSharedPreferenceChangeListener(
235c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin                mSharedPreferenceChangeListener);
236c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        if (mListener != null) {
237c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin            mListener.onPopupWindowVisibilityChanged(GLView.INVISIBLE);
238c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        }
239c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    }
240c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin
2414de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private void scheduleDeactiviateIndicatorBar() {
242c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        mHandler.removeMessages(DESELECT_INDICATOR);
243f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        mHandler.sendEmptyMessageDelayed(
244f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin                DESELECT_INDICATOR, POPUP_WINDOW_TIMEOUT);
2454de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mHandler.removeMessages(DEACTIVATE_INDICATOR_BAR);
246f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        mHandler.sendEmptyMessageDelayed(
247f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin                DEACTIVATE_INDICATOR_BAR, INDICATOR_BAR_TIMEOUT);
2484de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2494de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2500d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    public void setOrientation(int orientation) {
2510d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        GLRootView root = getGLRootView();
2520d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (root != null) {
2530d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            synchronized (root) {
2540d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                setOrientationLocked(orientation);
2550d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            }
2560d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        } else {
2570d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            setOrientationLocked(orientation);
2580d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
2594de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2604de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2610d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    private void setOrientationLocked(int orientation) {
2624de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mOrientation = orientation;
2636988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin        mIndicatorBar.setOrientation(orientation);
2644de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (mPopupWindow == null) return;
2654de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (mPopupWindow.getVisibility() == GLView.VISIBLE) {
2666988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin            Animation alpha = new AlphaAnimation(0.2f, 1);
2674de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            alpha.setDuration(250);
2684de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            mPopupWindow.startAnimation(alpha);
2694de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            scheduleDeactiviateIndicatorBar();
2704de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
2714de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setOrientation(orientation);
2724de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2734de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2744de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private void initializePopupWindow(Context context) {
2757b783cb800a90b3f301374f354750292bb75f7aaOwen Lin        mPopupWindow = new PopupWindow();
2764de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setBackground(
2774de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                new NinePatchTexture(context, R.drawable.menu_popup));
2784de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setAnchor(new ResourceTexture(
279281be5337852cb4b5d24e0a0440c426cb96bbebdOwen Lin                context, R.drawable.menu_popup_triangle), sPopupTriangleOffset);
2804de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setVisibility(GLView.INVISIBLE);
2814de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mPopupWindow.setOrientation(mOrientation);
2824de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        addComponent(mPopupWindow);
2834de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2844de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
2854de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    @Override
2864de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    protected boolean dispatchTouchEvent(MotionEvent event) {
287f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        if (mEnabled && super.dispatchTouchEvent(event)) {
2884de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            scheduleDeactiviateIndicatorBar();
2894de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            return true;
2904de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
2914de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return false;
2924de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
2934de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
294f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin    public void setEnabled(boolean enabled) {
2950d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // The mEnabled variable is not related to the rendering thread, so we
2960d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // don't need to synchronize on the GLRootView.
297f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        if (mEnabled == enabled) return;
298f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        mEnabled = enabled;
299f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin    }
300f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin
3014de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    @Override
3024de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    protected boolean onTouch(MotionEvent event) {
3034de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (mPopupWindow == null
3044de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                || mPopupWindow.getVisibility() == GLView.INVISIBLE) {
3054de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            return false;
3064de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
3074de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3084de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        switch (event.getAction()) {
3094de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            case MotionEvent.ACTION_UP:
310c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin                hidePopupWindow();
3114de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE);
3124de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                mIndicatorBar.setActivated(false);
3134de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                break;
3144de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
3154de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return true;
3164de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
3174de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
318469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    protected static ListPreference[] getListPreferences(
3194de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            PreferenceGroup group, String ... prefKeys) {
3204de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        ArrayList<ListPreference> list = new ArrayList<ListPreference>();
3214de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        for (String key : prefKeys) {
3224de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            ListPreference pref = group.findPreference(key);
3234de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            if (pref != null && pref.getEntries().length > 0) {
3244de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                list.add(pref);
3254de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            }
3264de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
3274de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return list.toArray(new ListPreference[list.size()]);
3284de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
3294de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
330469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    protected BasicIndicator addIndicator(
331469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin            Context context, PreferenceGroup group, String key) {
3324de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        IconListPreference iconPref =
3334de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                (IconListPreference) group.findPreference(key);
3344de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        if (iconPref == null) return null;
3358eaa6919f0d5c10c95c99f2f937d57ea5c4a5bbaWu-cheng Li        BasicIndicator indicator = new BasicIndicator(context, iconPref);
336469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin        mIndicatorBar.addComponent(indicator);
3374de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        return indicator;
3384de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
3394de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
340469a9ef839e38630e1e652d182f7e0ee5882e277Owen Lin    protected void initializeIndicatorBar(
3414de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            Context context, PreferenceGroup group) {
3424de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mIndicatorBar = new IndicatorBar();
3434de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3444de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mIndicatorBar.setBackground(new NinePatchTexture(
3454de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                context, R.drawable.ic_viewfinder_iconbar));
346bef57e1d1fbb1881a7e3a22bb7567e8e7c2f0795Owen Lin        mIndicatorBar.setHighlight(new ColorTexture(COLOR_ICONBAR_HIGHLIGHT));
3474de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        addComponent(mIndicatorBar);
3484de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        mIndicatorBar.setOnItemSelectedListener(new IndicatorBarListener());
3494de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
3504de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3514de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    private class IndicatorBarListener
3524de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            implements IndicatorBar.OnItemSelectedListener {
3534de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3544de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        public void onItemSelected(GLView view, int position) {
3554de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3564de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            AbstractIndicator indicator = (AbstractIndicator) view;
3574de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            if (mPopupWindow == null) {
3584de149ceb47f2c251f646419907424bfb67d2b64Owen Lin                initializePopupWindow(getGLRootView().getContext());
3594de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            }
3604de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            mPopupWindow.setContent(indicator.getPopupContent());
3614de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3624de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            if (mPopupWindow.getVisibility() == GLView.VISIBLE) {
3636988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin                layoutPopupWindow(indicator);
3644de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            } else {
3656988d4e2ef8d14d8bf3ee81c8eb3175bbf1b88ecOwen Lin                showPopupWindow(indicator);
3664de149ceb47f2c251f646419907424bfb67d2b64Owen Lin            }
3674de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
3684de149ceb47f2c251f646419907424bfb67d2b64Owen Lin
3694de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        public void onNothingSelected() {
370c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin            hidePopupWindow();
3714de149ceb47f2c251f646419907424bfb67d2b64Owen Lin        }
3724de149ceb47f2c251f646419907424bfb67d2b64Owen Lin    }
37333be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin
3740d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin    public boolean collapse() {
3750d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // We don't need to synchronize on GLRootView, since both the
3760d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // <code>isActivated()</code> and rendering thread are read-only to
3770d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // the variables inside.
3780d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (!mIndicatorBar.isActivated()) return false;
3790d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        mHandler.removeMessages(DESELECT_INDICATOR);
3800d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        mHandler.removeMessages(DEACTIVATE_INDICATOR_BAR);
3810d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        GLRootView root = getGLRootView();
3820d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (root != null) {
3830d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            synchronized (root) {
3840d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE);
3850d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                mIndicatorBar.setActivated(false);
3860d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            }
3870d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        } else {
388f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin            mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE);
389f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin            mIndicatorBar.setActivated(false);
390f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin        }
3910d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        return true;
392c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    }
393c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin
394c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    public void setListener(Listener listener) {
3950d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // No synchronization: mListener won't be accessed in rendering thread
396c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin        mListener = listener;
397c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin    }
398c24155c65b45f554ffc29c523d7ea8e63ea10d33Owen Lin
399706bd006d25aa8f322a9807eda6183a3941ad2c6Owen Lin    public void restorePreferences(final Parameters param) {
4000d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // Do synchronization in "reloadPreferences()"
4010d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin
4020d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        OnSharedPreferenceChangeListener l =
4030d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                mSharedPreferenceChangeListener;
4040d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // Unregister the listener since "upgrade preference" will
4050d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // change bunch of preferences. We can handle them with one
4060d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        // onSharedPreferencesChanged();
4070d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        mSharedPrefs.unregisterOnSharedPreferenceChangeListener(l);
4080d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        Context context = getGLRootView().getContext();
4090d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        Editor editor = mSharedPrefs.edit();
4100d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        editor.clear();
4114714a1cf1d211aad2d8cf1802f85f649e744beb0Wu-cheng Li        editor.apply();
4121ef634d277d550ed55b5b7089dfd56ed71815bd6Chih-Chung Chang        CameraSettings.upgradeAllPreferences(mSharedPrefs);
4130d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        CameraSettings.initialCameraPictureSize(context, param);
4140d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        reloadPreferences();
4150d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (mListener != null) {
4160d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            mListener.onSharedPreferencesChanged();
4170d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
4180d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        mSharedPrefs.registerOnSharedPreferenceChangeListener(l);
41933be45a1abaf6a8d611fb87b18945c84ab76c229Owen Lin    }
420f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin
421f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin    public void reloadPreferences() {
4220d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        GLRootView root = getGLRootView();
4230d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        if (root != null) {
4240d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            synchronized (root) {
4250d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                mPreferenceGroup.reloadValue();
4260d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin                mIndicatorBar.reloadPreferences();
4270d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            }
4280d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        } else {
4290d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            mPreferenceGroup.reloadValue();
4300d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin            mIndicatorBar.reloadPreferences();
4310d73bccf89870682007dd32d4a84bcdb812e2cc7Owen Lin        }
432f5876dbd29607a0e9762f88e9db6fa35ffb20067Owen Lin    }
4334de149ceb47f2c251f646419907424bfb67d2b64Owen Lin}
434