package com.android.camera.app;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import com.android.camera.AccessibilityUtil;
import com.android.camera.AnimationManager;
import com.android.camera.ButtonManager;
import com.android.camera.CaptureLayoutHelper;
import com.android.camera.widget.RoundedThumbnailView;
import com.android.camera2.R;
-import java.util.List;
-
/**
* CameraAppUI centralizes control of views shared across modules. Whereas module
* specific views will be handled in each Module UI. For example, we can now
*/
public boolean enablePanoOrientation;
+ /**
+ * Set true if manual exposure compensation should be visible.
+ *
+ * This option is not constrained by hardware limitations.
+ * For example, this is false in HDR+ mode.
+ */
public boolean enableExposureCompensation;
+ /**
+ * Set true if the device and module support exposure compensation.
+ * Used only to show exposure button in disabled (greyed out) state.
+ */
+ public boolean isExposureCompensationSupported;
+
/** Intent UI */
/**
private TextureView mTextureView;
private FrameLayout mModuleUI;
private ShutterButton mShutterButton;
+ private ImageButton mCountdownCancelButton;
private BottomBar mBottomBar;
private ModeOptionsOverlay mModeOptionsOverlay;
private IndicatorIconController mIndicatorIconController;
private View mModeOptionsToggle;
private final RoundedThumbnailView mRoundedThumbnailView;
private final CaptureLayoutHelper mCaptureLayoutHelper;
- private boolean mAccessibilityEnabled;
private final View mAccessibilityAffordances;
+ private AccessibilityUtil mAccessibilityUtil;
private boolean mDisableAllUserInteractions;
+ /** Whether to prevent capture indicator from being triggered. */
+ private boolean mSuppressCaptureIndicator;
+
/**
* Provides current preview frame and the controls/overlay from the module that
* are shown on top of the preview.
}
mAnimationManager = new AnimationManager();
mRoundedThumbnailView = (RoundedThumbnailView) appRootView.findViewById(R.id.rounded_thumbnail_view);
- mRoundedThumbnailView.setOnClickListener(new View.OnClickListener() {
+ mRoundedThumbnailView.setCallback(new RoundedThumbnailView.Callback() {
@Override
- public void onClick(View v) {
+ public void onHitStateFinished() {
mFilmstripLayout.showFilmstrip();
}
});
showFilmstrip();
}
});
+
+ mSuppressCaptureIndicator = false;
}
mController.getQuickSwitchToModuleId(currentModuleIndex);
if (currentModuleIndex != moduleToTransitionTo) {
mAppRootView.redirectTouchEventsTo(mModeTransitionView);
- int shadeColorId = R.color.mode_cover_default_color;
+ int shadeColorId = R.color.camera_gray_background;
int iconRes = CameraUtil.getCameraModeCoverIconResId(moduleToTransitionTo,
mController.getAndroidContext());
// Show UI that is meant to only be used when spoken feedback is
// enabled.
- mAccessibilityEnabled = isSpokenFeedbackAccessibilityEnabled();
- mAccessibilityAffordances.setVisibility(mAccessibilityEnabled ? View.VISIBLE : View.GONE);
- }
-
- /**
- * @return Whether any spoken feedback accessibility feature is currently
- * enabled.
- */
- private boolean isSpokenFeedbackAccessibilityEnabled() {
- AccessibilityManager accessibilityManager = AndroidServices.instance()
- .provideAccessibilityManager();
- List<AccessibilityServiceInfo> infos = accessibilityManager
- .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN);
- return infos != null && !infos.isEmpty();
+ mAccessibilityAffordances.setVisibility(
+ (!mIsCaptureIntent && mAccessibilityUtil.isAccessibilityEnabled()) ? View.VISIBLE
+ : View.GONE);
}
/**
mModeListView.onMenuPressed();
}
+ public void showAccessibilityZoomUI(float maxZoom) {
+ mAccessibilityUtil.showZoomUI(maxZoom);
+ }
+
+ public void hideAccessibilityZoomUI() {
+ mAccessibilityUtil.hideZoomUI();
+ }
+
/**
* A cover view showing the mode theme color and mode icon will be visible on
* top of preview until preview is ready (i.e. camera preview is started and
*/
private void showModeCoverUntilPreviewReady() {
int modeId = mController.getCurrentModuleIndex();
- int colorId = R.color.mode_cover_default_color;;
+ int colorId = R.color.camera_gray_background;;
int iconId = CameraUtil.getCameraModeCoverIconResId(modeId, mController.getAndroidContext());
mModeTransitionView.setupModeCover(colorId, iconId);
mHideCoverRunnable = new Runnable() {
mAccessibilityAffordances.setVisibility(View.GONE);
} else {
setIndicatorBottomBarWrapperVisible(true);
- if (mAccessibilityEnabled) {
+ if (!mIsCaptureIntent && mAccessibilityUtil.isAccessibilityEnabled()) {
mAccessibilityAffordances.setVisibility(View.VISIBLE);
} else {
mAccessibilityAffordances.setVisibility(View.GONE);
}
/**
- * Call to stop the preview from being rendered.
+ * Call to stop the preview from being rendered. Sets the entire capture
+ * root view to invisible which includes the preview plus focus indicator
+ * and any other auxiliary views for capture modes.
*/
public void pausePreviewRendering() {
- mTextureView.setVisibility(View.INVISIBLE);
+ mCameraRootView.setVisibility(View.INVISIBLE);
}
/**
- * Call to begin rendering the preview again.
+ * Call to begin rendering the preview and auxiliary views again.
*/
public void resumePreviewRendering() {
- mTextureView.setVisibility(View.VISIBLE);
+ mCameraRootView.setVisibility(View.VISIBLE);
}
/**
@Override
public void onModeListOpenProgress(float progress) {
+ // When the mode list is in transition, ensure the large layers are
+ // hardware accelerated.
+ if (progress >= 1.0f || progress <= 0.0f) {
+ // Convert hardware layers back to default layer types when animation stops
+ // to prevent accidental artifacting.
+ if(mModeOptionsToggle.getLayerType() == View.LAYER_TYPE_HARDWARE ||
+ mShutterButton.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+ Log.v(TAG, "Disabling hardware layer for the Mode Options Toggle Button.");
+ mModeOptionsToggle.setLayerType(View.LAYER_TYPE_NONE, null);
+ Log.v(TAG, "Disabling hardware layer for the Shutter Button.");
+ mShutterButton.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ } else {
+ if(mModeOptionsToggle.getLayerType() != View.LAYER_TYPE_HARDWARE ||
+ mShutterButton.getLayerType() != View.LAYER_TYPE_HARDWARE) {
+ Log.v(TAG, "Enabling hardware layer for the Mode Options Toggle Button.");
+ mModeOptionsToggle.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ Log.v(TAG, "Enabling hardware layer for the Shutter Button.");
+ mShutterButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ }
+
progress = 1 - progress;
float interpolatedProgress = Gusterpolator.INSTANCE.getInterpolation(progress);
mModeOptionsToggle.setAlpha(interpolatedProgress);
@Override
public void onModeListClosed() {
+ // Convert hardware layers back to default layer types when animation stops
+ // to prevent accidental artifacting.
+ if(mModeOptionsToggle.getLayerType() == View.LAYER_TYPE_HARDWARE ||
+ mShutterButton.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+ Log.v(TAG, "Disabling hardware layer for the Mode Options Toggle Button.");
+ mModeOptionsToggle.setLayerType(View.LAYER_TYPE_NONE, null);
+ Log.v(TAG, "Disabling hardware layer for the Shutter Button.");
+ mShutterButton.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+
// Make sure the alpha on mode options ellipse is reset when mode drawer
// is closed.
mModeOptionsToggle.setAlpha(1f);
public void onChangeCamera() {
ModuleController moduleController = mController.getCurrentModuleController();
applyModuleSpecs(moduleController.getHardwareSpec(), moduleController.getBottomBarSpec());
+ syncModeOptionIndicators();
+ }
+ /**
+ * Updates the mode option indicators according to the current settings.
+ */
+ public void syncModeOptionIndicators() {
if (mIndicatorIconController != null) {
// Sync the settings state with the indicator state.
mIndicatorIconController.syncIndicators();
mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout);
mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content);
mTextureViewHelper = new TextureViewHelper(mTextureView, mCaptureLayoutHelper,
- mController.getCameraProvider());
+ mController.getCameraProvider(), mController);
mTextureViewHelper.setSurfaceTextureListener(this);
mTextureViewHelper.setOnLayoutChangeListener(mPreviewLayoutChangeListener);
mBottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar);
int unpressedColor = mController.getAndroidContext().getResources()
- .getColor(R.color.bottombar_unpressed);
+ .getColor(R.color.camera_gray_background);
setBottomBarColor(unpressedColor);
updateModeSpecificUIColors();
mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay);
mPreviewOverlay.setOnTouchListener(new MyTouchListener());
mPreviewOverlay.setOnPreviewTouchedListener(mModeOptionsOverlay);
+ mAccessibilityUtil = new AccessibilityUtil(mPreviewOverlay, mAccessibilityAffordances);
mCaptureOverlay = (CaptureAnimationOverlay)
mCameraRootView.findViewById(R.id.capture_overlay);
mStickyBottomCaptureLayout = (StickyBottomCaptureLayout) mAppRootView
.findViewById(R.id.sticky_bottom_capture_layout);
mStickyBottomCaptureLayout.setCaptureLayoutHelper(mCaptureLayoutHelper);
+ mCountdownCancelButton = (ImageButton) mStickyBottomCaptureLayout
+ .findViewById(R.id.shutter_cancel_button);
mTextureViewHelper.addPreviewAreaSizeChangedListener(mModeListView);
mTextureViewHelper.addAspectRatioChangedListener(
so that modules can have more knowledge of the status of the animation. */
/**
+ * Turns on or off the capture indicator suppression.
+ */
+ public void setShouldSuppressCaptureIndicator(boolean suppress) {
+ mSuppressCaptureIndicator = suppress;
+ }
+
+ /**
* Starts the capture indicator pop-out animation.
*
* @param accessibilityString An accessibility String to be announced during the peek animation.
*/
public void startCaptureIndicatorRevealAnimation(String accessibilityString) {
- if (mFilmstripLayout.getVisibility() == View.VISIBLE) {
+ if (mSuppressCaptureIndicator || mFilmstripLayout.getVisibility() == View.VISIBLE) {
return;
}
mRoundedThumbnailView.startRevealThumbnailAnimation(accessibilityString);
* @param thumbnailBitmap The thumbnail image to be shown.
*/
public void updateCaptureIndicatorThumbnail(Bitmap thumbnailBitmap, int rotation) {
- mRoundedThumbnailView.setThumbnail(thumbnailBitmap);
- mRoundedThumbnailView.setRotation(rotation);
+ if (mSuppressCaptureIndicator || mFilmstripLayout.getVisibility() == View.VISIBLE) {
+ return;
+ }
+ mRoundedThumbnailView.setThumbnail(thumbnailBitmap, rotation);
}
/**
}
/**
+ * Sets or replaces the "cancel shutter" button listener.
+ * <p>
+ * TODO: Make this part of the interface the same way shutter button
+ * listeners are.
+ */
+ public void setCancelShutterButtonListener(View.OnClickListener listener) {
+ mCountdownCancelButton.setOnClickListener(listener);
+ }
+
+ /**
* Performs a transition to the capture layout of the bottom bar.
*/
public void transitionToCapture() {
applyModuleSpecs(moduleController.getHardwareSpec(),
moduleController.getBottomBarSpec());
mBottomBar.transitionToIntentCaptureLayout();
+ showModeOptions();
}
/**
applyModuleSpecs(moduleController.getHardwareSpec(),
moduleController.getBottomBarSpec());
mBottomBar.transitionToIntentReviewLayout();
+ hideModeOptions();
}
/**
buttonManager.hideButton(ButtonManager.BUTTON_CAMERA);
}
- if (bottomBarSpec.hideFlash) {
+ if (bottomBarSpec.hideFlash || !hardwareSpec.isFlashSupported()) {
// Hide both flash and torch button in flash disable logic
buttonManager.hideButton(ButtonManager.BUTTON_FLASH);
buttonManager.hideButton(ButtonManager.BUTTON_TORCH);
} else {
- if (hardwareSpec.isFlashSupported()) {
- if (bottomBarSpec.enableFlash) {
- buttonManager.initializeButton(ButtonManager.BUTTON_FLASH,
- bottomBarSpec.flashCallback);
- } else if (bottomBarSpec.enableTorchFlash) {
- buttonManager.initializeButton(ButtonManager.BUTTON_TORCH,
- bottomBarSpec.flashCallback);
- } else if (bottomBarSpec.enableHdrPlusFlash) {
- buttonManager.initializeButton(ButtonManager.BUTTON_HDR_PLUS_FLASH,
- bottomBarSpec.flashCallback);
- } else {
- // Hide both flash and torch button in flash disable logic
- buttonManager.disableButton(ButtonManager.BUTTON_FLASH);
- buttonManager.disableButton(ButtonManager.BUTTON_TORCH);
- }
+ if (bottomBarSpec.enableFlash) {
+ buttonManager.initializeButton(ButtonManager.BUTTON_FLASH,
+ bottomBarSpec.flashCallback);
+ } else if (bottomBarSpec.enableTorchFlash) {
+ buttonManager.initializeButton(ButtonManager.BUTTON_TORCH,
+ bottomBarSpec.flashCallback);
+ } else if (bottomBarSpec.enableHdrPlusFlash) {
+ buttonManager.initializeButton(ButtonManager.BUTTON_HDR_PLUS_FLASH,
+ bottomBarSpec.flashCallback);
} else {
- // Disable both flash and torch icon if not supported
- // by the chosen camera hardware.
+ // Disable both flash and torch button in flash disable logic
buttonManager.disableButton(ButtonManager.BUTTON_FLASH);
buttonManager.disableButton(ButtonManager.BUTTON_TORCH);
}
buttonManager.hideButton(ButtonManager.BUTTON_HDR_PLUS);
} else {
if (hardwareSpec.isHdrPlusSupported()) {
- if (bottomBarSpec.enableHdr && Keys.isCameraBackFacing(settingsManager,
- mController.getModuleScope())) {
+ if (bottomBarSpec.enableHdr) {
buttonManager.initializeButton(ButtonManager.BUTTON_HDR_PLUS,
bottomBarSpec.hdrCallback);
} else {
buttonManager.disableButton(ButtonManager.BUTTON_HDR_PLUS);
}
} else if (hardwareSpec.isHdrSupported()) {
- if (bottomBarSpec.enableHdr && Keys.isCameraBackFacing(settingsManager,
- mController.getModuleScope())) {
+ if (bottomBarSpec.enableHdr) {
buttonManager.initializeButton(ButtonManager.BUTTON_HDR,
bottomBarSpec.hdrCallback);
} else {
buttonManager.initializePanoOrientationButtons(bottomBarSpec.panoOrientationCallback);
}
- boolean enableExposureCompensation = bottomBarSpec.enableExposureCompensation &&
- !(bottomBarSpec.minExposureCompensation == 0 && bottomBarSpec.maxExposureCompensation == 0) &&
- mController.getSettingsManager().getBoolean(SettingsManager.SCOPE_GLOBAL,
- Keys.KEY_EXPOSURE_COMPENSATION_ENABLED);
- if (enableExposureCompensation) {
- buttonManager.initializePushButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION, null);
+
+
+ // If manual exposure is enabled both in SettingsManager and
+ // BottomBarSpec,then show the exposure button.
+ // If manual exposure is disabled in the BottomBarSpec (eg. HDR+
+ // enabled), but the device/module has the feature, then disable the exposure
+ // button.
+ // Otherwise, hide the button.
+ if (bottomBarSpec.enableExposureCompensation
+ && !(bottomBarSpec.minExposureCompensation == 0 && bottomBarSpec.maxExposureCompensation == 0)
+ && mController.getSettingsManager().getBoolean(SettingsManager.SCOPE_GLOBAL,
+ Keys.KEY_EXPOSURE_COMPENSATION_ENABLED)) {
+ buttonManager.initializePushButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mModeOptionsOverlay.showExposureOptions();
+ }
+ });
buttonManager.setExposureCompensationParameters(
- bottomBarSpec.minExposureCompensation,
- bottomBarSpec.maxExposureCompensation,
- bottomBarSpec.exposureCompensationStep);
+ bottomBarSpec.minExposureCompensation,
+ bottomBarSpec.maxExposureCompensation,
+ bottomBarSpec.exposureCompensationStep);
buttonManager.setExposureCompensationCallback(
bottomBarSpec.exposureCompensationSetCallback);
buttonManager.updateExposureButtons();
+ } else if (mController.getSettingsManager().getBoolean(SettingsManager.SCOPE_GLOBAL,
+ Keys.KEY_EXPOSURE_COMPENSATION_ENABLED)
+ && bottomBarSpec.isExposureCompensationSupported) {
+ buttonManager.disableButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION);
} else {
buttonManager.hideButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION);
buttonManager.setExposureCompensationCallback(null);
public void hideFilmstrip() {
mFilmstripLayout.hideFilmstrip();
}
+
+ public int getFilmstripVisibility() {
+ return mFilmstripLayout.getVisibility();
+ }
}