+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (c) 2013, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.0"
- android:duration="1000" />
- <scale
- android:fromXScale="1.0"
- android:fromYScale="1.0"
- android:toXScale="3.0"
- android:toYScale="3.0"
- android:pivotX="50%"
- android:pivotY="50%"
- android:duration="800" />
-</set>
\ No newline at end of file
android:id="@+id/hdr_indicator"
style="@style/IndicatorIcon" />
<ImageView
+ android:id="@+id/countdown_timer_indicator"
+ style="@style/IndicatorIcon" />
+ <ImageView
android:id="@+id/flash_indicator"
style="@style/IndicatorIcon" />
<ImageView
android:background="@null"
android:src="@drawable/ic_exposure"
android:contentDescription="@string/manual_exposure_compensation_desc" />
+ <com.android.camera.MultiToggleImageButton
+ android:id="@+id/countdown_toggle_button"
+ style="@style/ModeOption"
+ camera:imageIds="@array/countdown_duration_icons"
+ camera:contentDescriptionIds="@array/countdown_duration_descriptions" />
</com.android.camera.ui.TopRightWeightedLayout>
</com.android.camera.widget.ModeOptions>
android:id="@+id/hdr_indicator"
style="@style/IndicatorIcon" />
<ImageView
+ android:id="@+id/countdown_timer_indicator"
+ style="@style/IndicatorIcon" />
+ <ImageView
android:id="@+id/flash_indicator"
style="@style/IndicatorIcon" />
<ImageView
style="@style/ModeOption"
camera:imageIds="@array/camera_id_icons"
camera:contentDescriptionIds="@array/camera_id_descriptions" />
+ <com.android.camera.MultiToggleImageButton
+ android:id="@+id/countdown_toggle_button"
+ style="@style/ModeOption"
+ camera:imageIds="@array/countdown_duration_icons"
+ camera:contentDescriptionIds="@array/countdown_duration_descriptions" />
</com.android.camera.ui.TopRightWeightedLayout>
</com.android.camera.widget.ModeOptions>
android:clickable="true"
android:background="@android:color/black"
android:scaleType="fitCenter"/>
+ <com.android.camera.ui.CountDownView
+ android:id="@+id/count_down_view"
+ android:visibility="invisible"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <TextView android:id="@+id/remaining_seconds"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:textSize="160dp"
+ android:textColor="@android:color/white"
+ android:layout_gravity="top|left"
+ android:gravity="center"/>
+ </com.android.camera.ui.CountDownView>
+
</FrameLayout>
<item>@string/grid_lines_on_desc</item>
</array>
+ <array name="countdown_duration_descriptions" translatable="false">
+ <item>@string/countdown_timer_off</item>
+ <item>@string/countdown_timer_duration_3s</item>
+ <item>@string/countdown_timer_duration_10s</item>
+ </array>
+
<string-array name="pref_camera_pano_orientation_entryvalues">
<item>@string/pano_orientation_horizontal</item>
<item>@string/pano_orientation_vertical</item>
<item>@string/settings_close_desc</item>
</array>
+ <array name="countdown_duration_icons" translatable="false">
+ <item>@drawable/ic_timer_off_normal</item>
+ <item>@drawable/ic_timer_3s_normal</item>
+ <item>@drawable/ic_timer_10s_normal</item>
+ </array>
+
+ <array name="pref_camera_countdown_indicators" translatable="false">
+ <item>@drawable/ic_timer_off_indicator</item>
+ <item>@drawable/ic_timer_3s_indicator</item>
+ <item>@drawable/ic_timer_10s_indicator</item>
+ </array>
+
+ <string-array name="pref_countdown_duration" translatable="false">
+ <item>0</item>
+ <item>3</item>
+ <item>10</item>
+ </string-array>
+
<!--Index of camera modes. -->
<integer name="camera_mode_photo">0</integer>
public static final int BUTTON_REVIEW = 9;
public static final int BUTTON_GRID_LINES = 11;
public static final int BUTTON_EXPOSURE_COMPENSATION = 12;
+ public static final int BUTTON_COUNTDOWN = 13;
/** For two state MultiToggleImageButtons, the off index. */
public static final int OFF = 0;
private MultiToggleImageButton mButtonFlash;
private MultiToggleImageButton mButtonHdr;
private MultiToggleImageButton mButtonGridlines;
+ private MultiToggleImageButton mButtonCountdown;
/** Intent UI buttons. */
private ImageButton mButtonCancel;
mModeOptionsPano = (RadioOptions) root.findViewById(R.id.mode_options_pano);
mModeOptionsButtons = root.findViewById(R.id.mode_options_buttons);
mModeOptions = (ModeOptions) root.findViewById(R.id.mode_options);
+
+ mButtonCountdown = (MultiToggleImageButton) root.findViewById(R.id.countdown_toggle_button);
}
@Override
updateExposureButtons();
break;
}
+ case SettingsManager.SETTING_COUNTDOWN_DURATION: {
+ index = mSettingsManager.getStringValueIndex(id);
+ button = getButtonOrError(BUTTON_COUNTDOWN);
+ break;
+ }
default: {
// Do nothing.
}
throw new IllegalStateException("Grid lines button could not be found.");
}
return mButtonGridlines;
+ case BUTTON_COUNTDOWN:
+ if (mButtonCountdown == null) {
+ throw new IllegalStateException("Countdown button could not be found.");
+ }
+ return mButtonCountdown;
default:
throw new IllegalArgumentException("button not known by id=" + buttonId);
}
case BUTTON_GRID_LINES:
initializeGridLinesButton(button, cb, R.array.grid_lines_icons);
break;
+ case BUTTON_COUNTDOWN:
+ initializeCountdownButton(button, cb, R.array.countdown_duration_icons);
+ break;
default:
throw new IllegalArgumentException("button not known by id=" + buttonId);
}
}
/**
+ * Initialize a countdown timer button.
+ */
+ private void initializeCountdownButton(MultiToggleImageButton button,
+ final ButtonCallback cb, int resIdImages) {
+ if (resIdImages > 0) {
+ button.overrideImageIds(resIdImages);
+ }
+
+ int index = mSettingsManager.getStringValueIndex(
+ SettingsManager.SETTING_COUNTDOWN_DURATION);
+ button.setState(index >= 0 ? index : 0, false);
+
+ button.setOnStateChangeListener(new MultiToggleImageButton.OnStateChangeListener() {
+ @Override
+ public void stateChanged(View view, int state) {
+ mSettingsManager.setStringValueIndex(
+ SettingsManager.SETTING_COUNTDOWN_DURATION, state);
+ if(cb != null) {
+ cb.onStateChanged(state);
+ }
+ }
+ });
+ }
+
+ /**
* Update the visual state of the manual exposure buttons
*/
public void updateExposureButtons() {
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
+import android.media.AudioManager;
import android.media.CameraProfile;
+import android.media.SoundPool;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import com.android.camera.settings.ResolutionUtil;
import com.android.camera.settings.SettingsManager;
import com.android.camera.settings.SettingsUtil;
+import com.android.camera.ui.CountDownView;
import com.android.camera.util.ApiHelper;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.GcamHelper;
FocusOverlayManager.Listener,
SensorEventListener,
SettingsManager.OnSettingChangedListener,
- RemoteCameraModule {
+ RemoteCameraModule,
+ CountDownView.OnCountDownStatusListener {
private static final Log.Tag TAG = new Log.Tag("PhotoModule");
private FocusOverlayManager mFocusManager;
private final int mGcamModeIndex;
+ private final CountdownSoundPlayer mCountdownSoundPlayer = new CountdownSoundPlayer();
private String mSceneMode;
mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
mLocationManager = mActivity.getLocationManager();
mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
+ mUI.setCountdownFinishedListener(this);
+
+ // TODO: Make this a part of app controller API.
+ View cancelButton = mActivity.findViewById(R.id.shutter_cancel_button);
+ cancelButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ cancelCountDown();
+ }
+ });
+ }
+
+ private void cancelCountDown() {
+ if (mUI.isCountingDown()) {
+ // Cancel on-going countdown.
+ mUI.cancelCountDown();
+ }
+ mAppController.getCameraAppUI().transitionToCapture();
+ mAppController.getCameraAppUI().showModeOptions();
}
@Override
if (mPaused) {
return;
}
+ cancelCountDown();
SettingsManager settingsManager = mActivity.getSettingsManager();
Log.i(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
mCameraCapabilities.getExposureCompensationStep();
}
+ bottomBarSpec.enableSelfTimer = true;
+
if (isImageCaptureIntent()) {
bottomBarSpec.showCancel = true;
bottomBarSpec.cancelCallback = mCancelCallback;
}
Log.d(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
+ int countDownDuration = Integer.parseInt(mActivity.getSettingsManager()
+ .get(SettingsManager.SETTING_COUNTDOWN_DURATION));
+ if (countDownDuration > 0) {
+ // Start count down.
+ mAppController.getCameraAppUI().transitionToCancel();
+ mAppController.getCameraAppUI().hideModeOptions();
+ mUI.startCountdown(countDownDuration);
+ return;
+ } else {
+ focusAndCapture();
+ }
+ }
+
+ private void focusAndCapture() {
if (mSceneMode == CameraUtil.SCENE_MODE_HDR) {
mUI.setSwipingEnabled(false);
}
mFocusManager.focusAndCapture();
}
+ @Override
+ public void onRemainingSecondsChanged(int remainingSeconds) {
+ mCountdownSoundPlayer.onRemainingSecondsChanged(remainingSeconds);
+ }
+
+ @Override
+ public void onCountDownFinished() {
+ mAppController.getCameraAppUI().transitionToCapture();
+ mAppController.getCameraAppUI().showModeOptions();
+ if (mPaused) {
+ return;
+ }
+ focusAndCapture();
+ }
+
private void onResumeTasks() {
if (mPaused) {
return;
@Override
public void resume() {
mPaused = false;
+ mCountdownSoundPlayer.loadSounds();
if (mFocusManager != null) {
// If camera is not open when resume is called, focus manager will
// not
// preview area size change later in the initialization.
mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
}
-
- if (mUI.getPreviewAreaSizeChangedListener() != null) {
- mAppController.addPreviewAreaSizeChangedListener(
- mUI.getPreviewAreaSizeChangedListener());
- }
+ mAppController.addPreviewAreaSizeChangedListener(mUI);
// Add delay on resume from lock screen only, in order to to speed up
// the onResume --> onPause --> onResume cycle from lock screen.
// and startPreview hasn't been called, then this is a no-op.
// (e.g. onResume -> onPause -> onResume).
stopPreview();
+ cancelCountDown();
+ mCountdownSoundPlayer.release();
mNamedImages = null;
-
// If we are in an image capture intent and has taken
// a picture, we just clear it in onPause.
mJpegImageData = null;
}
getServices().getMemoryManager().removeListener(this);
mAppController.removePreviewAreaSizeChangedListener(mFocusManager);
- if (mUI.getPreviewAreaSizeChangedListener() != null) {
- mAppController.removePreviewAreaSizeChangedListener(
- mUI.getPreviewAreaSizeChangedListener());
- }
+ mAppController.removePreviewAreaSizeChangedListener(mUI);
SettingsManager settingsManager = mActivity.getSettingsManager();
settingsManager.removeListener(this);
public void onRemoteShutterPress() {
capture();
}
+
+ /**
+ * This class manages the loading/releasing/playing of the sounds needed for
+ * countdown timer.
+ */
+ private class CountdownSoundPlayer {
+ private SoundPool mSoundPool;
+ private int mBeepOnce;
+ private int mBeepTwice;
+
+ void loadSounds() {
+ // Load the beeps.
+ mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
+ mBeepOnce = mSoundPool.load(mAppController.getAndroidContext(), R.raw.beep_once, 1);
+ mBeepTwice = mSoundPool.load(mAppController.getAndroidContext(), R.raw.beep_twice, 1);
+ }
+
+ void onRemainingSecondsChanged(int newVal) {
+ if (mSoundPool == null) {
+ Log.e(TAG, "Cannot play sound - they have not been loaded.");
+ return;
+ }
+ if (newVal == 1) {
+ mSoundPool.play(mBeepTwice, 1.0f, 1.0f, 0, 0, 1.0f);
+ } else if (newVal == 2 || newVal == 3) {
+ mSoundPool.play(mBeepOnce, 1.0f, 1.0f, 0, 0, 1.0f);
+ }
+ }
+
+ void release() {
+ mSoundPool.release();
+ mSoundPool = null;
+ }
+ }
}
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.Face;
import com.android.camera.FocusOverlayManager.FocusUI;
import com.android.camera.cameradevice.CameraManager;
import com.android.camera.debug.Log;
+import com.android.camera.ui.CountDownView;
import com.android.camera.ui.FaceView;
import com.android.camera.ui.PreviewOverlay;
import com.android.camera.ui.PreviewStatusListener;
import java.util.List;
public class PhotoUI implements PreviewStatusListener,
- CameraManager.CameraFaceDetectionCallback {
+ CameraManager.CameraFaceDetectionCallback, PreviewStatusListener.PreviewAreaChangedListener {
private static final Log.Tag TAG = new Log.Tag("PhotoUI");
private static final int DOWN_SAMPLE_FACTOR = 4;
}
};
private Runnable mRunnableForNextFrame = null;
+ private CountDownView mCountdownView;
@Override
public GestureDetector.OnGestureListener getGestureListener() {
mRunnableForNextFrame = runnable;
}
+ /**
+ * Starts the countdown timer.
+ *
+ * @param sec seconds to countdown
+ */
+ public void startCountdown(int sec) {
+ mCountdownView.startCountDown(sec);
+ }
+
+ /**
+ * Sets a listener that gets notified when the countdown is finished.
+ */
+ public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
+ mCountdownView.setCountDownStatusListener(listener);
+ }
+
+ /**
+ * Returns whether the countdown is on-going.
+ */
+ public boolean isCountingDown() {
+ return mCountdownView.isCountingDown();
+ }
+
+ /**
+ * Cancels the on-going countdown, if any.
+ */
+ public void cancelCountDown() {
+ mCountdownView.cancelCountDown();
+ }
+
+ @Override
+ public void onPreviewAreaChanged(RectF previewArea) {
+ if (mFaceView != null) {
+ mFaceView.onPreviewAreaChanged(previewArea);
+ }
+ mCountdownView.onPreviewAreaChanged(previewArea);
+ }
+
private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
private final byte [] mData;
private final int mOrientation;
initIndicators();
mFocusUI = (FocusUI) mRootView.findViewById(R.id.focus_overlay);
mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
+ mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
}
public FocusUI getFocusUI() {
}
}
- /**
- * Returns a {@link com.android.camera.ui.PreviewStatusListener.PreviewAreaChangedListener}
- * that should be registered to listen to preview area change.
- */
- public PreviewAreaChangedListener getPreviewAreaSizeChangedListener() {
- return mFaceView;
- }
-
}
public int minExposureCompensation;
public int maxExposureCompensation;
public float exposureCompensationStep;
+
+ /**
+ * Whether or not timer should show.
+ */
+ public boolean enableSelfTimer = false;
}
}
}
+ if (bottomBarSpec.enableSelfTimer) {
+ buttonManager.initializeButton(ButtonManager.BUTTON_COUNTDOWN, null);
+ } else {
+ buttonManager.hideButton(ButtonManager.BUTTON_COUNTDOWN);
+ }
+
if (bottomBarSpec.enablePanoOrientation
&& PhotoSphereHelper.getPanoramaOrientationOptionArrayId() > 0) {
buttonManager.initializePanoOrientationButtons(bottomBarSpec.panoOrientationCallback);
SettingsManager.SETTING_EXPOSURE_COMPENSATION_ENABLED);
mKeyMap.put(SettingsManager.KEY_USER_SELECTED_ASPECT_RATIO,
SettingsManager.SETTING_USER_SELECTED_ASPECT_RATIO);
+ mKeyMap.put(SettingsManager.KEY_COUNTDOWN_DURATION,
+ SettingsManager.SETTING_COUNTDOWN_DURATION);
}
/**
return SettingsManager.getManualExposureCompensationSetting(mContext);
case SettingsManager.SETTING_USER_SELECTED_ASPECT_RATIO:
return SettingsManager.getUserSelectedAspectRatioSetting(mContext);
+ case SettingsManager.SETTING_COUNTDOWN_DURATION:
+ return SettingsManager.getCountDownDurationSetting(mContext);
default:
return mExtraSettings.settingFromId(id, mContext);
}
public static final int SETTING_SHOULD_SHOW_REFOCUS_VIEWER_CLING = 31;
public static final int SETTING_EXPOSURE_COMPENSATION_ENABLED = 32;
public static final int SETTING_USER_SELECTED_ASPECT_RATIO = 33;
+ public static final int SETTING_COUNTDOWN_DURATION = 34;
// Shared preference keys.
public static final String KEY_RECORD_LOCATION = "pref_camera_recordlocation_key";
public static final String KEY_EXPOSURE_COMPENSATION_ENABLED =
"pref_camera_exposure_compensation_key";
public static final String KEY_USER_SELECTED_ASPECT_RATIO = "pref_user_selected_aspect_ratio";
+ public static final String KEY_COUNTDOWN_DURATION = "pref_camera_countdown_duration_key";
public static final int WHITE_BALANCE_DEFAULT_INDEX = 2;
KEY_EXPOSURE_COMPENSATION_ENABLED, values, FLUSH_OFF);
}
+ public static Setting getCountDownDurationSetting(Context context) {
+ String defaultValue = Integer.toString(0);
+ String[] values = context.getResources().getStringArray(R.array.pref_countdown_duration);
+ return new Setting(SOURCE_DEFAULT, TYPE_STRING, defaultValue,
+ KEY_COUNTDOWN_DURATION, values, FLUSH_OFF);
+ }
+
public static Setting getPictureSizeBackSetting(Context context) {
String defaultValue = null;
String[] values = null;
private float mCenterX;
private float mCenterY;
private final RectF mRect = new RectF();
- private final RectF mPreviewArea = new RectF();
private CaptureLayoutHelper mCaptureLayoutHelper = null;
public BottomBar(Context context, AttributeSet attrs) {
mCancelLayout.setBackgroundColor(mBackgroundPressedColor);
} else if (MotionEvent.ACTION_UP == event.getActionMasked() ||
MotionEvent.ACTION_CANCEL == event.getActionMasked()) {
- mCancelLayout.setBackgroundColor(mBackgroundColor);
+ mCancelLayout.setBackgroundColor(mCircleColor);
} else if (MotionEvent.ACTION_MOVE == event.getActionMasked()) {
if (!mRect.contains(event.getX(), event.getY())) {
- mCancelLayout.setBackgroundColor(mBackgroundColor);
+ mCancelLayout.setBackgroundColor(mCircleColor);
}
}
return false;
public void transitionToCancel() {
mCaptureLayout.setVisibility(View.INVISIBLE);
mIntentReviewLayout.setVisibility(View.INVISIBLE);
+ mCancelLayout.setBackgroundColor(mCircleColor);
mCancelLayout.setVisibility(View.VISIBLE);
mMode = MODE_CANCEL;
}
--- /dev/null
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.ui;
+
+import java.util.Locale;
+
+import android.content.Context;
+import android.graphics.RectF;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.camera.debug.Log;
+import com.android.camera2.R;
+
+/**
+ * This class manages the looks of the countdown.
+ */
+public class CountDownView extends FrameLayout {
+
+ private static final Log.Tag TAG = new Log.Tag("CountDownView");
+ private static final int SET_TIMER_TEXT = 1;
+ private static final long ANIMATION_DURATION_MS = 800;
+ private TextView mRemainingSecondsView;
+ private int mRemainingSecs = 0;
+ private OnCountDownStatusListener mListener;
+ private final Handler mHandler = new MainHandler();
+ private final RectF mPreviewArea = new RectF();
+
+ /**
+ * Listener that gets notified when the countdown status has
+ * been updated (i.e. remaining seconds changed, or finished).
+ */
+ public interface OnCountDownStatusListener {
+ /**
+ * Gets notified when the remaining seconds for the countdown
+ * has changed.
+ *
+ * @param remainingSeconds seconds remained for countdown
+ */
+ public void onRemainingSecondsChanged(int remainingSeconds);
+
+ /**
+ * Gets called when countdown is finished.
+ */
+ public void onCountDownFinished();
+ }
+
+ public CountDownView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Returns whether countdown is on-going.
+ */
+ public boolean isCountingDown() {
+ return mRemainingSecs > 0;
+ };
+
+ /**
+ * Responds to preview area change by centering th countdown UI in the new
+ * preview area.
+ */
+ public void onPreviewAreaChanged(RectF previewArea) {
+ mPreviewArea.set(previewArea);
+ }
+
+ private void remainingSecondsChanged(int newVal) {
+ mRemainingSecs = newVal;
+ if (mListener != null) {
+ mListener.onRemainingSecondsChanged(mRemainingSecs);
+ }
+
+ if (newVal == 0) {
+ // Countdown has finished.
+ setVisibility(View.INVISIBLE);
+ if (mListener != null) {
+ mListener.onCountDownFinished();
+ }
+ } else {
+ Locale locale = getResources().getConfiguration().locale;
+ String localizedValue = String.format(locale, "%d", newVal);
+ mRemainingSecondsView.setText(localizedValue);
+ // Fade-out animation.
+ startFadeOutAnimation();
+ // Schedule the next remainingSecondsChanged() call in 1 second
+ mHandler.sendEmptyMessageDelayed(SET_TIMER_TEXT, 1000);
+ }
+ }
+
+ private void startFadeOutAnimation() {
+ int textWidth = mRemainingSecondsView.getMeasuredWidth();
+ int textHeight = mRemainingSecondsView.getMeasuredHeight();
+ mRemainingSecondsView.setScaleX(1f);
+ mRemainingSecondsView.setScaleY(1f);
+ mRemainingSecondsView.setTranslationX(mPreviewArea.centerX() - textWidth / 2);
+ mRemainingSecondsView.setTranslationY(mPreviewArea.centerY() - textHeight / 2);
+ mRemainingSecondsView.setPivotX(textWidth / 2);
+ mRemainingSecondsView.setPivotY(textHeight / 2);
+ mRemainingSecondsView.setAlpha(1f);
+ float endScale = 2.5f;
+ mRemainingSecondsView.animate().scaleX(endScale).scaleY(endScale)
+ .alpha(0f).setDuration(ANIMATION_DURATION_MS).start();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mRemainingSecondsView = (TextView) findViewById(R.id.remaining_seconds);
+ }
+
+ /**
+ * Sets a listener that gets notified when the status of countdown has changed.
+ */
+ public void setCountDownStatusListener(OnCountDownStatusListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Starts showing countdown in the UI.
+ *
+ * @param sec duration of the countdown, in seconds
+ */
+ public void startCountDown(int sec) {
+ if (sec <= 0) {
+ Log.w(TAG, "Invalid input for countdown timer: " + sec + " seconds");
+ return;
+ }
+ if (isCountingDown()) {
+ cancelCountDown();
+ }
+ setVisibility(View.VISIBLE);
+ remainingSecondsChanged(sec);
+ }
+
+ /**
+ * Cancels the on-going countdown in the UI, if any.
+ */
+ public void cancelCountDown() {
+ if (mRemainingSecs > 0) {
+ mRemainingSecs = 0;
+ mHandler.removeMessages(SET_TIMER_TEXT);
+ setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private class MainHandler extends Handler {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == SET_TIMER_TEXT) {
+ remainingSecondsChanged(mRemainingSecs -1);
+ }
+ }
+ }
+}
\ No newline at end of file
private ImageView mFlashIndicator;
private ImageView mHdrIndicator;
private ImageView mPanoIndicator;
+ private ImageView mCountdownTimerIndicator;
private ImageView mExposureIndicatorN2;
private ImageView mExposureIndicatorN1;
private TypedArray mHdrPlusIndicatorIcons;
private TypedArray mHdrIndicatorIcons;
private TypedArray mPanoIndicatorIcons;
+ private TypedArray mCountdownTimerIndicatorIcons;
private AppController mController;
context.getResources().obtainTypedArray(panoIndicatorArrayId);
}
+ mCountdownTimerIndicator = (ImageView) root.findViewById(R.id.countdown_timer_indicator);
+ mCountdownTimerIndicatorIcons = context.getResources().obtainTypedArray(
+ R.array.pref_camera_countdown_indicators);
+
mExposureIndicatorN2 = (ImageView) root.findViewById(R.id.exposure_n2_indicator);
mExposureIndicatorN1 = (ImageView) root.findViewById(R.id.exposure_n1_indicator);
mExposureIndicatorP1 = (ImageView) root.findViewById(R.id.exposure_p1_indicator);
syncHdrIndicator();
syncPanoIndicator();
syncExposureIndicator();
+ syncCountdownTimerIndicator();
}
/**
}
}
+ private void syncCountdownTimerIndicator() {
+ ButtonManager buttonManager = mController.getButtonManager();
+
+ if (buttonManager.isEnabled(ButtonManager.BUTTON_COUNTDOWN)
+ && buttonManager.isVisible(ButtonManager.BUTTON_COUNTDOWN)) {
+ setIndicatorState(mController.getSettingsManager(),
+ SettingsManager.SETTING_COUNTDOWN_DURATION,
+ mCountdownTimerIndicator, mCountdownTimerIndicatorIcons, false);
+ } else {
+ changeVisibility(mCountdownTimerIndicator, View.GONE);
+ }
+ }
+
/**
* Sets the image resource and visibility of the indicator
* based on the indicator's corresponding setting state.
syncExposureIndicator();
break;
}
+ case SettingsManager.SETTING_COUNTDOWN_DURATION:
+ syncCountdownTimerIndicator();
+ break;
default: {
// Do nothing.
}
}
}
+
}