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