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