ButtonManager.java revision c989d417a53341b144e9f78304270ac66f8f5813
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.view.LayoutInflater;
22import android.view.View;
23import android.widget.ImageButton;
24import android.widget.LinearLayout;
25
26import com.android.camera.app.AppController;
27import com.android.camera.app.CameraAppUI;
28import com.android.camera.settings.Keys;
29import com.android.camera.settings.SettingsManager;
30import com.android.camera.ui.RadioOptions;
31import com.android.camera.util.PhotoSphereHelper;
32import com.android.camera.widget.ModeOptions;
33import com.android.camera2.R;
34
35/**
36 * A  class for generating pre-initialized
37 * {@link #android.widget.ImageButton}s.
38 */
39public class ButtonManager implements SettingsManager.OnSettingChangedListener {
40    public static final int BUTTON_FLASH = 0;
41    public static final int BUTTON_TORCH = 1;
42    public static final int BUTTON_HDR_PLUS_FLASH = 2;
43    public static final int BUTTON_CAMERA = 3;
44    public static final int BUTTON_HDR_PLUS = 4;
45    public static final int BUTTON_HDR = 5;
46    public static final int BUTTON_CANCEL = 6;
47    public static final int BUTTON_DONE = 7;
48    public static final int BUTTON_RETAKE = 8;
49    public static final int BUTTON_REVIEW = 9;
50    public static final int BUTTON_GRID_LINES = 10;
51    public static final int BUTTON_EXPOSURE_COMPENSATION = 11;
52    public static final int BUTTON_COUNTDOWN = 12;
53
54    /** For two state MultiToggleImageButtons, the off index. */
55    public static final int OFF = 0;
56    /** For two state MultiToggleImageButtons, the on index. */
57    public static final int ON = 1;
58
59    private static final int NO_RESOURCE = -1;
60
61    /** A reference to the application's settings manager. */
62    private final SettingsManager mSettingsManager;
63
64    /** Bottom bar options toggle buttons. */
65    private MultiToggleImageButton mButtonCamera;
66    private MultiToggleImageButton mButtonFlash;
67    private MultiToggleImageButton mButtonHdr;
68    private MultiToggleImageButton mButtonGridlines;
69    private MultiToggleImageButton mButtonCountdown;
70
71    /** Intent UI buttons. */
72    private ImageButton mButtonCancel;
73    private ImageButton mButtonDone;
74    private ImageButton mButtonRetake; // same as review.
75
76    private ImageButton mButtonExposureCompensation;
77    private ImageButton mExposureN2;
78    private ImageButton mExposureN1;
79    private ImageButton mExposure0;
80    private ImageButton mExposureP1;
81    private ImageButton mExposureP2;
82    private RadioOptions mModeOptionsExposure;
83    private RadioOptions mModeOptionsPano;
84    private View mModeOptionsButtons;
85    private ModeOptions mModeOptions;
86
87    private int mMinExposureCompensation;
88    private int mMaxExposureCompensation;
89    private float mExposureCompensationStep;
90
91    /** A listener for button enabled and visibility
92        state changes. */
93    private ButtonStatusListener mListener;
94
95    /** An reference to the gcam mode index. */
96    private static int sGcamIndex;
97
98    private final AppController mAppController;
99
100    /**
101     * Get a new global ButtonManager.
102     */
103    public ButtonManager(AppController app) {
104        mAppController = app;
105
106        Context context = app.getAndroidContext();
107        sGcamIndex = context.getResources().getInteger(R.integer.camera_mode_gcam);
108
109        mSettingsManager = app.getSettingsManager();
110        mSettingsManager.addListener(this);
111    }
112
113    /**
114     * Load references to buttons under a root View.
115     * Call this after the root clears/reloads all of its children
116     * to prevent stale references button views.
117     */
118    public void load(View root) {
119        getButtonsReferences(root);
120    }
121
122    /**
123     * ButtonStatusListener provides callbacks for when button's
124     * visibility changes and enabled status changes.
125     */
126    public interface ButtonStatusListener {
127        /**
128         * A button's visibility has changed.
129         */
130        public void onButtonVisibilityChanged(ButtonManager buttonManager, int buttonId);
131
132        /**
133         * A button's enabled state has changed.
134         */
135        public void onButtonEnabledChanged(ButtonManager buttonManager, int buttonId);
136    }
137
138    /**
139     * Sets the ButtonStatusListener.
140     */
141    public void setListener(ButtonStatusListener listener) {
142        mListener = listener;
143    }
144
145    /**
146     * Gets references to all known buttons.
147     */
148    private void getButtonsReferences(View root) {
149        mButtonCamera
150            = (MultiToggleImageButton) root.findViewById(R.id.camera_toggle_button);
151        mButtonFlash
152            = (MultiToggleImageButton) root.findViewById(R.id.flash_toggle_button);
153        mButtonHdr
154            = (MultiToggleImageButton) root.findViewById(R.id.hdr_plus_toggle_button);
155        mButtonGridlines
156            = (MultiToggleImageButton) root.findViewById(R.id.grid_lines_toggle_button);
157        mButtonCancel
158            = (ImageButton) root.findViewById(R.id.cancel_button);
159        mButtonDone
160            = (ImageButton) root.findViewById(R.id.done_button);
161        mButtonRetake
162            = (ImageButton) root.findViewById(R.id.retake_button);
163
164        mButtonExposureCompensation =
165            (ImageButton) root.findViewById(R.id.exposure_button);
166        mExposureN2 = (ImageButton) root.findViewById(R.id.exposure_n2);
167        mExposureN1 = (ImageButton) root.findViewById(R.id.exposure_n1);
168        mExposure0 = (ImageButton) root.findViewById(R.id.exposure_0);
169        mExposureP1 = (ImageButton) root.findViewById(R.id.exposure_p1);
170        mExposureP2 = (ImageButton) root.findViewById(R.id.exposure_p2);
171        mModeOptionsExposure = (RadioOptions) root.findViewById(R.id.mode_options_exposure);
172        mModeOptionsPano = (RadioOptions) root.findViewById(R.id.mode_options_pano);
173        mModeOptionsButtons = root.findViewById(R.id.mode_options_buttons);
174        mModeOptions = (ModeOptions) root.findViewById(R.id.mode_options);
175
176        mButtonCountdown = (MultiToggleImageButton) root.findViewById(R.id.countdown_toggle_button);
177    }
178
179    @Override
180    public void onSettingChanged(SettingsManager settingsManager, String key) {
181        MultiToggleImageButton button = null;
182        int index = 0;
183
184        if (key.equals(Keys.KEY_FLASH_MODE)) {
185            index = mSettingsManager.getIndexOfCurrentValue(mAppController.getCameraScope(),
186                                                            Keys.KEY_FLASH_MODE);
187            button = getButtonOrError(BUTTON_FLASH);
188        } else if (key.equals(Keys.KEY_VIDEOCAMERA_FLASH_MODE)) {
189            index = mSettingsManager.getIndexOfCurrentValue(mAppController.getCameraScope(),
190                                                            Keys.KEY_VIDEOCAMERA_FLASH_MODE);
191            button = getButtonOrError(BUTTON_TORCH);
192        } else if (key.equals(Keys.KEY_HDR_PLUS_FLASH_MODE)) {
193            index = mSettingsManager.getIndexOfCurrentValue(mAppController.getModuleScope(),
194                                                            Keys.KEY_HDR_PLUS_FLASH_MODE);
195            button = getButtonOrError(BUTTON_HDR_PLUS_FLASH);
196        } else if (key.equals(Keys.KEY_CAMERA_ID)) {
197            index = mSettingsManager.getIndexOfCurrentValue(mAppController.getModuleScope(),
198                                                            Keys.KEY_CAMERA_ID);
199            button = getButtonOrError(BUTTON_CAMERA);
200        } else if (key.equals(Keys.KEY_CAMERA_HDR_PLUS)) {
201            index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
202                                                            Keys.KEY_CAMERA_HDR_PLUS);
203            button = getButtonOrError(BUTTON_HDR_PLUS);
204        } else if (key.equals(Keys.KEY_CAMERA_HDR)) {
205            index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
206                                                            Keys.KEY_CAMERA_HDR);
207            button = getButtonOrError(BUTTON_HDR);
208        } else if (key.equals(Keys.KEY_CAMERA_GRID_LINES)) {
209            index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
210                                                            Keys.KEY_CAMERA_GRID_LINES);
211            button = getButtonOrError(BUTTON_GRID_LINES);
212        } else if (key.equals(Keys.KEY_CAMERA_PANO_ORIENTATION)) {
213            updatePanoButtons();
214        } else if (key.equals(Keys.KEY_EXPOSURE)) {
215            updateExposureButtons();
216        } else if (key.equals(Keys.KEY_COUNTDOWN_DURATION)) {
217            index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
218                                                            Keys.KEY_COUNTDOWN_DURATION);
219            button = getButtonOrError(BUTTON_COUNTDOWN);
220        }
221
222        if (button != null && button.getState() != index) {
223            button.setState(Math.max(index, 0), false);
224        }
225    }
226
227    /**
228     * A callback executed in the state listener of a button.
229     *
230     * Used by a module to set specific behavior when a button's
231     * state changes.
232     */
233    public interface ButtonCallback {
234        public void onStateChanged(int state);
235    }
236
237    /**
238     * Returns the appropriate {@link com.android.camera.MultiToggleImageButton}
239     * based on button id.  An IllegalStateException will be throw if the
240     * button could not be found in the view hierarchy.
241     */
242    private MultiToggleImageButton getButtonOrError(int buttonId) {
243        switch (buttonId) {
244            case BUTTON_FLASH:
245                if (mButtonFlash == null) {
246                    throw new IllegalStateException("Flash button could not be found.");
247                }
248                return mButtonFlash;
249            case BUTTON_TORCH:
250                if (mButtonFlash == null) {
251                    throw new IllegalStateException("Torch button could not be found.");
252                }
253                return mButtonFlash;
254            case BUTTON_HDR_PLUS_FLASH:
255                if (mButtonFlash == null) {
256                    throw new IllegalStateException("Hdr plus torch button could not be found.");
257                }
258                return mButtonFlash;
259            case BUTTON_CAMERA:
260                if (mButtonCamera == null) {
261                    throw new IllegalStateException("Camera button could not be found.");
262                }
263                return mButtonCamera;
264            case BUTTON_HDR_PLUS:
265                if (mButtonHdr == null) {
266                    throw new IllegalStateException("Hdr plus button could not be found.");
267                }
268                return mButtonHdr;
269            case BUTTON_HDR:
270                if (mButtonHdr == null) {
271                    throw new IllegalStateException("Hdr button could not be found.");
272                }
273                return mButtonHdr;
274            case BUTTON_GRID_LINES:
275                if (mButtonGridlines == null) {
276                    throw new IllegalStateException("Grid lines button could not be found.");
277                }
278                return mButtonGridlines;
279            case BUTTON_COUNTDOWN:
280                if (mButtonCountdown == null) {
281                    throw new IllegalStateException("Countdown button could not be found.");
282                }
283                return mButtonCountdown;
284            default:
285                throw new IllegalArgumentException("button not known by id=" + buttonId);
286        }
287    }
288
289    /**
290     * Returns the appropriate {@link android.widget.ImageButton}
291     * based on button id.  An IllegalStateException will be throw if the
292     * button could not be found in the view hierarchy.
293     */
294    private ImageButton getImageButtonOrError(int buttonId) {
295        switch (buttonId) {
296            case BUTTON_CANCEL:
297                if (mButtonCancel == null) {
298                    throw new IllegalStateException("Cancel button could not be found.");
299                }
300                return mButtonCancel;
301            case BUTTON_DONE:
302                if (mButtonDone == null) {
303                    throw new IllegalStateException("Done button could not be found.");
304                }
305                return mButtonDone;
306            case BUTTON_RETAKE:
307                if (mButtonRetake == null) {
308                    throw new IllegalStateException("Retake button could not be found.");
309                }
310                return mButtonRetake;
311            case BUTTON_REVIEW:
312                if (mButtonRetake == null) {
313                    throw new IllegalStateException("Review button could not be found.");
314                }
315                return mButtonRetake;
316            case BUTTON_EXPOSURE_COMPENSATION:
317                if (mButtonExposureCompensation == null) {
318                    throw new IllegalStateException("Exposure Compensation button could not be found.");
319                }
320                return mButtonExposureCompensation;
321            default:
322                throw new IllegalArgumentException("button not known by id=" + buttonId);
323        }
324    }
325
326    /**
327     * Initialize a known button by id, with a state change callback and
328     * a resource id that points to an array of drawables, and then enable
329     * the button.
330     */
331    public void initializeButton(int buttonId, ButtonCallback cb) {
332        MultiToggleImageButton button = getButtonOrError(buttonId);
333        switch (buttonId) {
334            case BUTTON_FLASH:
335                initializeFlashButton(button, cb, R.array.camera_flashmode_icons);
336                break;
337            case BUTTON_TORCH:
338                initializeTorchButton(button, cb, R.array.video_flashmode_icons);
339                break;
340            case BUTTON_HDR_PLUS_FLASH:
341                initializeHdrPlusFlashButton(button, cb, R.array.camera_flashmode_icons);
342                break;
343            case BUTTON_CAMERA:
344                initializeCameraButton(button, cb, R.array.camera_id_icons);
345                break;
346            case BUTTON_HDR_PLUS:
347                initializeHdrPlusButton(button, cb, R.array.pref_camera_hdr_plus_icons);
348                break;
349            case BUTTON_HDR:
350                initializeHdrButton(button, cb, R.array.pref_camera_hdr_icons);
351                break;
352            case BUTTON_GRID_LINES:
353                initializeGridLinesButton(button, cb, R.array.grid_lines_icons);
354                break;
355            case BUTTON_COUNTDOWN:
356                initializeCountdownButton(button, cb, R.array.countdown_duration_icons);
357                break;
358            default:
359                throw new IllegalArgumentException("button not known by id=" + buttonId);
360        }
361
362        showButton(buttonId);
363        enableButton(buttonId);
364    }
365
366    /**
367     * Initialize a known button with a click listener and a drawable resource id,
368     * and a content description resource id.
369     * Sets the button visible.
370     */
371    public void initializePushButton(int buttonId, View.OnClickListener cb,
372            int imageId, int contentDescriptionId) {
373        ImageButton button = getImageButtonOrError(buttonId);
374        button.setOnClickListener(cb);
375        if (imageId != NO_RESOURCE) {
376            button.setImageResource(imageId);
377        }
378        if (contentDescriptionId != NO_RESOURCE) {
379            button.setContentDescription(mAppController
380                    .getAndroidContext().getResources().getString(contentDescriptionId));
381        }
382
383        if (!button.isEnabled()) {
384            button.setEnabled(true);
385            if (mListener != null) {
386                mListener.onButtonEnabledChanged(this, buttonId);
387            }
388        }
389        button.setTag(R.string.tag_enabled_id, buttonId);
390
391        if (button.getVisibility() != View.VISIBLE) {
392            button.setVisibility(View.VISIBLE);
393            if (mListener != null) {
394                mListener.onButtonVisibilityChanged(this, buttonId);
395            }
396        }
397    }
398
399    /**
400     * Initialize a known button with a click listener and a resource id.
401     * Sets the button visible.
402     */
403    public void initializePushButton(int buttonId, View.OnClickListener cb,
404            int imageId) {
405        initializePushButton(buttonId, cb, imageId, NO_RESOURCE);
406    }
407
408    /**
409     * Initialize a known button with a click listener. Sets the button visible.
410     */
411    public void initializePushButton(int buttonId, View.OnClickListener cb) {
412        initializePushButton(buttonId, cb, NO_RESOURCE, NO_RESOURCE);
413    }
414
415    /**
416     * Sets a button in its disabled (greyed out) state.
417     */
418    public void disableButton(int buttonId) {
419        MultiToggleImageButton button = getButtonOrError(buttonId);
420
421        // HDR and HDR+ buttons share the same button object,
422        // but change actual image icons at runtime.
423        // This extra check is to ensure the correct icons are used
424        // in the case of the HDR[+] button being disabled at startup,
425        // e.g. app startup with front-facing camera.
426        // b/18104680
427        if (buttonId == BUTTON_HDR_PLUS) {
428            initializeHdrPlusButtonIcons(button, R.array.pref_camera_hdr_plus_icons);
429        } else if (buttonId == BUTTON_HDR) {
430            initializeHdrButtonIcons(button, R.array.pref_camera_hdr_icons);
431        }
432
433        if (button.isEnabled()) {
434            button.setEnabled(false);
435            if (mListener != null) {
436                mListener.onButtonEnabledChanged(this, buttonId);
437            }
438        }
439        button.setTag(R.string.tag_enabled_id, null);
440    }
441
442    /**
443     * Enables a button that has already been initialized.
444     */
445    public void enableButton(int buttonId) {
446        ImageButton button = getButtonOrError(buttonId);
447        if (!button.isEnabled()) {
448            button.setEnabled(true);
449            if (mListener != null) {
450                mListener.onButtonEnabledChanged(this, buttonId);
451            }
452        }
453        button.setTag(R.string.tag_enabled_id, buttonId);
454    }
455
456    /**
457     * Disable click reactions for a button without affecting visual state.
458     * For most cases you'll want to use {@link #disableButton(int)}.
459     * @param buttonId The id of the button.
460     */
461    public void disableButtonClick(int buttonId) {
462        ImageButton button = getButtonOrError(buttonId);
463        if (button instanceof MultiToggleImageButton) {
464            ((MultiToggleImageButton) button).setClickEnabled(false);
465        }
466    }
467
468    /**
469     * Enable click reactions for a button without affecting visual state.
470     * For most cases you'll want to use {@link #enableButton(int)}.
471     * @param buttonId The id of the button.
472     */
473    public void enableButtonClick(int buttonId) {
474        ImageButton button = getButtonOrError(buttonId);
475        if (button instanceof MultiToggleImageButton) {
476            ((MultiToggleImageButton) button).setClickEnabled(true);
477        }
478    }
479
480    /**
481     * Hide a button by id.
482     */
483    public void hideButton(int buttonId) {
484        View button;
485        try {
486            button = getButtonOrError(buttonId);
487        } catch (IllegalArgumentException e) {
488            button = getImageButtonOrError(buttonId);
489        }
490        if (button.getVisibility() == View.VISIBLE) {
491            button.setVisibility(View.GONE);
492            if (mListener != null) {
493                mListener.onButtonVisibilityChanged(this, buttonId);
494            }
495        }
496    }
497
498    /**
499     * Show a button by id.
500     */
501    public void showButton(int buttonId) {
502        View button;
503        try {
504            button = getButtonOrError(buttonId);
505        } catch (IllegalArgumentException e) {
506            button = getImageButtonOrError(buttonId);
507        }
508        if (button.getVisibility() != View.VISIBLE) {
509            button.setVisibility(View.VISIBLE);
510            if (mListener != null) {
511                mListener.onButtonVisibilityChanged(this, buttonId);
512            }
513        }
514    }
515
516
517    public void setToInitialState() {
518        mModeOptions.setMainBar(ModeOptions.BAR_STANDARD);
519    }
520
521    public void setExposureCompensationCallback(final CameraAppUI.BottomBarUISpec
522                                        .ExposureCompensationSetCallback cb) {
523        if (cb == null) {
524            mModeOptionsExposure.setOnOptionClickListener(null);
525        } else {
526            mModeOptionsExposure
527                .setOnOptionClickListener(new RadioOptions.OnOptionClickListener() {
528                    @Override
529                    public void onOptionClicked(View v) {
530                        int comp = Integer.parseInt((String)(v.getTag()));
531
532                        if (mExposureCompensationStep != 0.0f) {
533                            int compValue =
534                                Math.round(comp / mExposureCompensationStep);
535                            cb.setExposure(compValue);
536                        }
537                    }
538                });
539        }
540    }
541
542    /**
543     * Set the exposure compensation parameters supported by the current camera mode.
544     * @param min Minimum exposure compensation value.
545     * @param max Maximum exposure compensation value.
546     * @param step Expsoure compensation step value.
547     */
548    public void setExposureCompensationParameters(int min, int max, float step) {
549        mMaxExposureCompensation = max;
550        mMinExposureCompensation = min;
551        mExposureCompensationStep = step;
552
553
554        setVisible(mExposureN2, (Math.round(min * step) <= -2));
555        setVisible(mExposureN1, (Math.round(min * step) <= -1));
556        setVisible(mExposureP1, (Math.round(max * step) >= 1));
557        setVisible(mExposureP2, (Math.round(max * step) >= 2));
558
559        updateExposureButtons();
560    }
561
562    private static void setVisible(View v, boolean visible) {
563        if (visible) {
564            v.setVisibility(View.VISIBLE);
565        } else {
566            v.setVisibility(View.INVISIBLE);
567        }
568    }
569
570    /**
571     * @return The exposure compensation step value.
572     **/
573    public float getExposureCompensationStep() {
574        return mExposureCompensationStep;
575    }
576
577    /**
578     * Check if a button is enabled with the given button id..
579     */
580    public boolean isEnabled(int buttonId) {
581        View button;
582        try {
583            button = getButtonOrError(buttonId);
584        } catch (IllegalArgumentException e) {
585            button = getImageButtonOrError(buttonId);
586        }
587
588        Integer enabledId = (Integer) button.getTag(R.string.tag_enabled_id);
589        if (enabledId != null) {
590            return (enabledId.intValue() == buttonId) && button.isEnabled();
591        } else {
592            return false;
593        }
594    }
595
596    /**
597     * Check if a button is visible.
598     */
599    public boolean isVisible(int buttonId) {
600        View button;
601        try {
602            button = getButtonOrError(buttonId);
603        } catch (IllegalArgumentException e) {
604            button = getImageButtonOrError(buttonId);
605        }
606        return (button.getVisibility() == View.VISIBLE);
607    }
608
609    /**
610     * Initialize a flash button.
611     */
612    private void initializeFlashButton(MultiToggleImageButton button,
613            final ButtonCallback cb, int resIdImages) {
614
615        if (resIdImages > 0) {
616            button.overrideImageIds(resIdImages);
617        }
618        button.overrideContentDescriptions(R.array.camera_flash_descriptions);
619
620        int index = mSettingsManager.getIndexOfCurrentValue(mAppController.getCameraScope(),
621                                                            Keys.KEY_FLASH_MODE);
622        button.setState(index >= 0 ? index : 0, false);
623
624        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
625            @Override
626            public void stateChanged(View view, int state) {
627                mSettingsManager.setValueByIndex(mAppController.getCameraScope(),
628                                                 Keys.KEY_FLASH_MODE, state);
629                if (cb != null) {
630                    cb.onStateChanged(state);
631                }
632            }
633        });
634    }
635
636    /**
637     * Initialize video torch button
638     */
639    private void initializeTorchButton(MultiToggleImageButton button,
640            final ButtonCallback cb, int resIdImages) {
641
642        if (resIdImages > 0) {
643            button.overrideImageIds(resIdImages);
644        }
645        button.overrideContentDescriptions(R.array.video_flash_descriptions);
646
647        int index = mSettingsManager.getIndexOfCurrentValue(mAppController.getCameraScope(),
648                                                            Keys.KEY_VIDEOCAMERA_FLASH_MODE);
649        button.setState(index >= 0 ? index : 0, false);
650
651        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
652            @Override
653            public void stateChanged(View view, int state) {
654                mSettingsManager.setValueByIndex(mAppController.getCameraScope(),
655                                                 Keys.KEY_VIDEOCAMERA_FLASH_MODE, state);
656                if (cb != null) {
657                    cb.onStateChanged(state);
658                }
659            }
660        });
661    }
662
663    /**
664     * Initialize hdr plus flash button
665     */
666    private void initializeHdrPlusFlashButton(MultiToggleImageButton button,
667            final ButtonCallback cb, int resIdImages) {
668
669        if (resIdImages > 0) {
670            button.overrideImageIds(resIdImages);
671        }
672        button.overrideContentDescriptions(R.array.hdr_plus_flash_descriptions);
673
674        int index = mSettingsManager.getIndexOfCurrentValue(mAppController.getModuleScope(),
675                                                            Keys.KEY_HDR_PLUS_FLASH_MODE);
676        button.setState(index >= 0 ? index : 0, false);
677
678        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
679            @Override
680            public void stateChanged(View view, int state) {
681                mSettingsManager.setValueByIndex(mAppController.getModuleScope(),
682                                                 Keys.KEY_HDR_PLUS_FLASH_MODE, state);
683                if (cb != null) {
684                    cb.onStateChanged(state);
685                }
686            }
687        });
688    }
689
690    /**
691     * Initialize a camera button.
692     */
693    private void initializeCameraButton(final MultiToggleImageButton button,
694            final ButtonCallback cb, int resIdImages) {
695
696        if (resIdImages > 0) {
697            button.overrideImageIds(resIdImages);
698        }
699
700        int index = mSettingsManager.getIndexOfCurrentValue(mAppController.getModuleScope(),
701                                                            Keys.KEY_CAMERA_ID);
702        button.setState(index >= 0 ? index : 0, false);
703
704        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
705            @Override
706            public void stateChanged(View view, int state) {
707                mSettingsManager.setValueByIndex(mAppController.getModuleScope(),
708                                                 Keys.KEY_CAMERA_ID, state);
709                int cameraId = mSettingsManager.getInteger(mAppController.getModuleScope(),
710                                                           Keys.KEY_CAMERA_ID);
711                // This is a quick fix for ISE in Gcam module which can be
712                // found by rapid pressing camera switch button. The assumption
713                // here is that each time this button is clicked, the listener
714                // will do something and then enable this button again.
715                button.setEnabled(false);
716                if (cb != null) {
717                    cb.onStateChanged(cameraId);
718                }
719                mAppController.getCameraAppUI().onChangeCamera();
720            }
721        });
722    }
723
724    /**
725     * Initialize an hdr plus button.
726     */
727    private void initializeHdrPlusButton(MultiToggleImageButton button,
728            final ButtonCallback cb, int resIdImages) {
729
730        initializeHdrPlusButtonIcons(button, resIdImages);
731
732        int index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
733                                                            Keys.KEY_CAMERA_HDR_PLUS);
734        button.setState(index >= 0 ? index : 0, false);
735
736        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
737            @Override
738            public void stateChanged(View view, int state) {
739                mSettingsManager.setValueByIndex(SettingsManager.SCOPE_GLOBAL,
740                                                 Keys.KEY_CAMERA_HDR_PLUS, state);
741                if (cb != null) {
742                    cb.onStateChanged(state);
743                }
744            }
745        });
746    }
747
748    private void initializeHdrPlusButtonIcons(MultiToggleImageButton button, int resIdImages) {
749        if (resIdImages > 0) {
750            button.overrideImageIds(resIdImages);
751        }
752        button.overrideContentDescriptions(R.array.hdr_plus_descriptions);
753    }
754
755    /**
756     * Initialize an hdr button.
757     */
758    private void initializeHdrButton(MultiToggleImageButton button,
759            final ButtonCallback cb, int resIdImages) {
760
761        initializeHdrButtonIcons(button, resIdImages);
762
763        int index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
764                                                            Keys.KEY_CAMERA_HDR);
765        button.setState(index >= 0 ? index : 0, false);
766
767        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
768            @Override
769            public void stateChanged(View view, int state) {
770                mSettingsManager.setValueByIndex(SettingsManager.SCOPE_GLOBAL,
771                                                 Keys.KEY_CAMERA_HDR, state);
772                if (cb != null) {
773                    cb.onStateChanged(state);
774                }
775            }
776        });
777    }
778
779    private void initializeHdrButtonIcons(MultiToggleImageButton button, int resIdImages) {
780        if (resIdImages > 0) {
781            button.overrideImageIds(resIdImages);
782        }
783        button.overrideContentDescriptions(R.array.hdr_descriptions);
784    }
785
786    /**
787     * Initialize a countdown timer button.
788     */
789    private void initializeCountdownButton(MultiToggleImageButton button,
790            final ButtonCallback cb, int resIdImages) {
791        if (resIdImages > 0) {
792            button.overrideImageIds(resIdImages);
793        }
794
795        int index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
796                                                            Keys.KEY_COUNTDOWN_DURATION);
797        button.setState(index >= 0 ? index : 0, false);
798
799        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
800            @Override
801            public void stateChanged(View view, int state) {
802                mSettingsManager.setValueByIndex(SettingsManager.SCOPE_GLOBAL,
803                                                 Keys.KEY_COUNTDOWN_DURATION, state);
804                if(cb != null) {
805                    cb.onStateChanged(state);
806                }
807            }
808        });
809    }
810
811    /**
812     * Update the visual state of the manual exposure buttons
813     */
814    public void updateExposureButtons() {
815        int compValue = mSettingsManager.getInteger(mAppController.getCameraScope(),
816                                                    Keys.KEY_EXPOSURE);
817        if (mExposureCompensationStep != 0.0f) {
818            int comp = Math.round(compValue * mExposureCompensationStep);
819            mModeOptionsExposure.setSelectedOptionByTag(String.valueOf(comp));
820        }
821    }
822
823    /**
824     * Initialize a grid lines button.
825     */
826    private void initializeGridLinesButton(MultiToggleImageButton button,
827            final ButtonCallback cb, int resIdImages) {
828
829        if (resIdImages > 0) {
830            button.overrideImageIds(resIdImages);
831        }
832        button.overrideContentDescriptions(R.array.grid_lines_descriptions);
833
834        button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
835            @Override
836            public void stateChanged(View view, int state) {
837                mSettingsManager.setValueByIndex(SettingsManager.SCOPE_GLOBAL,
838                                                 Keys.KEY_CAMERA_GRID_LINES, state);
839                if (cb != null) {
840                    cb.onStateChanged(state);
841                }
842            }
843        });
844
845        int index = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
846                                                            Keys.KEY_CAMERA_GRID_LINES);
847        button.setState(index >= 0 ? index : 0, true);
848    }
849
850    public boolean isPanoEnabled() {
851        return mModeOptions.getMainBar() == ModeOptions.BAR_PANO;
852    }
853
854   /**
855     * Initialize a panorama orientation buttons.
856     */
857    public void initializePanoOrientationButtons(final ButtonCallback cb) {
858        int resIdImages = PhotoSphereHelper.getPanoramaOrientationOptionArrayId();
859        int resIdDescriptions = PhotoSphereHelper.getPanoramaOrientationDescriptions();
860        if (resIdImages > 0) {
861            TypedArray imageIds = null;
862            TypedArray descriptionIds = null;
863            try {
864                mModeOptions.setMainBar(ModeOptions.BAR_PANO);
865                imageIds = mAppController
866                    .getAndroidContext().getResources().obtainTypedArray(resIdImages);
867                descriptionIds = mAppController
868                    .getAndroidContext().getResources().obtainTypedArray(resIdDescriptions);
869                mModeOptionsPano.removeAllViews();
870                final boolean isHorizontal =
871                    (mModeOptionsPano.getOrientation() == LinearLayout.HORIZONTAL);
872                final int numImageIds = imageIds.length();
873                for (int index = 0; index < numImageIds; index++) {
874                    int i;
875                    // if in portrait orientation (pano bar horizonal), order buttons normally
876                    // if in landscape orientation (pano bar vertical), reverse button order
877                    if (isHorizontal) {
878                        i = index;
879                    } else {
880                        i = numImageIds - index - 1;
881                    }
882
883                    int imageId = imageIds.getResourceId(i, 0);
884                    if (imageId > 0) {
885                        ImageButton imageButton = (ImageButton) LayoutInflater
886                            .from(mAppController.getAndroidContext())
887                            .inflate(R.layout.mode_options_imagebutton_template,
888                                     mModeOptionsPano, false);
889                        imageButton.setImageResource(imageId);
890                        imageButton.setTag(String.valueOf(i));
891                        mModeOptionsPano.addView(imageButton);
892
893                        int descriptionId = descriptionIds.getResourceId(i, 0);
894                        if (descriptionId > 0) {
895                            imageButton.setContentDescription(
896                                    mAppController.getAndroidContext().getString(descriptionId));
897                        }
898                    }
899                }
900                mModeOptionsPano.updateListeners();
901                mModeOptionsPano
902                    .setOnOptionClickListener(new RadioOptions.OnOptionClickListener() {
903                        @Override
904                        public void onOptionClicked(View v) {
905                            if (cb != null) {
906                                int state = Integer.parseInt((String)v.getTag());
907                                mSettingsManager.setValueByIndex(SettingsManager.SCOPE_GLOBAL,
908                                                                 Keys.KEY_CAMERA_PANO_ORIENTATION,
909                                                                 state);
910                                cb.onStateChanged(state);
911                            }
912                        }
913                    });
914                updatePanoButtons();
915            } finally {
916                if (imageIds != null) {
917                    imageIds.recycle();
918                }
919                if (descriptionIds != null) {
920                    descriptionIds.recycle();
921                }
922            }
923        }
924    }
925
926    private void updatePanoButtons() {
927        int modeIndex = mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
928                                                                Keys.KEY_CAMERA_PANO_ORIENTATION);
929        mModeOptionsPano.setSelectedOptionByTag(String.valueOf(modeIndex));
930    }
931}
932