From d6954f337e20365fc24ecffdd6f30e17c6b31eff Mon Sep 17 00:00:00 2001 From: Michael Kolb Date: Fri, 8 Mar 2013 20:43:01 -0800 Subject: Spring cleaning Change-Id: I00d7176301501784a6a400bc9ea2cb23ff9ec90a --- src/com/android/camera/CameraModule.java | 2 - src/com/android/camera/FocusOverlayManager.java | 65 +- src/com/android/camera/MediaSaveService.java | 14 +- src/com/android/camera/PanoramaModule.java | 5 - src/com/android/camera/PhotoController.java | 252 ++----- src/com/android/camera/PhotoMenu.java | 221 ++++++ src/com/android/camera/PhotoModule.java | 917 ++++++------------------ src/com/android/camera/PhotoUI.java | 725 +++++++++++++++++++ src/com/android/camera/PreviewGestures.java | 12 +- src/com/android/camera/VideoController.java | 187 ----- src/com/android/camera/VideoMenu.java | 187 +++++ src/com/android/camera/VideoModule.java | 8 +- 12 files changed, 1434 insertions(+), 1161 deletions(-) create mode 100644 src/com/android/camera/PhotoMenu.java create mode 100644 src/com/android/camera/PhotoUI.java delete mode 100644 src/com/android/camera/VideoController.java create mode 100644 src/com/android/camera/VideoMenu.java (limited to 'src/com') diff --git a/src/com/android/camera/CameraModule.java b/src/com/android/camera/CameraModule.java index aa057b916..3275d5f51 100644 --- a/src/com/android/camera/CameraModule.java +++ b/src/com/android/camera/CameraModule.java @@ -64,8 +64,6 @@ public interface CameraModule { public void updateCameraAppView(); - public boolean collapseCameraControls(); - public boolean needsSwitcher(); public boolean needsPieMenu(); diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java index a3726ed56..8bcb52fe5 100644 --- a/src/com/android/camera/FocusOverlayManager.java +++ b/src/com/android/camera/FocusOverlayManager.java @@ -27,9 +27,6 @@ import android.os.Looper; import android.os.Message; import android.util.Log; -import com.android.camera.ui.FaceView; -import com.android.camera.ui.FocusIndicator; -import com.android.camera.ui.PieRenderer; import com.android.gallery3d.common.ApiHelper; import java.util.ArrayList; @@ -78,13 +75,10 @@ public class FocusOverlayManager { private boolean mAeAwbLock; private Matrix mMatrix; - private PieRenderer mPieRenderer; - private int mPreviewWidth; // The width of the preview frame layout. private int mPreviewHeight; // The height of the preview frame layout. private boolean mMirror; // true if the camera is front-facing. private int mDisplayOrientation; - private FaceView mFaceView; private List mFocusArea; // focus area in driver format private List mMeteringArea; // metering area in driver format private String mFocusMode; @@ -97,6 +91,19 @@ public class FocusOverlayManager { private boolean mPreviousMoving; private boolean mFocusDefault; + private FocusUI mUI; + + public interface FocusUI { + public boolean hasFaces(); + public void clearFocus(); + public void setFocusPosition(int x, int y); + public void onFocusStarted(); + public void onFocusSucceeded(boolean timeOut); + public void onFocusFailed(boolean timeOut); + public void pauseFaceDetection(); + public void resumeFaceDetection(); + } + public interface Listener { public void autoFocus(); public void cancelAutoFocus(); @@ -125,7 +132,7 @@ public class FocusOverlayManager { public FocusOverlayManager(ComboPreferences preferences, String[] defaultFocusModes, Parameters parameters, Listener listener, - boolean mirror, Looper looper) { + boolean mirror, Looper looper, FocusUI ui) { mHandler = new MainHandler(looper); mMatrix = new Matrix(); mPreferences = preferences; @@ -134,11 +141,7 @@ public class FocusOverlayManager { mListener = listener; setMirror(mirror); mFocusDefault = true; - } - - public void setFocusRenderer(PieRenderer renderer) { - mPieRenderer = renderer; - mInitialized = (mMatrix != null); + mUI = ui; } public void setParameters(Parameters parameters) { @@ -172,10 +175,6 @@ public class FocusOverlayManager { setMatrix(); } - public void setFaceView(FaceView faceView) { - mFaceView = faceView; - } - private void setMatrix() { if (mPreviewWidth != 0 && mPreviewHeight != 0) { Matrix matrix = new Matrix(); @@ -185,7 +184,7 @@ public class FocusOverlayManager { // coordinates. In tap focus, the inverted matrix converts the UI // coordinates to driver coordinates. matrix.invert(mMatrix); - mInitialized = (mPieRenderer != null); + mInitialized = true; } } @@ -295,9 +294,11 @@ public class FocusOverlayManager { public void onAutoFocusMoving(boolean moving) { if (!mInitialized) return; + + // Ignore if the camera has detected some faces. - if (mFaceView != null && mFaceView.faceExists()) { - mPieRenderer.clear(); + if (mUI.hasFaces()) { + mUI.clearFocus(); return; } @@ -307,9 +308,9 @@ public class FocusOverlayManager { // animate on false->true trasition only b/8219520 if (moving && !mPreviousMoving) { - mPieRenderer.showStart(); + mUI.onFocusStarted(); } else if (!moving) { - mPieRenderer.showSuccess(true); + mUI.onFocusSucceeded(true); } mPreviousMoving = moving; } @@ -358,7 +359,7 @@ public class FocusOverlayManager { } // Use margin to set the focus indicator to the touched area. - mPieRenderer.setFocus(x, y); + mUI.setFocusPosition(x, y); // Stop face detection because we want to specify focus and metering area. mListener.stopFaceDetection(); @@ -396,7 +397,7 @@ public class FocusOverlayManager { mState = STATE_FOCUSING; // Pause the face view because the driver will keep sending face // callbacks after the focus completes. - if (mFaceView != null) mFaceView.pause(); + mUI.pauseFaceDetection(); updateFocusUI(); mHandler.removeMessages(RESET_TOUCH_FOCUS); } @@ -409,7 +410,7 @@ public class FocusOverlayManager { // driver is not reset. resetTouchFocus(); mListener.cancelAutoFocus(); - if (mFaceView != null) mFaceView.resume(); + mUI.resumeFaceDetection(); mState = STATE_IDLE; updateFocusUI(); mHandler.removeMessages(RESET_TOUCH_FOCUS); @@ -470,28 +471,26 @@ public class FocusOverlayManager { public void updateFocusUI() { if (!mInitialized) return; // Show only focus indicator or face indicator. - boolean faceExists = (mFaceView != null && mFaceView.faceExists()); - FocusIndicator focusIndicator = (faceExists) ? mFaceView : mPieRenderer; if (mState == STATE_IDLE) { if (mFocusDefault) { - focusIndicator.clear(); + mUI.clearFocus(); } else { // Users touch on the preview and the indicator represents the // metering area. Either focus area is not supported or // autoFocus call is not required. - focusIndicator.showStart(); + mUI.onFocusStarted(); } } else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) { - focusIndicator.showStart(); + mUI.onFocusStarted(); } else { if (Util.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)) { // TODO: check HAL behavior and decide if this can be removed. - focusIndicator.showSuccess(false); + mUI.onFocusSucceeded(false); } else if (mState == STATE_SUCCESS) { - focusIndicator.showSuccess(false); + mUI.onFocusSucceeded(false); } else if (mState == STATE_FAIL) { - focusIndicator.showFail(false); + mUI.onFocusFailed(false); } } } @@ -500,7 +499,7 @@ public class FocusOverlayManager { if (!mInitialized) return; // Put focus indicator to the center. clear reset position - mPieRenderer.clear(); + mUI.clearFocus(); // Initialize mFocusArea. if (mFocusAreaSupported) { initializeFocusAreas(mPreviewWidth / 2, mPreviewHeight / 2); diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index d0e02f1d7..48fb629e9 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -38,8 +38,8 @@ public class MediaSaveService extends Service { private Listener mListener; interface Listener { - public void onQueueAvailable(); - public void onQueueFull(); + + public void onQueueStatus(boolean full); } interface OnMediaSavedListener { @@ -96,19 +96,15 @@ public class MediaSaveService extends Service { public void setListener(Listener l) { mListener = l; if (l == null) return; - if (isQueueFull()) { - l.onQueueFull(); - } else { - l.onQueueAvailable(); - } + l.onQueueStatus(isQueueFull()); } private void onQueueFull() { - if (mListener != null) mListener.onQueueFull(); + if (mListener != null) mListener.onQueueStatus(true); } private void onQueueAvailable() { - if (mListener != null) mListener.onQueueAvailable(); + if (mListener != null) mListener.onQueueStatus(false); } private class SaveTask extends AsyncTask { diff --git a/src/com/android/camera/PanoramaModule.java b/src/com/android/camera/PanoramaModule.java index d12c8286e..2703c3596 100644 --- a/src/com/android/camera/PanoramaModule.java +++ b/src/com/android/camera/PanoramaModule.java @@ -1297,11 +1297,6 @@ public class PanoramaModule implements CameraModule, public void updateCameraAppView() { } - @Override - public boolean collapseCameraControls() { - return false; - } - @Override public boolean needsSwitcher() { return true; diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index c2501c781..b76022e57 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * 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. @@ -16,211 +16,47 @@ package com.android.camera; -import android.content.Context; -import android.hardware.Camera.Parameters; -import android.view.LayoutInflater; - -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.ListPrefSettingPopup; -import com.android.camera.ui.MoreSettingPopup; -import com.android.camera.ui.PieItem; -import com.android.camera.ui.PieItem.OnClickListener; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.TimerSettingPopup; -import com.android.gallery3d.R; - -public class PhotoController extends PieController - implements MoreSettingPopup.Listener, - TimerSettingPopup.Listener, - ListPrefSettingPopup.Listener { - private static String TAG = "CAM_photocontrol"; - private static float FLOAT_PI_DIVIDED_BY_TWO = (float) Math.PI / 2; - private final String mSettingOff; - - private PhotoModule mModule; - private String[] mOtherKeys; - // First level popup - private MoreSettingPopup mPopup; - // Second level popup - private AbstractSettingPopup mSecondPopup; - - public PhotoController(CameraActivity activity, PhotoModule module, PieRenderer pie) { - super(activity, pie); - mModule = module; - mSettingOff = activity.getString(R.string.setting_off_value); - } - - public void initialize(PreferenceGroup group) { - super.initialize(group); - mPopup = null; - mSecondPopup = null; - float sweep = FLOAT_PI_DIVIDED_BY_TWO / 2; - addItem(CameraSettings.KEY_FLASH_MODE, FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); - addItem(CameraSettings.KEY_EXPOSURE, 3 * FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); - addItem(CameraSettings.KEY_WHITE_BALANCE, 3 * FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); - if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { - PieItem item = makeItem(R.drawable.ic_switch_photo_facing_holo_light); - item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - // Find the index of next camera. - ListPreference camPref = mPreferenceGroup - .findPreference(CameraSettings.KEY_CAMERA_ID); - if (camPref != null) { - int index = camPref.findIndexOfValue(camPref.getValue()); - CharSequence[] values = camPref.getEntryValues(); - index = (index + 1) % values.length; - int newCameraId = Integer - .parseInt((String) values[index]); - mListener.onCameraPickerClicked(newCameraId); - } - } - }); - mRenderer.addItem(item); - } - if (group.findPreference(CameraSettings.KEY_CAMERA_HDR) != null) { - PieItem hdr = makeItem(R.drawable.ic_hdr); - hdr.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO, sweep); - hdr.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - // Find the index of next camera. - ListPreference pref = mPreferenceGroup - .findPreference(CameraSettings.KEY_CAMERA_HDR); - if (pref != null) { - // toggle hdr value - int index = (pref.findIndexOfValue(pref.getValue()) + 1) % 2; - pref.setValueIndex(index); - onSettingChanged(pref); - } - } - }); - mRenderer.addItem(hdr); - } - mOtherKeys = new String[] { - CameraSettings.KEY_SCENE_MODE, - CameraSettings.KEY_RECORD_LOCATION, - CameraSettings.KEY_PICTURE_SIZE, - CameraSettings.KEY_FOCUS_MODE, - CameraSettings.KEY_TIMER, - CameraSettings.KEY_TIMER_SOUND_EFFECTS, - }; - PieItem item = makeItem(R.drawable.ic_settings_holo_light); - item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO * 3, sweep); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - if (mPopup == null) { - initializePopup(); - } - mModule.showPopup(mPopup); - } - }); - mRenderer.addItem(item); - } - - protected void setCameraId(int cameraId) { - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - pref.setValue("" + cameraId); - } - - @Override - public void reloadPreferences() { - super.reloadPreferences(); - if (mPopup != null) { - mPopup.reloadPreference(); - } - } - - @Override - // Hit when an item in the second-level popup gets selected - public void onListPrefChanged(ListPreference pref) { - if (mPopup != null && mSecondPopup != null) { - mModule.dismissPopup(true); - mPopup.reloadPreference(); - } - onSettingChanged(pref); - } - - @Override - public void overrideSettings(final String ... keyvalues) { - super.overrideSettings(keyvalues); - if (mPopup == null) initializePopup(); - mPopup.overrideSettings(keyvalues); - } - - protected void initializePopup() { - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( - R.layout.more_setting_popup, null, false); - popup.setSettingChangedListener(this); - popup.initialize(mPreferenceGroup, mOtherKeys); - if (mActivity.isSecureCamera()) { - // Prevent location preference from getting changed in secure camera mode - popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); - } - mPopup = popup; - } - - public void popupDismissed(boolean topPopupOnly) { - // if the 2nd level popup gets dismissed - if (mSecondPopup != null) { - mSecondPopup = null; - if (topPopupOnly) mModule.showPopup(mPopup); - } - } - - // Return true if the preference has the specified key but not the value. - private static boolean notSame(ListPreference pref, String key, String value) { - return (key.equals(pref.getKey()) && !value.equals(pref.getValue())); - } - - private void setPreference(String key, String value) { - ListPreference pref = mPreferenceGroup.findPreference(key); - if (pref != null && !value.equals(pref.getValue())) { - pref.setValue(value); - reloadPreferences(); - } - } - - @Override - public void onSettingChanged(ListPreference pref) { - // Reset the scene mode if HDR is set to on. Reset HDR if scene mode is - // set to non-auto. - if (notSame(pref, CameraSettings.KEY_CAMERA_HDR, mSettingOff)) { - setPreference(CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO); - } else if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) { - setPreference(CameraSettings.KEY_CAMERA_HDR, mSettingOff); - } - super.onSettingChanged(pref); - } - - @Override - // Hit when an item in the first-level popup gets selected, then bring up - // the second-level popup - public void onPreferenceClicked(ListPreference pref) { - if (mSecondPopup != null) return; - - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - if (CameraSettings.KEY_TIMER.equals(pref.getKey())) { - TimerSettingPopup timerPopup = (TimerSettingPopup) inflater.inflate( - R.layout.timer_setting_popup, null, false); - timerPopup.initialize(pref); - timerPopup.setSettingChangedListener(this); - mModule.dismissPopup(true); - mSecondPopup = timerPopup; - } else { - ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( - R.layout.list_pref_setting_popup, null, false); - basic.initialize(pref); - basic.setSettingChangedListener(this); - mModule.dismissPopup(true); - mSecondPopup = basic; - } - mModule.showPopup(mSecondPopup); - } +import android.view.SurfaceHolder; +import android.view.View; + +import com.android.camera.ShutterButton.OnShutterButtonListener; + + +public interface PhotoController extends OnShutterButtonListener { + + public static final int PREVIEW_STOPPED = 0; + public static final int IDLE = 1; // preview is active + // Focus is in progress. The exact focus state is in Focus.java. + public static final int FOCUSING = 2; + public static final int SNAPSHOT_IN_PROGRESS = 3; + // Switching between cameras. + public static final int SWITCHING_CAMERA = 4; + + // returns the actual set zoom value + public int onZoomChanged(int requestedZoom); + + public boolean isImageCaptureIntent(); + + public boolean isCameraIdle(); + + public void onCaptureDone(); + + public void onCaptureCancelled(); + + public void onCaptureRetake(); + + public void cancelAutoFocus(); + + public void stopPreview(); + + public int getCameraState(); + + public void onSingleTapUp(View view, int x, int y); + + public void onSurfaceCreated(SurfaceHolder holder); + + public void onCountDownFinished(); + + public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight); + } diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java new file mode 100644 index 000000000..2535a0cc4 --- /dev/null +++ b/src/com/android/camera/PhotoMenu.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2012 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; + +import android.content.Context; +import android.hardware.Camera.Parameters; +import android.view.LayoutInflater; + +import com.android.camera.ui.AbstractSettingPopup; +import com.android.camera.ui.ListPrefSettingPopup; +import com.android.camera.ui.MoreSettingPopup; +import com.android.camera.ui.PieItem; +import com.android.camera.ui.PieItem.OnClickListener; +import com.android.camera.ui.PieRenderer; +import com.android.camera.ui.TimerSettingPopup; +import com.android.gallery3d.R; + +public class PhotoMenu extends PieController + implements MoreSettingPopup.Listener, + TimerSettingPopup.Listener, + ListPrefSettingPopup.Listener { + private static String TAG = "CAM_photomenu"; + private static float FLOAT_PI_DIVIDED_BY_TWO = (float) Math.PI / 2; + private final String mSettingOff; + + private PhotoUI mUI; + private String[] mOtherKeys; + // First level popup + private MoreSettingPopup mPopup; + // Second level popup + private AbstractSettingPopup mSecondPopup; + + public PhotoMenu(CameraActivity activity, PhotoUI ui, PieRenderer pie) { + super(activity, pie); + mUI = ui; + mSettingOff = activity.getString(R.string.setting_off_value); + } + + public void initialize(PreferenceGroup group) { + super.initialize(group); + mPopup = null; + mSecondPopup = null; + float sweep = FLOAT_PI_DIVIDED_BY_TWO / 2; + addItem(CameraSettings.KEY_FLASH_MODE, FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); + addItem(CameraSettings.KEY_EXPOSURE, 3 * FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); + addItem(CameraSettings.KEY_WHITE_BALANCE, 3 * FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); + if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { + PieItem item = makeItem(R.drawable.ic_switch_photo_facing_holo_light); + item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); + item.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + // Find the index of next camera. + ListPreference camPref = mPreferenceGroup + .findPreference(CameraSettings.KEY_CAMERA_ID); + if (camPref != null) { + int index = camPref.findIndexOfValue(camPref.getValue()); + CharSequence[] values = camPref.getEntryValues(); + index = (index + 1) % values.length; + int newCameraId = Integer + .parseInt((String) values[index]); + mListener.onCameraPickerClicked(newCameraId); + } + } + }); + mRenderer.addItem(item); + } + if (group.findPreference(CameraSettings.KEY_CAMERA_HDR) != null) { + PieItem hdr = makeItem(R.drawable.ic_hdr); + hdr.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO, sweep); + hdr.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + // Find the index of next camera. + ListPreference pref = mPreferenceGroup + .findPreference(CameraSettings.KEY_CAMERA_HDR); + if (pref != null) { + // toggle hdr value + int index = (pref.findIndexOfValue(pref.getValue()) + 1) % 2; + pref.setValueIndex(index); + onSettingChanged(pref); + } + } + }); + mRenderer.addItem(hdr); + } + mOtherKeys = new String[] { + CameraSettings.KEY_SCENE_MODE, + CameraSettings.KEY_RECORD_LOCATION, + CameraSettings.KEY_PICTURE_SIZE, + CameraSettings.KEY_FOCUS_MODE, + CameraSettings.KEY_TIMER, + CameraSettings.KEY_TIMER_SOUND_EFFECTS, + }; + PieItem item = makeItem(R.drawable.ic_settings_holo_light); + item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO * 3, sweep); + item.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup == null) { + initializePopup(); + } + mUI.showPopup(mPopup); + } + }); + mRenderer.addItem(item); + } + + @Override + public void reloadPreferences() { + super.reloadPreferences(); + if (mPopup != null) { + mPopup.reloadPreference(); + } + } + + @Override + // Hit when an item in the second-level popup gets selected + public void onListPrefChanged(ListPreference pref) { + if (mPopup != null && mSecondPopup != null) { + mUI.dismissPopup(true); + mPopup.reloadPreference(); + } + onSettingChanged(pref); + } + + @Override + public void overrideSettings(final String ... keyvalues) { + super.overrideSettings(keyvalues); + if (mPopup == null) initializePopup(); + mPopup.overrideSettings(keyvalues); + } + + protected void initializePopup() { + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + + MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup.setSettingChangedListener(this); + popup.initialize(mPreferenceGroup, mOtherKeys); + if (mActivity.isSecureCamera()) { + // Prevent location preference from getting changed in secure camera mode + popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); + } + mPopup = popup; + } + + public void popupDismissed(boolean topPopupOnly) { + // if the 2nd level popup gets dismissed + if (mSecondPopup != null) { + mSecondPopup = null; + if (topPopupOnly) mUI.showPopup(mPopup); + } + } + + // Return true if the preference has the specified key but not the value. + private static boolean notSame(ListPreference pref, String key, String value) { + return (key.equals(pref.getKey()) && !value.equals(pref.getValue())); + } + + private void setPreference(String key, String value) { + ListPreference pref = mPreferenceGroup.findPreference(key); + if (pref != null && !value.equals(pref.getValue())) { + pref.setValue(value); + reloadPreferences(); + } + } + + @Override + public void onSettingChanged(ListPreference pref) { + // Reset the scene mode if HDR is set to on. Reset HDR if scene mode is + // set to non-auto. + if (notSame(pref, CameraSettings.KEY_CAMERA_HDR, mSettingOff)) { + setPreference(CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO); + } else if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) { + setPreference(CameraSettings.KEY_CAMERA_HDR, mSettingOff); + } + super.onSettingChanged(pref); + } + + @Override + // Hit when an item in the first-level popup gets selected, then bring up + // the second-level popup + public void onPreferenceClicked(ListPreference pref) { + if (mSecondPopup != null) return; + + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + if (CameraSettings.KEY_TIMER.equals(pref.getKey())) { + TimerSettingPopup timerPopup = (TimerSettingPopup) inflater.inflate( + R.layout.timer_setting_popup, null, false); + timerPopup.initialize(pref); + timerPopup.setSettingChangedListener(this); + mUI.dismissPopup(true); + mSecondPopup = timerPopup; + } else { + ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( + R.layout.list_pref_setting_popup, null, false); + basic.initialize(pref); + basic.setSettingChangedListener(this); + mUI.dismissPopup(true); + mSecondPopup = basic; + } + mUI.showPopup(mSecondPopup); + } +} diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 4049aa573..4c627c92c 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -28,8 +28,6 @@ import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.SurfaceTexture; import android.hardware.Camera.CameraInfo; -import android.hardware.Camera.Face; -import android.hardware.Camera.FaceDetectionListener; import android.hardware.Camera.Parameters; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; @@ -45,32 +43,17 @@ import android.os.MessageQueue; import android.os.SystemClock; import android.provider.MediaStore; import android.util.Log; -import android.view.Gravity; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.SurfaceHolder; import android.view.View; -import android.view.ViewStub; -import android.view.View.OnClickListener; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.FrameLayout.LayoutParams; -import android.widget.ImageView; -import android.widget.Toast; import com.android.camera.CameraManager.CameraProxy; -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.CountDownView; -import com.android.camera.ui.FaceView; -import com.android.camera.ui.PieRenderer; +import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; import com.android.camera.ui.PopupManager; -import com.android.camera.ui.RenderOverlay; import com.android.camera.ui.RotateTextToast; -import com.android.camera.ui.ZoomRenderer; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.filtershow.CropExtras; @@ -88,14 +71,12 @@ import java.util.List; public class PhotoModule implements CameraModule, + PhotoController, FocusOverlayManager.Listener, CameraPreference.OnPreferenceChangedListener, - LocationManager.Listener, ShutterButton.OnShutterButtonListener, - SurfaceHolder.Callback, - PieRenderer.PieListener, - CountDownView.OnCountDownFinishedListener, - MediaSaveService.Listener { + MediaSaveService.Listener, + OnCountDownFinishedListener { private static final String TAG = "CAM_PhotoModule"; @@ -127,12 +108,12 @@ public class PhotoModule // copied from Camera hierarchy private CameraActivity mActivity; - private View mRootView; private CameraProxy mCameraDevice; private int mCameraId; private Parameters mParameters; private boolean mPaused; - private AbstractSettingPopup mPopup; + + private PhotoUI mUI; // these are only used by Camera @@ -150,8 +131,6 @@ public class PhotoModule private static final int SCREEN_DELAY = 2 * 60 * 1000; private int mZoomValue; // The current zoom value. - private int mZoomMax; - private List mZoomRatios; private Parameters mInitialParams; private boolean mFocusAreaSupported; @@ -167,35 +146,12 @@ public class PhotoModule private static final String sTempCropFilename = "crop-temp"; private ContentProviderClient mMediaProviderClient; - private ShutterButton mShutterButton; private boolean mFaceDetectionStarted = false; - private Object mSurfaceTexture; - private CountDownView mCountDownView; - - private volatile SurfaceHolder mCameraSurfaceHolder; - - private FaceView mFaceView; - private RenderOverlay mRenderOverlay; - private View mReviewCancelButton; - private View mReviewDoneButton; - private View mReviewRetakeButton; - // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. private String mCropValue; private Uri mSaveUri; - private View mMenu; - private View mBlocker; - - // Small indicators which show the camera settings in the viewfinder. - private ImageView mExposureIndicator; - private ImageView mFlashIndicator; - private ImageView mSceneIndicator; - private ImageView mHdrIndicator; - // A view group that contains all the small indicators. - private View mOnScreenIndicators; - // We use a queue to generated names of the images to be used later // when the image is ready to be saved. private NamedImages mNamedImages; @@ -207,16 +163,6 @@ public class PhotoModule } }; - private final View.OnLayoutChangeListener mLayoutChangeListener = - new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, - int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - onScreenSizeChanged(right - left, bottom - top); - } - }; - private int mPreviewWidth = 0; - private int mPreviewHeight = 0; private final StringBuilder mBuilder = new StringBuilder(); private final Formatter mFormatter = new Formatter(mBuilder); private final Object[] mFormatterArgs = new Object[1]; @@ -242,13 +188,6 @@ public class PhotoModule private boolean mFirstTimeInitialized; private boolean mIsImageCaptureIntent; - private static final int PREVIEW_STOPPED = 0; - private static final int IDLE = 1; // preview is active - // Focus is in progress. The exact focus state is in Focus.java. - private static final int FOCUSING = 2; - private static final int SNAPSHOT_IN_PROGRESS = 3; - // Switching between cameras. - private static final int SWITCHING_CAMERA = 4; private int mCameraState = PREVIEW_STOPPED; private boolean mSnapshotOnIdle = false; @@ -289,12 +228,7 @@ public class PhotoModule // This handles everything about focus. private FocusOverlayManager mFocusManager; - private PieRenderer mPieRenderer; - private PhotoController mPhotoControl; - - private ZoomRenderer mZoomRenderer; private String mSceneMode; - private Toast mNotSelectableToast; private final Handler mHandler = new MainHandler(); private PreferenceGroup mPreferenceGroup; @@ -304,8 +238,6 @@ public class PhotoModule CameraStartUpThread mCameraStartUpThread; ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); - private PreviewGestures mGestures; - private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @Override @@ -420,19 +352,12 @@ public class PhotoModule } case CAMERA_OPEN_DONE: { - initializeAfterCameraOpen(); + onCameraOpened(); break; } case START_PREVIEW_DONE: { - mCameraStartUpThread = null; - setCameraState(IDLE); - if (!ApiHelper.HAS_SURFACE_TEXTURE) { - // This may happen if surfaceCreated has arrived. - mCameraDevice.setPreviewDisplayAsync(mCameraSurfaceHolder); - } - startFaceDetection(); - locationFirstRun(); + onPreviewStarted(); break; } @@ -458,7 +383,7 @@ public class PhotoModule @Override public void init(CameraActivity activity, View parent, boolean reuseNail) { mActivity = activity; - mRootView = parent; + mUI = new PhotoUI(activity, this, parent); mPreferences = new ComboPreferences(mActivity); CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); mCameraId = getPreferredCameraId(mPreferences); @@ -470,17 +395,6 @@ public class PhotoModule mCameraStartUpThread = new CameraStartUpThread(); mCameraStartUpThread.start(); - mActivity.getLayoutInflater().inflate(R.layout.photo_module, - (ViewGroup) mRootView, true); - mRootView.addOnLayoutChangeListener(mLayoutChangeListener); - if (ApiHelper.HAS_FACE_DETECTION) { - ViewStub faceViewStub = (ViewStub) mRootView - .findViewById(R.id.face_view_stub); - if (faceViewStub != null) { - faceViewStub.inflate(); - mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); - } - } // Surface texture is from camera screen nail and startPreview needs it. // This must be done before startPreview. @@ -501,10 +415,25 @@ public class PhotoModule initializeControlByIntent(); mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); - mLocationManager = new LocationManager(mActivity, this); - initOnScreenIndicator(); - mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); - mCountDownView.setCountDownFinishedListener(this); + mLocationManager = new LocationManager(mActivity, mUI); + } + + private void initializeControlByIntent() { + mUI.initializeControlByIntent(); + if (mIsImageCaptureIntent) { + setupCaptureParams(); + } + } + + private void onPreviewStarted() { + mCameraStartUpThread = null; + setCameraState(IDLE); + if (!ApiHelper.HAS_SURFACE_TEXTURE) { + // This may happen if surfaceCreated has arrived. + mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); + } + startFaceDetection(); + locationFirstRun(); } // Prompt the user to pick to record location for the very first run of @@ -554,52 +483,12 @@ public class PhotoModule onSharedPreferenceChanged(); } - private void initializeRenderOverlay() { - if (mPieRenderer != null) { - mRenderOverlay.addRenderer(mPieRenderer); - mFocusManager.setFocusRenderer(mPieRenderer); - } - if (mZoomRenderer != null) { - mRenderOverlay.addRenderer(mZoomRenderer); - } - if (mGestures != null) { - mGestures.clearTouchReceivers(); - mGestures.setRenderOverlay(mRenderOverlay); - mGestures.addTouchReceiver(mMenu); - mGestures.addTouchReceiver(mBlocker); - - if (isImageCaptureIntent()) { - if (mReviewCancelButton != null) { - mGestures.addTouchReceiver(mReviewCancelButton); - } - if (mReviewDoneButton != null) { - mGestures.addTouchReceiver(mReviewDoneButton); - } - } - } - mRenderOverlay.requestLayout(); - } - - private void initializeAfterCameraOpen() { - if (mPieRenderer == null) { - mPieRenderer = new PieRenderer(mActivity); - mPhotoControl = new PhotoController(mActivity, this, mPieRenderer); - mPhotoControl.setListener(this); - mPieRenderer.setPieListener(this); - } - if (mZoomRenderer == null) { - mZoomRenderer = new ZoomRenderer(mActivity); - } - if (mGestures == null) { - // this will handle gesture disambiguation and dispatching - mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); - } - initializeRenderOverlay(); - initializePhotoControl(); - + private void onCameraOpened() { + View root = mUI.getRootView(); // These depend on camera parameters. - int width = mRootView.getWidth(); - int height = mRootView.getHeight(); + + int width = root.getWidth(); + int height = root.getHeight(); mFocusManager.setPreviewSize(width, height); // Full-screen screennail if (Util.getDisplayRotation(mActivity) % 180 == 0) { @@ -608,37 +497,76 @@ public class PhotoModule ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(height, width); } // Set touch focus listener. - mActivity.setSingleTapUpListener(mRootView); - loadCameraPreferences(); - initializeZoom(); - updateOnScreenIndicators(); - showTapToFocusToastIfNeeded(); + mActivity.setSingleTapUpListener(root); + openCameraCommon(); onFullScreenChanged(mActivity.isInCameraApp()); } - public void onScreenSizeChanged(int width, int height) { - // Full-screen screennail - int w = width; - int h = height; - if (Util.getDisplayRotation(mActivity) % 180 != 0) { - w = height; - h = width; + private void switchCamera() { + if (mPaused) return; + + Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId); + mCameraId = mPendingSwitchCameraId; + mPendingSwitchCameraId = -1; + setCameraId(mCameraId); + + // from onPause + closeCamera(); + mUI.collapseCameraControls(); + mUI.clearFaces(); + if (mFocusManager != null) mFocusManager.removeMessages(); + + // Restart the camera and initialize the UI. From onCreate. + mPreferences.setLocalId(mActivity, mCameraId); + CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); + try { + mCameraDevice = Util.openCamera(mActivity, mCameraId); + mParameters = mCameraDevice.getParameters(); + } catch (CameraHardwareException e) { + Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); + return; + } catch (CameraDisabledException e) { + Util.showErrorAndFinish(mActivity, R.string.camera_disabled); + return; } - if (mPreviewWidth != w || mPreviewHeight != h) { - Log.d(TAG, "Preview size changed."); - if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); - ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(w, h); + initializeCapabilities(); + CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; + boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); + mFocusManager.setMirror(mirror); + mFocusManager.setParameters(mInitialParams); + setupPreview(); + + openCameraCommon(); + + if (ApiHelper.HAS_SURFACE_TEXTURE) { + // Start switch camera animation. Post a message because + // onFrameAvailable from the old camera may already exist. + mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); } } - private void initializePhotoControl() { + protected void setCameraId(int cameraId) { + ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); + pref.setValue("" + cameraId); + } + + // either open a new camera or switch cameras + private void openCameraCommon() { loadCameraPreferences(); - if (mPhotoControl != null) { - mPhotoControl.initialize(mPreferenceGroup); - } - updateSceneModeUI(); + + mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this); + updateSceneMode(); + showTapToFocusToastIfNeeded(); + + } + public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { + Log.d(TAG, "Preview size changed."); + if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); + ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize( + previewWidth, previewHeight); + } private void resetExposureCompensation() { String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE, @@ -673,11 +601,7 @@ public class PhotoModule keepMediaProviderInstance(); - // Initialize shutter button. - mShutterButton = mActivity.getShutterButton(); - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mShutterButton.setOnShutterButtonListener(this); - mShutterButton.setVisibility(View.VISIBLE); + mUI.initializeFirstTime(); MediaSaveService s = mActivity.getMediaSaveService(); // We set the listener only when both service and shutterbutton // are initialized. @@ -693,93 +617,54 @@ public class PhotoModule mActivity.updateStorageSpaceAndHint(); } - private void showTapToFocusToastIfNeeded() { - // Show the tap to focus toast if this is the first start. - if (mFocusAreaSupported && - mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) { - // Delay the toast for one second to wait for orientation. - mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000); - } - } - - private void addIdleHandler() { - MessageQueue queue = Looper.myQueue(); - queue.addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - Storage.ensureOSXCompatible(); - return false; - } - }); - } - // If the activity is paused and resumed, this method will be called in // onResume. private void initializeSecondTime() { - // Start location update if needed. boolean recordLocation = RecordLocationPreference.get( mPreferences, mContentResolver); mLocationManager.recordLocation(recordLocation); - MediaSaveService s = mActivity.getMediaSaveService(); if (s != null) { s.setListener(this); } mNamedImages = new NamedImages(); - initializeZoom(); + mUI.initializeSecondTime(mParameters); keepMediaProviderInstance(); - hidePostCaptureAlert(); - - if (mPhotoControl != null) { - mPhotoControl.reloadPreferences(); - } } - private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { - @Override - public void onZoomValueChanged(int index) { - // Not useful to change zoom value when the activity is paused. - if (mPaused) return; - mZoomValue = index; - if (mParameters == null || mCameraDevice == null) return; - // Set zoom parameters asynchronously - mParameters.setZoom(mZoomValue); - mCameraDevice.setParametersAsync(mParameters); - if (mZoomRenderer != null) { - Parameters p = mCameraDevice.getParameters(); - mZoomRenderer.setZoomValue(mZoomRatios.get(p.getZoom())); - } - } + @Override + public void onSurfaceCreated(SurfaceHolder holder) { + // Do not access the camera if camera start up thread is not finished. + if (mCameraDevice == null || mCameraStartUpThread != null) + return; - @Override - public void onZoomStart() { - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(true); - } + mCameraDevice.setPreviewDisplayAsync(holder); + // This happens when onConfigurationChanged arrives, surface has been + // destroyed, and there is no onFullScreenChanged. + if (mCameraState == PREVIEW_STOPPED) { + setupPreview(); } + } - @Override - public void onZoomEnd() { - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(false); - } + private void showTapToFocusToastIfNeeded() { + // Show the tap to focus toast if this is the first start. + if (mFocusAreaSupported && + mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) { + // Delay the toast for one second to wait for orientation. + mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000); } } - private void initializeZoom() { - if ((mParameters == null) || !mParameters.isZoomSupported() - || (mZoomRenderer == null)) return; - mZoomMax = mParameters.getMaxZoom(); - mZoomRatios = mParameters.getZoomRatios(); - // Currently we use immediate zoom for fast zooming to get better UX and - // there is no plan to take advantage of the smooth zoom. - if (mZoomRenderer != null) { - mZoomRenderer.setZoomMax(mZoomMax); - mZoomRenderer.setZoom(mParameters.getZoom()); - mZoomRenderer.setZoomValue(mZoomRatios.get(mParameters.getZoom())); - mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); - } + private void addIdleHandler() { + MessageQueue queue = Looper.myQueue(); + queue.addIdleHandler(new MessageQueue.IdleHandler() { + @Override + public boolean queueIdle() { + Storage.ensureOSXCompatible(); + return false; + } + }); } @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) @@ -789,19 +674,10 @@ public class PhotoModule if (mFaceDetectionStarted) return; if (mParameters.getMaxNumDetectedFaces() > 0) { mFaceDetectionStarted = true; - mFaceView.clear(); - mFaceView.setVisibility(View.VISIBLE); - mFaceView.setDisplayOrientation(mDisplayOrientation); CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - mFaceView.setMirror(info.facing == CameraInfo.CAMERA_FACING_FRONT); - mFaceView.resume(); - mFocusManager.setFaceView(mFaceView); - mCameraDevice.setFaceDetectionListener(new FaceDetectionListener() { - @Override - public void onFaceDetection(Face[] faces, android.hardware.Camera camera) { - mFaceView.setFaces(faces); - } - }); + mUI.onStartFaceDetection(mDisplayOrientation, + (info.facing == CameraInfo.CAMERA_FACING_FRONT)); + mCameraDevice.setFaceDetectionListener(mUI); mCameraDevice.startFaceDetection(); } } @@ -815,115 +691,14 @@ public class PhotoModule mFaceDetectionStarted = false; mCameraDevice.setFaceDetectionListener(null); mCameraDevice.stopFaceDetection(); - if (mFaceView != null) mFaceView.clear(); + mUI.clearFaces(); } } @Override public boolean dispatchTouchEvent(MotionEvent m) { if (mCameraState == SWITCHING_CAMERA) return true; - if (mPopup != null) { - return mActivity.superDispatchTouchEvent(m); - } else if (mGestures != null && mRenderOverlay != null) { - return mGestures.dispatchTouch(m); - } - return false; - } - - private void initOnScreenIndicator() { - mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators); - mExposureIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_exposure_indicator); - mFlashIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_flash_indicator); - mSceneIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_scenemode_indicator); - mHdrIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_hdr_indicator); - } - - @Override - public void showGpsOnScreenIndicator(boolean hasSignal) { } - - @Override - public void hideGpsOnScreenIndicator() { } - - private void updateExposureOnScreenIndicator(int value) { - if (mExposureIndicator == null) { - return; - } - int id = 0; - float step = mParameters.getExposureCompensationStep(); - value = (int) Math.round(value * step); - switch(value) { - case -3: - id = R.drawable.ic_indicator_ev_n3; - break; - case -2: - id = R.drawable.ic_indicator_ev_n2; - break; - case -1: - id = R.drawable.ic_indicator_ev_n1; - break; - case 0: - id = R.drawable.ic_indicator_ev_0; - break; - case 1: - id = R.drawable.ic_indicator_ev_p1; - break; - case 2: - id = R.drawable.ic_indicator_ev_p2; - break; - case 3: - id = R.drawable.ic_indicator_ev_p3; - break; - } - mExposureIndicator.setImageResource(id); - - } - - private void updateFlashOnScreenIndicator(String value) { - if (mFlashIndicator == null) { - return; - } - if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) { - mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off); - } else { - if (Parameters.FLASH_MODE_AUTO.equals(value)) { - mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_auto); - } else if (Parameters.FLASH_MODE_ON.equals(value)) { - mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_on); - } else { - mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off); - } - } - } - - private void updateSceneOnScreenIndicator(String value) { - if (mSceneIndicator == null) { - return; - } - if ((value == null) || Parameters.SCENE_MODE_AUTO.equals(value) - || Parameters.SCENE_MODE_HDR.equals(value)) { - mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_off); - } else { - mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_on); - } - } - - private void updateHdrOnScreenIndicator(String value) { - if (mHdrIndicator == null) { - return; - } - if ((value != null) && Parameters.SCENE_MODE_HDR.equals(value)) { - mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_on); - } else { - mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_off); - } - } - - private void updateOnScreenIndicators() { - if (mParameters == null) return; - updateSceneOnScreenIndicator(mParameters.getSceneMode()); - updateExposureOnScreenIndicator(CameraSettings.readExposure(mPreferences)); - updateFlashOnScreenIndicator(mParameters.getFlashMode()); - updateHdrOnScreenIndicator(mParameters.getSceneMode()); + return mUI.dispatchTouchEvent(m); } private final class ShutterCallback @@ -1038,9 +813,9 @@ public class PhotoModule } else { mJpegImageData = jpegData; if (!mQuickCapture) { - showPostCaptureAlert(); + mUI.showPostCaptureAlert(); } else { - doAttach(); + onCaptureDone(); } } @@ -1068,7 +843,7 @@ public class PhotoModule mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime; Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); setCameraState(IDLE); - mFocusManager.onAutoFocus(focused, mShutterButton.isPressed()); + mFocusManager.onAutoFocus(focused, mUI.isShutterPressed()); } } @@ -1124,18 +899,17 @@ public class PhotoModule private void setCameraState(int state) { mCameraState = state; switch (state) { - case PREVIEW_STOPPED: - case SNAPSHOT_IN_PROGRESS: - case FOCUSING: - case SWITCHING_CAMERA: - if (mGestures != null) mGestures.setEnabled(false); - break; - case IDLE: - if (mGestures != null && mActivity.mShowCameraAppView) { - // Enable gestures only when the camera app view is visible - mGestures.setEnabled(true); - } - break; + case PhotoController.PREVIEW_STOPPED: + case PhotoController.SNAPSHOT_IN_PROGRESS: + case PhotoController.FOCUSING: + case PhotoController.SWITCHING_CAMERA: + mUI.enableGestures(false); + break; + case PhotoController.IDLE: + if (mActivity.isInCameraApp()) { + mUI.enableGestures(true); + } + break; } } @@ -1215,38 +989,9 @@ public class PhotoModule } } - private void setShowMenu(boolean show) { - if (mOnScreenIndicators != null) { - mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); - } - if (mMenu != null) { - mMenu.setVisibility(show ? View.VISIBLE : View.GONE); - } - } - @Override public void onFullScreenChanged(boolean full) { - if (mFaceView != null) { - mFaceView.setBlockDraw(!full); - } - if (mPopup != null) { - dismissPopup(false, full); - } - if (mGestures != null) { - mGestures.setEnabled(full); - } - if (mRenderOverlay != null) { - // this can not happen in capture mode - mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE); - } - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(!full); - } - setShowMenu(full); - if (mBlocker != null) { - mBlocker.setVisibility(full ? View.VISIBLE : View.GONE); - } - if (!full && mCountDownView != null) mCountDownView.cancelCountDown(); + mUI.onFullScreenChanged(full); if (ApiHelper.HAS_SURFACE_TEXTURE) { if (mActivity.mCameraScreenNail != null) { ((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full); @@ -1255,35 +1000,7 @@ public class PhotoModule } } - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height=" - + height); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.v(TAG, "surfaceCreated: " + holder); - mCameraSurfaceHolder = holder; - // Do not access the camera if camera start up thread is not finished. - if (mCameraDevice == null || mCameraStartUpThread != null) return; - - mCameraDevice.setPreviewDisplayAsync(holder); - // This happens when onConfigurationChanged arrives, surface has been - // destroyed, and there is no onFullScreenChanged. - if (mCameraState == PREVIEW_STOPPED) { - setupPreview(); - } - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.v(TAG, "surfaceDestroyed: " + holder); - mCameraSurfaceHolder = null; - stopPreview(); - } - - private void updateSceneModeUI() { + private void updateSceneMode() { // If scene mode is set, we cannot set flash mode, white balance, and // focus mode, instead, we read it from driver if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { @@ -1296,14 +1013,10 @@ public class PhotoModule private void overrideCameraSettings(final String flashMode, final String whiteBalance, final String focusMode) { - if (mPhotoControl != null) { -// mPieControl.enableFilter(true); - mPhotoControl.overrideSettings( - CameraSettings.KEY_FLASH_MODE, flashMode, - CameraSettings.KEY_WHITE_BALANCE, whiteBalance, - CameraSettings.KEY_FOCUS_MODE, focusMode); -// mPieControl.enableFilter(false); - } + mUI.overrideSettings( + CameraSettings.KEY_FLASH_MODE, flashMode, + CameraSettings.KEY_WHITE_BALANCE, whiteBalance, + CameraSettings.KEY_FOCUS_MODE, focusMode); } private void loadCameraPreferences() { @@ -1312,26 +1025,6 @@ public class PhotoModule mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences); } - @Override - public boolean collapseCameraControls() { - // Remove all the popups/dialog boxes - boolean ret = false; - if (mPopup != null) { - dismissPopup(false); - ret = true; - } - return ret; - } - - public boolean removeTopLevelPopup() { - // Remove the top level popup or dialog box and return true if there's any - if (mPopup != null) { - dismissPopup(true); - return true; - } - return false; - } - @Override public void onOrientationChanged(int orientation) { // We keep the last known orientation. So if the user first orient @@ -1355,29 +1048,22 @@ public class PhotoModule } } - // onClick handler for R.id.btn_done - @OnClickAttr - public void onReviewDoneClicked(View v) { - doAttach(); - } - - // onClick handler for R.id.btn_cancel - @OnClickAttr - public void onReviewCancelClicked(View v) { - doCancel(); + @Override + public void onCaptureCancelled() { + mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent()); + mActivity.finish(); } - // onClick handler for R.id.btn_retake - @OnClickAttr - public void onReviewRetakeClicked(View v) { + @Override + public void onCaptureRetake() { if (mPaused) return; - - hidePostCaptureAlert(); + mUI.hidePostCaptureAlert(); setupPreview(); } - private void doAttach() { + @Override + public void onCaptureDone() { if (mPaused) { return; } @@ -1456,14 +1142,9 @@ public class PhotoModule } } - private void doCancel() { - mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent()); - mActivity.finish(); - } - @Override public void onShutterButtonFocus(boolean pressed) { - if (mPaused || collapseCameraControls() + if (mPaused || mUI.collapseCameraControls() || (mCameraState == SNAPSHOT_IN_PROGRESS) || (mCameraState == PREVIEW_STOPPED)) return; @@ -1479,7 +1160,7 @@ public class PhotoModule } else { // for countdown mode, we need to postpone the shutter release // i.e. lock the focus during countdown. - if (!mCountDownView.isCountingDown()) { + if (!mUI.isCountingDown()) { mFocusManager.onShutterUp(); } } @@ -1487,7 +1168,7 @@ public class PhotoModule @Override public void onShutterButtonClick() { - if (mPaused || collapseCameraControls() + if (mPaused || mUI.collapseCameraControls() || (mCameraState == SWITCHING_CAMERA) || (mCameraState == PREVIEW_STOPPED)) return; @@ -1520,11 +1201,11 @@ public class PhotoModule int seconds = Integer.parseInt(timer); // When shutter button is pressed, check whether the previous countdown is // finished. If not, cancel the previous countdown and start a new one. - if (mCountDownView.isCountingDown()) { - mCountDownView.cancelCountDown(); - mCountDownView.startCountDown(seconds, playSound); - } else if (seconds > 0) { - mCountDownView.startCountDown(seconds, playSound); + if (mUI.isCountingDown()) { + mUI.cancelCountDown(); + } + if (seconds > 0) { + mUI.startCountDown(seconds, playSound); } else { mSnapshotOnIdle = false; mFocusManager.doSnap(); @@ -1614,17 +1295,8 @@ public class PhotoModule mCameraDevice.cancelAutoFocus(); } stopPreview(); - mCountDownView.cancelCountDown(); - // Close the camera now because other activities may need to use it. - closeCamera(); // Release surface texture. ((CameraScreenNail) mActivity.mCameraScreenNail).releaseSurfaceTexture(); - mSurfaceTexture = null; - resetScreenOn(); - - // Clear UI. - collapseCameraControls(); - if (mFaceView != null) mFaceView.clear(); mNamedImages = null; @@ -1645,9 +1317,11 @@ public class PhotoModule mHandler.removeMessages(OPEN_CAMERA_FAIL); mHandler.removeMessages(CAMERA_DISABLED); - mRootView.removeOnLayoutChangeListener(mLayoutChangeListener); - mPreviewWidth = 0; - mPreviewHeight = 0; + closeCamera(); + + resetScreenOn(); + mUI.onPause(); + mPendingSwitchCameraId = -1; if (mFocusManager != null) mFocusManager.removeMessages(); MediaSaveService s = mActivity.getMediaSaveService(); @@ -1656,61 +1330,12 @@ public class PhotoModule } } - private void initializeControlByIntent() { - mBlocker = mActivity.findViewById(R.id.blocker); - mMenu = mActivity.findViewById(R.id.menu); - mMenu.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mPieRenderer != null) { - // If autofocus is not finished, cancel autofocus so that the - // subsequent touch can be handled by PreviewGestures - if (mCameraState == FOCUSING) cancelAutoFocus(); - mPieRenderer.showInCenter(); - } - } - }); - if (mIsImageCaptureIntent) { - mActivity.hideSwitcher(); - ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); - mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); - - mReviewDoneButton = mActivity.findViewById(R.id.btn_done); - mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); - mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake); - mReviewCancelButton.setVisibility(View.VISIBLE); - - mReviewDoneButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - onReviewDoneClicked(v); - } - }); - mReviewCancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - onReviewCancelClicked(v); - } - }); - - mReviewRetakeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - onReviewRetakeClicked(v); - } - }); - - setupCaptureParams(); - } - } - /** * The focus manager is the first UI related element to get initialized, * and it requires the RenderOverlay, so initialize it here */ private void initializeFocusManager() { // Create FocusManager object. startPreview needs it. - mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); // if mFocusManager not null, reuse it // otherwise create a new instance if (mFocusManager != null) { @@ -1722,7 +1347,7 @@ public class PhotoModule R.array.pref_camera_focusmode_default_array); mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes, mInitialParams, this, mirror, - mActivity.getMainLooper()); + mActivity.getMainLooper(), mUI); } } @@ -1784,7 +1409,7 @@ public class PhotoModule } // Do not trigger touch focus if popup window is opened. - if (removeTopLevelPopup()) return; + if (mUI.removeTopLevelPopup()) return; // Check if metering area or focus area is supported. if (!mFocusAreaSupported && !mMeteringAreaSupported) return; @@ -1793,24 +1418,7 @@ public class PhotoModule @Override public boolean onBackPressed() { - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - return true; - } - // In image capture mode, back button should: - // 1) if there is any popup, dismiss them, 2) otherwise, get out of image capture - if (mIsImageCaptureIntent) { - if (!removeTopLevelPopup()) { - // no popup to dismiss, cancel image capture - doCancel(); - } - return true; - } else if (!isCameraIdle()) { - // ignore backs while we're taking a picture - return true; - } else { - return removeTopLevelPopup(); - } + return mUI.onBackPressed(); } @Override @@ -1838,14 +1446,9 @@ public class PhotoModule // Start auto-focus immediately to reduce shutter lag. After // the shutter button gets the focus, onShutterButtonFocus() // will be called again but it is fine. - if (removeTopLevelPopup()) return true; + if (mUI.removeTopLevelPopup()) return true; onShutterButtonFocus(true); - if (mShutterButton.isInTouchMode()) { - mShutterButton.requestFocusFromTouch(); - } else { - mShutterButton.requestFocus(); - } - mShutterButton.setPressed(true); + mUI.pressShutterButton(); } return true; } @@ -1891,9 +1494,7 @@ public class PhotoModule mDisplayRotation = Util.getDisplayRotation(mActivity); mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); mCameraDisplayOrientation = Util.getDisplayOrientation(0, mCameraId); - if (mFaceView != null) { - mFaceView.setDisplayOrientation(mDisplayOrientation); - } + mUI.setDisplayOrientation(mDisplayOrientation); if (mFocusManager != null) { mFocusManager.setDisplayOrientation(mDisplayOrientation); } @@ -1933,7 +1534,7 @@ public class PhotoModule if (ApiHelper.HAS_SURFACE_TEXTURE) { CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - if (mSurfaceTexture == null) { + if (mUI.getSurfaceTexture() == null) { Size size = mParameters.getPreviewSize(); if (mCameraDisplayOrientation % 180 == 0) { screenNail.setSize(size.width, size.height); @@ -1947,15 +1548,16 @@ public class PhotoModule if (t != null && t.isCanceled()) { return; // Exiting, so no need to get the surface texture. } - mSurfaceTexture = screenNail.getSurfaceTexture(); + mUI.setSurfaceTexture(screenNail.getSurfaceTexture()); } mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - if (mSurfaceTexture != null) { - mCameraDevice.setPreviewTextureAsync((SurfaceTexture) mSurfaceTexture); + Object st = mUI.getSurfaceTexture(); + if (st != null) { + mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st); } } else { mCameraDevice.setDisplayOrientation(mDisplayOrientation); - mCameraDevice.setPreviewDisplayAsync(mCameraSurfaceHolder); + mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); } Log.v(TAG, "startPreview"); @@ -1968,7 +1570,8 @@ public class PhotoModule } } - private void stopPreview() { + @Override + public void stopPreview() { if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { Log.v(TAG, "stopPreview"); mCameraDevice.stopPreview(); @@ -2197,7 +1800,7 @@ public class PhotoModule return; } else if (isCameraIdle()) { setCameraParameters(mUpdateSet); - updateSceneModeUI(); + updateSceneMode(); mUpdateSet = 0; } else { if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) { @@ -2207,14 +1810,14 @@ public class PhotoModule } } - private boolean isCameraIdle() { + public boolean isCameraIdle() { return (mCameraState == IDLE) || (mCameraState == PREVIEW_STOPPED) || ((mFocusManager != null) && mFocusManager.isFocusCompleted() && (mCameraState != SWITCHING_CAMERA)); } - private boolean isImageCaptureIntent() { + public boolean isImageCaptureIntent() { String action = mActivity.getIntent().getAction(); return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) || ActivityBase.ACTION_IMAGE_CAPTURE_SECURE.equals(action)); @@ -2228,26 +1831,6 @@ public class PhotoModule } } - private void showPostCaptureAlert() { - if (mIsImageCaptureIntent) { - mOnScreenIndicators.setVisibility(View.GONE); - mMenu.setVisibility(View.GONE); - Util.fadeIn(mReviewDoneButton); - mShutterButton.setVisibility(View.INVISIBLE); - Util.fadeIn(mReviewRetakeButton); - } - } - - private void hidePostCaptureAlert() { - if (mIsImageCaptureIntent) { - mOnScreenIndicators.setVisibility(View.VISIBLE); - mMenu.setVisibility(View.VISIBLE); - Util.fadeOut(mReviewDoneButton); - mShutterButton.setVisibility(View.VISIBLE); - Util.fadeOut(mReviewRetakeButton); - } - } - @Override public void onSharedPreferenceChanged() { // ignore the events after "onPause()" @@ -2258,7 +1841,7 @@ public class PhotoModule mLocationManager.recordLocation(recordLocation); setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); - updateOnScreenIndicators(); + mUI.updateOnScreenIndicators(mParameters, mPreferences); } @Override @@ -2278,71 +1861,6 @@ public class PhotoModule } } - private void switchCamera() { - if (mPaused) return; - - Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId); - mCameraId = mPendingSwitchCameraId; - mPendingSwitchCameraId = -1; - mPhotoControl.setCameraId(mCameraId); - - // from onPause - closeCamera(); - collapseCameraControls(); - if (mFaceView != null) mFaceView.clear(); - if (mFocusManager != null) mFocusManager.removeMessages(); - - // Restart the camera and initialize the UI. From onCreate. - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - try { - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - initializeCapabilities(); - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); - mFocusManager.setMirror(mirror); - mFocusManager.setParameters(mInitialParams); - setupPreview(); - loadCameraPreferences(); - initializePhotoControl(); - - // from initializeFirstTime - initializeZoom(); - updateOnScreenIndicators(); - showTapToFocusToastIfNeeded(); - - if (ApiHelper.HAS_SURFACE_TEXTURE) { - // Start switch camera animation. Post a message because - // onFrameAvailable from the old camera may already exist. - mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); - } - } - - @Override - public void onPieOpened(int centerX, int centerY) { - mActivity.cancelActivityTouchHandling(); - mActivity.setSwipingEnabled(false); - if (mFaceView != null) { - mFaceView.setBlockDraw(true); - } - } - - @Override - public void onPieClosed() { - mActivity.setSwipingEnabled(true); - if (mFaceView != null) { - mFaceView.setBlockDraw(false); - } - } - // Preview texture has been copied. Now camera can be released and the // animation can be started. @Override @@ -2378,11 +1896,7 @@ public class PhotoModule @Override public void onOverriddenPreferencesClicked() { if (mPaused) return; - if (mNotSelectableToast == null) { - String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); - mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); - } - mNotSelectableToast.show(); + mUI.showPreferencesToast(); } private void showTapToFocusToast() { @@ -2421,56 +1935,41 @@ public class PhotoModule return true; } - public void showPopup(AbstractSettingPopup popup) { - mActivity.hideUI(); - mBlocker.setVisibility(View.INVISIBLE); - setShowMenu(false); - mPopup = popup; - mPopup.setVisibility(View.VISIBLE); - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - ((FrameLayout) mRootView).addView(mPopup, lp); - } - - public void dismissPopup(boolean topPopupOnly) { - dismissPopup(topPopupOnly, true); - } - - private void dismissPopup(boolean topOnly, boolean fullScreen) { - if (fullScreen) { - mActivity.showUI(); - mBlocker.setVisibility(View.VISIBLE); - } - setShowMenu(fullScreen); - if (mPopup != null) { - ((FrameLayout) mRootView).removeView(mPopup); - mPopup = null; - } - mPhotoControl.popupDismissed(topOnly); + @Override + public void onShowSwitcherPopup() { + mUI.onShowSwitcherPopup(); } @Override - public void onShowSwitcherPopup() { - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - } + public int onZoomChanged(int index) { + // Not useful to change zoom value when the activity is paused. + if (mPaused) return index; + mZoomValue = index; + if (mParameters == null || mCameraDevice == null) return index; + // Set zoom parameters asynchronously + mParameters.setZoom(mZoomValue); + mCameraDevice.setParametersAsync(mParameters); + Parameters p = mCameraDevice.getParameters(); + if (p != null) return p.getZoom(); + return index; } @Override - public void onQueueAvailable() { - if (mShutterButton != null) mShutterButton.enableTouch(true); + public int getCameraState() { + return mCameraState; } @Override - public void onQueueFull() { - if (mShutterButton != null) mShutterButton.enableTouch(false); + public void onQueueStatus(boolean full) { + mUI.enableShutter(!full); } @Override public void onMediaSaveServiceConnected(MediaSaveService s) { // We set the listener only when both service and shutterbutton // are initialized. - if (mShutterButton != null) s.setListener(this); + if (mFirstTimeInitialized) { + s.setListener(this); + } } } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java new file mode 100644 index 000000000..995996480 --- /dev/null +++ b/src/com/android/camera/PhotoUI.java @@ -0,0 +1,725 @@ +/* + * 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. + */ + + +package com.android.camera; + +import android.hardware.Camera; +import android.hardware.Camera.Face; +import android.hardware.Camera.FaceDetectionListener; +import android.hardware.Camera.Parameters; +import android.util.Log; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLayoutChangeListener; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; +import android.widget.ImageView; +import android.widget.Toast; + +import com.android.camera.CameraPreference.OnPreferenceChangedListener; +import com.android.camera.FocusOverlayManager.FocusUI; +import com.android.camera.ui.AbstractSettingPopup; +import com.android.camera.ui.CountDownView; +import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; +import com.android.camera.ui.FaceView; +import com.android.camera.ui.FocusIndicator; +import com.android.camera.ui.PieRenderer; +import com.android.camera.ui.PieRenderer.PieListener; +import com.android.camera.ui.RenderOverlay; +import com.android.camera.ui.ZoomRenderer; +import com.android.gallery3d.R; +import com.android.gallery3d.common.ApiHelper; + +import java.util.List; + +public class PhotoUI implements PieListener, + SurfaceHolder.Callback, + PreviewGestures.SingleTapListener, + FocusUI, + LocationManager.Listener, + FaceDetectionListener { + + private static final String TAG = "CAM_UI"; + + private CameraActivity mActivity; + private PhotoController mController; + private PreviewGestures mGestures; + + private View mRootView; + private Object mSurfaceTexture; + private volatile SurfaceHolder mSurfaceHolder; + + private AbstractSettingPopup mPopup; + private ShutterButton mShutterButton; + private CountDownView mCountDownView; + + private FaceView mFaceView; + private RenderOverlay mRenderOverlay; + private View mReviewCancelButton; + private View mReviewDoneButton; + private View mReviewRetakeButton; + + private View mMenuButton; + private View mBlocker; + private PhotoMenu mMenu; + + // Small indicators which show the camera settings in the viewfinder. + private ImageView mExposureIndicator; + private ImageView mFlashIndicator; + private ImageView mSceneIndicator; + private ImageView mHdrIndicator; + // A view group that contains all the small indicators. + private View mOnScreenIndicators; + + private PieRenderer mPieRenderer; + private ZoomRenderer mZoomRenderer; + private Toast mNotSelectableToast; + + private int mZoomMax; + private List mZoomRatios; + + private int mPreviewWidth = 0; + private int mPreviewHeight = 0; + + private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, + int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + int width = right - left; + int height = bottom - top; + // Full-screen screennail + int w = width; + int h = height; + if (Util.getDisplayRotation(mActivity) % 180 != 0) { + w = height; + h = width; + } + if (mPreviewWidth != w || mPreviewHeight != h) { + mController.onScreenSizeChanged(width, height, w, h); + } + } + }; + + public PhotoUI(CameraActivity activity, PhotoController controller, View parent) { + mActivity = activity; + mController = controller; + mRootView = parent; + + mActivity.getLayoutInflater().inflate(R.layout.photo_module, + (ViewGroup) mRootView, true); + mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); + + initIndicators(); + mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); + mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); + + if (ApiHelper.HAS_FACE_DETECTION) { + ViewStub faceViewStub = (ViewStub) mRootView + .findViewById(R.id.face_view_stub); + if (faceViewStub != null) { + faceViewStub.inflate(); + mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); + } + } + + mRootView.addOnLayoutChangeListener(mLayoutListener); + } + + public View getRootView() { + return mRootView; + } + + private void initIndicators() { + mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators); + mExposureIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_exposure_indicator); + mFlashIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_flash_indicator); + mSceneIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_scenemode_indicator); + mHdrIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_hdr_indicator); + } + + public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, + Camera.Parameters params, OnPreferenceChangedListener listener) { + if (mPieRenderer == null) { + mPieRenderer = new PieRenderer(mActivity); + mPieRenderer.setPieListener(this); + } + if (mMenu == null) { + mMenu = new PhotoMenu(mActivity, this, mPieRenderer); + mMenu.setListener(listener); + } + mMenu.initialize(prefGroup); + + if (mZoomRenderer == null) { + mZoomRenderer = new ZoomRenderer(mActivity); + } + mRenderOverlay.addRenderer(mPieRenderer); + mRenderOverlay.addRenderer(mZoomRenderer); + if (mGestures == null) { + // this will handle gesture disambiguation and dispatching + mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); + } + mGestures.clearTouchReceivers(); + mGestures.setRenderOverlay(mRenderOverlay); + mGestures.addTouchReceiver(mMenuButton); + mGestures.addTouchReceiver(mBlocker); + // make sure to add touch targets for image capture + if (mController.isImageCaptureIntent()) { + if (mReviewCancelButton != null) { + mGestures.addTouchReceiver(mReviewCancelButton); + } + if (mReviewDoneButton != null) { + mGestures.addTouchReceiver(mReviewDoneButton); + } + } + mRenderOverlay.requestLayout(); + + initializeZoom(params); + updateOnScreenIndicators(params, prefs); + } + + public void initializeControlByIntent() { + mBlocker = mActivity.findViewById(R.id.blocker); + mMenuButton = mActivity.findViewById(R.id.menu); + mMenuButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mPieRenderer != null) { + // If autofocus is not finished, cancel autofocus so that the + // subsequent touch can be handled by PreviewGestures + if (mController.getCameraState() == PhotoController.FOCUSING) { + mController.cancelAutoFocus(); + } + mPieRenderer.showInCenter(); + } + } + }); + if (mController.isImageCaptureIntent()) { + mActivity.hideSwitcher(); + ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); + mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); + + mReviewDoneButton = mActivity.findViewById(R.id.btn_done); + mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); + mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake); + mReviewCancelButton.setVisibility(View.VISIBLE); + + mReviewDoneButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mController.onCaptureDone(); + } + }); + mReviewCancelButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mController.onCaptureCancelled(); + } + }); + + mReviewRetakeButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mController.onCaptureRetake(); + } + }); + } + } + + // called from onResume but only the first time + public void initializeFirstTime() { + // Initialize shutter button. + mShutterButton = mActivity.getShutterButton(); + mShutterButton.setImageResource(R.drawable.btn_new_shutter); + mShutterButton.setOnShutterButtonListener(mController); + mShutterButton.setVisibility(View.VISIBLE); + } + + // called from onResume every other time + public void initializeSecondTime(Camera.Parameters params) { + initializeZoom(params); + if (mController.isImageCaptureIntent()) { + hidePostCaptureAlert(); + } + if (mMenu != null) { + mMenu.reloadPreferences(); + } + } + + public void initializeZoom(Camera.Parameters params) { + if ((params == null) || !params.isZoomSupported() + || (mZoomRenderer == null)) return; + mZoomMax = params.getMaxZoom(); + mZoomRatios = params.getZoomRatios(); + // Currently we use immediate zoom for fast zooming to get better UX and + // there is no plan to take advantage of the smooth zoom. + if (mZoomRenderer != null) { + mZoomRenderer.setZoomMax(mZoomMax); + mZoomRenderer.setZoom(params.getZoom()); + mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom())); + mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); + } + } + + public void enableGestures(boolean enable) { + if (mGestures != null) { + mGestures.setEnabled(enable); + } + } + + public void showGpsOnScreenIndicator(boolean hasSignal) { } + + public void hideGpsOnScreenIndicator() { } + + public void overrideSettings(final String ... keyvalues) { + mMenu.overrideSettings(keyvalues); + } + + public void updateOnScreenIndicators(Camera.Parameters params, + ComboPreferences prefs) { + if (params == null) return; + updateSceneOnScreenIndicator(params.getSceneMode()); + updateExposureOnScreenIndicator(params, + CameraSettings.readExposure(prefs)); + updateFlashOnScreenIndicator(params.getFlashMode()); + updateHdrOnScreenIndicator(params.getSceneMode()); + } + + private void updateExposureOnScreenIndicator(Camera.Parameters params, int value) { + if (mExposureIndicator == null) { + return; + } + int id = 0; + float step = params.getExposureCompensationStep(); + value = (int) Math.round(value * step); + switch(value) { + case -3: + id = R.drawable.ic_indicator_ev_n3; + break; + case -2: + id = R.drawable.ic_indicator_ev_n2; + break; + case -1: + id = R.drawable.ic_indicator_ev_n1; + break; + case 0: + id = R.drawable.ic_indicator_ev_0; + break; + case 1: + id = R.drawable.ic_indicator_ev_p1; + break; + case 2: + id = R.drawable.ic_indicator_ev_p2; + break; + case 3: + id = R.drawable.ic_indicator_ev_p3; + break; + } + mExposureIndicator.setImageResource(id); + } + + private void updateFlashOnScreenIndicator(String value) { + if (mFlashIndicator == null) { + return; + } + if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) { + mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off); + } else { + if (Parameters.FLASH_MODE_AUTO.equals(value)) { + mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_auto); + } else if (Parameters.FLASH_MODE_ON.equals(value)) { + mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_on); + } else { + mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off); + } + } + } + + private void updateSceneOnScreenIndicator(String value) { + if (mSceneIndicator == null) { + return; + } + if ((value == null) || Parameters.SCENE_MODE_AUTO.equals(value) + || Parameters.SCENE_MODE_HDR.equals(value)) { + mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_off); + } else { + mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_on); + } + } + + private void updateHdrOnScreenIndicator(String value) { + if (mHdrIndicator == null) { + return; + } + if ((value != null) && Parameters.SCENE_MODE_HDR.equals(value)) { + mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_on); + } else { + mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_off); + } + } + + public void setCameraState(int state) { + } + + public boolean dispatchTouchEvent(MotionEvent m) { + if (mPopup != null) { + return mActivity.superDispatchTouchEvent(m); + } else if (mGestures != null && mRenderOverlay != null) { + return mGestures.dispatchTouch(m); + } + return false; + } + + public boolean onBackPressed() { + if (mPieRenderer != null && mPieRenderer.showsItems()) { + mPieRenderer.hide(); + return true; + } + // In image capture mode, back button should: + // 1) if there is any popup, dismiss them, 2) otherwise, get out of + // image capture + if (mController.isImageCaptureIntent()) { + if (!removeTopLevelPopup()) { + // no popup to dismiss, cancel image capture + mController.onCaptureCancelled(); + } + return true; + } else if (!mController.isCameraIdle()) { + // ignore backs while we're taking a picture + return true; + } else { + return removeTopLevelPopup(); + } + } + + public void onFullScreenChanged(boolean full) { + if (mFaceView != null) { + mFaceView.setBlockDraw(!full); + } + if (mPopup != null) { + dismissPopup(false, full); + } + if (mGestures != null) { + mGestures.setEnabled(full); + } + if (mRenderOverlay != null) { + // this can not happen in capture mode + mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE); + } + if (mPieRenderer != null) { + mPieRenderer.setBlockFocus(!full); + } + setShowMenu(full); + if (mBlocker != null) { + mBlocker.setVisibility(full ? View.VISIBLE : View.GONE); + } + if (!full && mCountDownView != null) mCountDownView.cancelCountDown(); + } + + public boolean removeTopLevelPopup() { + // Remove the top level popup or dialog box and return true if there's any + if (mPopup != null) { + dismissPopup(true); + return true; + } + return false; + } + + public void showPopup(AbstractSettingPopup popup) { + mActivity.hideUI(); + mBlocker.setVisibility(View.INVISIBLE); + setShowMenu(false); + mPopup = popup; + mPopup.setVisibility(View.VISIBLE); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER; + ((FrameLayout) mRootView).addView(mPopup, lp); + } + + public void dismissPopup(boolean topPopupOnly) { + dismissPopup(topPopupOnly, true); + } + + private void dismissPopup(boolean topOnly, boolean fullScreen) { + if (fullScreen) { + mActivity.showUI(); + mBlocker.setVisibility(View.VISIBLE); + } + setShowMenu(fullScreen); + if (mPopup != null) { + ((FrameLayout) mRootView).removeView(mPopup); + mPopup = null; + } + mMenu.popupDismissed(topOnly); + } + + public void onShowSwitcherPopup() { + if (mPieRenderer != null && mPieRenderer.showsItems()) { + mPieRenderer.hide(); + } + } + + private void setShowMenu(boolean show) { + if (mOnScreenIndicators != null) { + mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); + } + if (mMenuButton != null) { + mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); + } + } + + public boolean collapseCameraControls() { + // Remove all the popups/dialog boxes + boolean ret = false; + if (mPopup != null) { + dismissPopup(false); + ret = true; + } + return ret; + } + + protected void showPostCaptureAlert() { + mOnScreenIndicators.setVisibility(View.GONE); + mMenuButton.setVisibility(View.GONE); + Util.fadeIn(mReviewDoneButton); + mShutterButton.setVisibility(View.INVISIBLE); + Util.fadeIn(mReviewRetakeButton); + } + + protected void hidePostCaptureAlert() { + mOnScreenIndicators.setVisibility(View.VISIBLE); + mMenuButton.setVisibility(View.VISIBLE); + Util.fadeOut(mReviewDoneButton); + mShutterButton.setVisibility(View.VISIBLE); + Util.fadeOut(mReviewRetakeButton); + } + + public void setDisplayOrientation(int orientation) { + if (mFaceView != null) { + mFaceView.setDisplayOrientation(orientation); + } + } + + // shutter button handling + + public boolean isShutterPressed() { + return mShutterButton.isPressed(); + } + + // focus handling + + + private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { + @Override + public void onZoomValueChanged(int index) { + int newZoom = mController.onZoomChanged(index); + if (mZoomRenderer != null) { + mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); + } + } + + @Override + public void onZoomStart() { + if (mPieRenderer != null) { + mPieRenderer.setBlockFocus(true); + } + } + + @Override + public void onZoomEnd() { + if (mPieRenderer != null) { + mPieRenderer.setBlockFocus(false); + } + } + } + + @Override + public void onPieOpened(int centerX, int centerY) { + mActivity.cancelActivityTouchHandling(); + mActivity.setSwipingEnabled(false); + if (mFaceView != null) { + mFaceView.setBlockDraw(true); + } + } + + @Override + public void onPieClosed() { + mActivity.setSwipingEnabled(true); + if (mFaceView != null) { + mFaceView.setBlockDraw(false); + } + } + + // Surface Listener + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height=" + + height); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + Log.v(TAG, "surfaceCreated: " + holder); + mSurfaceHolder = holder; + mController.onSurfaceCreated(holder); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.v(TAG, "surfaceDestroyed: " + holder); + mSurfaceHolder = null; + mController.stopPreview(); + } + + public Object getSurfaceTexture() { + return mSurfaceTexture; + } + + public void setSurfaceTexture(Object st) { + mSurfaceTexture = st; + } + + public SurfaceHolder getSurfaceHolder() { + return mSurfaceHolder; + } + + public boolean isCountingDown() { + return mCountDownView.isCountingDown(); + } + + public void cancelCountDown() { + mCountDownView.cancelCountDown(); + } + + public void startCountDown(int sec, boolean playSound) { + mCountDownView.startCountDown(sec, playSound); + } + + public void showPreferencesToast() { + if (mNotSelectableToast == null) { + String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); + mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); + } + mNotSelectableToast.show(); + } + + public void onPause() { + mCountDownView.cancelCountDown(); + // Close the camera now because other activities may need to use it. + mSurfaceTexture = null; + + // Clear UI. + collapseCameraControls(); + if (mFaceView != null) mFaceView.clear(); + + + mRootView.removeOnLayoutChangeListener(mLayoutListener); + mPreviewWidth = 0; + mPreviewHeight = 0; + } + + public void enableShutter(boolean enabled) { + if (mShutterButton != null) { + mShutterButton.setEnabled(enabled); + } + } + + public void pressShutterButton() { + if (mShutterButton.isInTouchMode()) { + mShutterButton.requestFocusFromTouch(); + } else { + mShutterButton.requestFocus(); + } + mShutterButton.setPressed(true); + } + + // forward from preview gestures to controller + @Override + public void onSingleTapUp(View view, int x, int y) { + mController.onSingleTapUp(view, x, y); + } + + // focus UI implementation + + private FocusIndicator getFocusIndicator() { + return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer; + } + + @Override + public boolean hasFaces() { + return (mFaceView != null && mFaceView.faceExists()); + } + + public void clearFaces() { + if (mFaceView != null) mFaceView.clear(); + } + + @Override + public void clearFocus() { + getFocusIndicator().clear(); + } + + @Override + public void setFocusPosition(int x, int y) { + mPieRenderer.setFocus(x, y); + } + + @Override + public void onFocusStarted() { + getFocusIndicator().showStart(); + } + + @Override + public void onFocusSucceeded(boolean timeout) { + getFocusIndicator().showSuccess(timeout); + } + + @Override + public void onFocusFailed(boolean timeout) { + getFocusIndicator().showFail(timeout); + } + + @Override + public void pauseFaceDetection() { + if (mFaceView != null) mFaceView.pause(); + } + + @Override + public void resumeFaceDetection() { + if (mFaceView != null) mFaceView.resume(); + } + + public void onStartFaceDetection(int orientation, boolean mirror) { + mFaceView.clear(); + mFaceView.setVisibility(View.VISIBLE); + mFaceView.setDisplayOrientation(orientation); + mFaceView.setMirror(mirror); + mFaceView.resume(); + } + + @Override + public void onFaceDetection(Face[] faces, android.hardware.Camera camera) { + mFaceView.setFaces(faces); + } + +} diff --git a/src/com/android/camera/PreviewGestures.java b/src/com/android/camera/PreviewGestures.java index cb7ca09c7..f6b622827 100644 --- a/src/com/android/camera/PreviewGestures.java +++ b/src/com/android/camera/PreviewGestures.java @@ -46,7 +46,7 @@ public class PreviewGestures private static final int MODE_ALL = 4; private CameraActivity mActivity; - private CameraModule mModule; + private SingleTapListener mTapListener; private RenderOverlay mOverlay; private PieRenderer mPie; private ZoomRenderer mZoom; @@ -72,10 +72,14 @@ public class PreviewGestures } }; - public PreviewGestures(CameraActivity ctx, CameraModule module, + public interface SingleTapListener { + public void onSingleTapUp(View v, int x, int y); + } + + public PreviewGestures(CameraActivity ctx, SingleTapListener tapListener, ZoomRenderer zoom, PieRenderer pie) { mActivity = ctx; - mModule = module; + mTapListener = tapListener; mPie = pie; mZoom = zoom; mMode = MODE_ALL; @@ -199,7 +203,7 @@ public class PreviewGestures cancelActivityTouchHandling(m); // must have been tap if (m.getEventTime() - mDown.getEventTime() < mTapTimeout) { - mModule.onSingleTapUp(null, + mTapListener.onSingleTapUp(null, (int) mDown.getX() - mOverlay.getWindowPositionX(), (int) mDown.getY() - mOverlay.getWindowPositionY()); return true; diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java deleted file mode 100644 index 3a220773b..000000000 --- a/src/com/android/camera/VideoController.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import android.content.Context; -import android.view.LayoutInflater; - -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.ListPrefSettingPopup; -import com.android.camera.ui.MoreSettingPopup; -import com.android.camera.ui.PieItem; -import com.android.camera.ui.PieItem.OnClickListener; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.TimeIntervalPopup; -import com.android.gallery3d.R; - -public class VideoController extends PieController - implements MoreSettingPopup.Listener, - ListPrefSettingPopup.Listener, - TimeIntervalPopup.Listener { - - - private static String TAG = "CAM_videocontrol"; - private static float FLOAT_PI_DIVIDED_BY_TWO = (float) Math.PI / 2; - - private VideoModule mModule; - private String[] mOtherKeys; - private AbstractSettingPopup mPopup; - - private static final int POPUP_NONE = 0; - private static final int POPUP_FIRST_LEVEL = 1; - private static final int POPUP_SECOND_LEVEL = 2; - private int mPopupStatus; - - public VideoController(CameraActivity activity, VideoModule module, PieRenderer pie) { - super(activity, pie); - mModule = module; - } - - public void initialize(PreferenceGroup group) { - super.initialize(group); - mPopup = null; - mPopupStatus = POPUP_NONE; - float sweep = FLOAT_PI_DIVIDED_BY_TWO / 2; - - addItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); - addItem(CameraSettings.KEY_WHITE_BALANCE, 3 * FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); - PieItem item = makeItem(R.drawable.ic_switch_video_facing_holo_light); - item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); - item.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(PieItem item) { - // Find the index of next camera. - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - if (pref != null) { - int index = pref.findIndexOfValue(pref.getValue()); - CharSequence[] values = pref.getEntryValues(); - index = (index + 1) % values.length; - int newCameraId = Integer.parseInt((String) values[index]); - mListener.onCameraPickerClicked(newCameraId); - } - } - }); - mRenderer.addItem(item); - mOtherKeys = new String[] { - CameraSettings.KEY_VIDEO_EFFECT, - CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, - CameraSettings.KEY_VIDEO_QUALITY, - CameraSettings.KEY_RECORD_LOCATION}; - - item = makeItem(R.drawable.ic_settings_holo_light); - item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO * 3, sweep); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { - initializePopup(); - mPopupStatus = POPUP_FIRST_LEVEL; - } - mModule.showPopup(mPopup); - } - }); - mRenderer.addItem(item); - } - - protected void setCameraId(int cameraId) { - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - pref.setValue("" + cameraId); - } - - @Override - public void reloadPreferences() { - super.reloadPreferences(); - if (mPopup != null) { - mPopup.reloadPreference(); - } - } - - @Override - public void overrideSettings(final String ... keyvalues) { - super.overrideSettings(keyvalues); - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { - mPopupStatus = POPUP_FIRST_LEVEL; - initializePopup(); - } - ((MoreSettingPopup) mPopup).overrideSettings(keyvalues); - } - - @Override - // Hit when an item in the second-level popup gets selected - public void onListPrefChanged(ListPreference pref) { - if (mPopup != null) { - if (mPopupStatus == POPUP_SECOND_LEVEL) { - mModule.dismissPopup(true); - } - } - super.onSettingChanged(pref); - } - - protected void initializePopup() { - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( - R.layout.more_setting_popup, null, false); - popup.setSettingChangedListener(this); - popup.initialize(mPreferenceGroup, mOtherKeys); - if (mActivity.isSecureCamera()) { - // Prevent location preference from getting changed in secure camera mode - popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); - } - mPopup = popup; - } - - public void popupDismissed(boolean topPopupOnly) { - // if the 2nd level popup gets dismissed - if (mPopupStatus == POPUP_SECOND_LEVEL) { - initializePopup(); - mPopupStatus = POPUP_FIRST_LEVEL; - if (topPopupOnly) mModule.showPopup(mPopup); - } - } - - @Override - // Hit when an item in the first-level popup gets selected, then bring up - // the second-level popup - public void onPreferenceClicked(ListPreference pref) { - if (mPopupStatus != POPUP_FIRST_LEVEL) return; - - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - if (CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL.equals(pref.getKey())) { - TimeIntervalPopup timeInterval = (TimeIntervalPopup) inflater.inflate( - R.layout.time_interval_popup, null, false); - timeInterval.initialize((IconListPreference) pref); - timeInterval.setSettingChangedListener(this); - mModule.dismissPopup(true); - mPopup = timeInterval; - } else { - ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( - R.layout.list_pref_setting_popup, null, false); - basic.initialize(pref); - basic.setSettingChangedListener(this); - mModule.dismissPopup(true); - mPopup = basic; - } - mModule.showPopup(mPopup); - mPopupStatus = POPUP_SECOND_LEVEL; - } - -} diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java new file mode 100644 index 000000000..ab53e1546 --- /dev/null +++ b/src/com/android/camera/VideoMenu.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2012 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; + +import android.content.Context; +import android.view.LayoutInflater; + +import com.android.camera.ui.AbstractSettingPopup; +import com.android.camera.ui.ListPrefSettingPopup; +import com.android.camera.ui.MoreSettingPopup; +import com.android.camera.ui.PieItem; +import com.android.camera.ui.PieItem.OnClickListener; +import com.android.camera.ui.PieRenderer; +import com.android.camera.ui.TimeIntervalPopup; +import com.android.gallery3d.R; + +public class VideoMenu extends PieController + implements MoreSettingPopup.Listener, + ListPrefSettingPopup.Listener, + TimeIntervalPopup.Listener { + + + private static String TAG = "CAM_videocontrol"; + private static float FLOAT_PI_DIVIDED_BY_TWO = (float) Math.PI / 2; + + private VideoModule mModule; + private String[] mOtherKeys; + private AbstractSettingPopup mPopup; + + private static final int POPUP_NONE = 0; + private static final int POPUP_FIRST_LEVEL = 1; + private static final int POPUP_SECOND_LEVEL = 2; + private int mPopupStatus; + + public VideoMenu(CameraActivity activity, VideoModule module, PieRenderer pie) { + super(activity, pie); + mModule = module; + } + + public void initialize(PreferenceGroup group) { + super.initialize(group); + mPopup = null; + mPopupStatus = POPUP_NONE; + float sweep = FLOAT_PI_DIVIDED_BY_TWO / 2; + + addItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep); + addItem(CameraSettings.KEY_WHITE_BALANCE, 3 * FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); + PieItem item = makeItem(R.drawable.ic_switch_video_facing_holo_light); + item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep); + item.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(PieItem item) { + // Find the index of next camera. + ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); + if (pref != null) { + int index = pref.findIndexOfValue(pref.getValue()); + CharSequence[] values = pref.getEntryValues(); + index = (index + 1) % values.length; + int newCameraId = Integer.parseInt((String) values[index]); + mListener.onCameraPickerClicked(newCameraId); + } + } + }); + mRenderer.addItem(item); + mOtherKeys = new String[] { + CameraSettings.KEY_VIDEO_EFFECT, + CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, + CameraSettings.KEY_VIDEO_QUALITY, + CameraSettings.KEY_RECORD_LOCATION}; + + item = makeItem(R.drawable.ic_settings_holo_light); + item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO * 3, sweep); + item.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + } + mModule.showPopup(mPopup); + } + }); + mRenderer.addItem(item); + } + + protected void setCameraId(int cameraId) { + ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); + pref.setValue("" + cameraId); + } + + @Override + public void reloadPreferences() { + super.reloadPreferences(); + if (mPopup != null) { + mPopup.reloadPreference(); + } + } + + @Override + public void overrideSettings(final String ... keyvalues) { + super.overrideSettings(keyvalues); + if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { + mPopupStatus = POPUP_FIRST_LEVEL; + initializePopup(); + } + ((MoreSettingPopup) mPopup).overrideSettings(keyvalues); + } + + @Override + // Hit when an item in the second-level popup gets selected + public void onListPrefChanged(ListPreference pref) { + if (mPopup != null) { + if (mPopupStatus == POPUP_SECOND_LEVEL) { + mModule.dismissPopup(true); + } + } + super.onSettingChanged(pref); + } + + protected void initializePopup() { + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + + MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup.setSettingChangedListener(this); + popup.initialize(mPreferenceGroup, mOtherKeys); + if (mActivity.isSecureCamera()) { + // Prevent location preference from getting changed in secure camera mode + popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); + } + mPopup = popup; + } + + public void popupDismissed(boolean topPopupOnly) { + // if the 2nd level popup gets dismissed + if (mPopupStatus == POPUP_SECOND_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + if (topPopupOnly) mModule.showPopup(mPopup); + } + } + + @Override + // Hit when an item in the first-level popup gets selected, then bring up + // the second-level popup + public void onPreferenceClicked(ListPreference pref) { + if (mPopupStatus != POPUP_FIRST_LEVEL) return; + + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + + if (CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL.equals(pref.getKey())) { + TimeIntervalPopup timeInterval = (TimeIntervalPopup) inflater.inflate( + R.layout.time_interval_popup, null, false); + timeInterval.initialize((IconListPreference) pref); + timeInterval.setSettingChangedListener(this); + mModule.dismissPopup(true); + mPopup = timeInterval; + } else { + ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( + R.layout.list_pref_setting_popup, null, false); + basic.initialize(pref); + basic.setSettingChangedListener(this); + mModule.dismissPopup(true); + mPopup = basic; + } + mModule.showPopup(mPopup); + mPopupStatus = POPUP_SECOND_LEVEL; + } + +} diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 7bda657a2..9ba5bec47 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -91,7 +91,8 @@ public class VideoModule implements CameraModule, MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener, EffectsRecorder.EffectsListener, - PieRenderer.PieListener { + PieRenderer.PieListener, + PreviewGestures.SingleTapListener { private static final String TAG = "CAM_VideoModule"; @@ -213,7 +214,7 @@ public class VideoModule implements CameraModule, private RenderOverlay mRenderOverlay; private PieRenderer mPieRenderer; - private VideoController mVideoControl; + private VideoMenu mVideoControl; private AbstractSettingPopup mPopup; private int mPendingSwitchCameraId; @@ -393,7 +394,7 @@ public class VideoModule implements CameraModule, mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); if (mPieRenderer == null) { mPieRenderer = new PieRenderer(mActivity); - mVideoControl = new VideoController(mActivity, this, mPieRenderer); + mVideoControl = new VideoMenu(mActivity, this, mPieRenderer); mVideoControl.setListener(this); mPieRenderer.setPieListener(this); } @@ -511,7 +512,6 @@ public class VideoModule implements CameraModule, settings.getPreferenceGroup(R.xml.video_preferences)); } - @Override public boolean collapseCameraControls() { boolean ret = false; if (mPopup != null) { -- cgit v1.2.3