diff options
Diffstat (limited to 'src/com')
39 files changed, 3874 insertions, 372 deletions
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java index e26b6a90e..f833cb279 100644 --- a/src/com/android/camera/AndroidCameraManagerImpl.java +++ b/src/com/android/camera/AndroidCameraManagerImpl.java @@ -39,6 +39,9 @@ import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.SurfaceHolder; +import android.hardware.Camera.CameraDataCallback; +import com.android.camera.util.ApiHelper; +import android.os.ConditionVariable; /** * A class to implement {@link CameraManager} of the Android camera framework. @@ -47,6 +50,9 @@ class AndroidCameraManagerImpl implements CameraManager { private static final String TAG = "CAM_" + AndroidCameraManagerImpl.class.getSimpleName(); + // Thread progress signals + private ConditionVariable mSig = new ConditionVariable(); + private Parameters mParameters; private boolean mParametersIsDirty; private IOException mReconnectIOException; @@ -83,6 +89,11 @@ class AndroidCameraManagerImpl implements CameraManager { // Presentation private static final int ENABLE_SHUTTER_SOUND = 501; private static final int SET_DISPLAY_ORIENTATION = 502; + // Histogram + private static final int SET_HISTOGRAM_MODE = 601; + private static final int SEND_HISTOGRAM_DATA = 602; + //LONGSHOT + private static final int SET_LONGSHOT = 701; private CameraHandler mCameraHandler; private android.hardware.Camera mCamera; @@ -205,6 +216,9 @@ class AndroidCameraManagerImpl implements CameraManager { return; case RELEASE: + if (mCamera == null) { + return; + } mCamera.release(); mCamera = null; return; @@ -294,9 +308,9 @@ class AndroidCameraManagerImpl implements CameraManager { case SET_PARAMETERS: mParametersIsDirty = true; - mParamsToSet.unflatten((String) msg.obj); - mCamera.setParameters(mParamsToSet); - return; + mCamera.setParameters((Parameters) msg.obj); + mSig.open(); + break; case GET_PARAMETERS: if (mParametersIsDirty) { @@ -317,6 +331,18 @@ class AndroidCameraManagerImpl implements CameraManager { mParametersIsDirty = true; return; + case SET_HISTOGRAM_MODE: + mCamera.setHistogramMode((CameraDataCallback) msg.obj); + break; + + case SEND_HISTOGRAM_DATA: + mCamera.sendHistogramData(); + break; + + case SET_LONGSHOT: + mCamera.setLongshot((Boolean) msg.obj); + break; + default: throw new RuntimeException("Invalid CameraProxy message=" + msg.what); } @@ -525,8 +551,10 @@ class AndroidCameraManagerImpl implements CameraManager { Log.v(TAG, "null parameters in setParameters()"); return; } - mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten()) + mSig.close(); + mCameraHandler.obtainMessage(SET_PARAMETERS, params) .sendToTarget(); + mSig.block(); } @Override @@ -546,6 +574,21 @@ class AndroidCameraManagerImpl implements CameraManager { mCameraHandler.obtainMessage( ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); } + + @Override + public void setLongshot(boolean enable) { + mCameraHandler.obtainMessage(SET_LONGSHOT, + new Boolean(enable)).sendToTarget(); + } + + @Override + public void setHistogramMode(CameraDataCallback cb) { + mCameraHandler.obtainMessage(SET_HISTOGRAM_MODE, cb).sendToTarget(); + } + @Override + public void sendHistogramData() { + mCameraHandler.sendEmptyMessage(SEND_HISTOGRAM_DATA); + } } /** diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 8f2b04b4f..5ade3950a 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -175,6 +175,7 @@ public class CameraActivity extends Activity private Menu mActionBarMenu; private ViewGroup mUndoDeletionBar; private boolean mIsUndoingDeletion = false; + private boolean mIsEditActivityInProgress = false; private Uri[] mNfcPushUris = new Uri[1]; @@ -335,6 +336,9 @@ public class CameraActivity extends Activity @Override public void onDataFullScreenChange(int dataID, boolean full) { boolean isCameraID = isCameraPreview(dataID); + if (full && isCameraID && CameraActivity.this.hasWindowFocus()){ + updateStorageSpaceAndHint(); + } if (!isCameraID) { if (!full) { // Always show action bar in filmstrip mode @@ -397,6 +401,16 @@ public class CameraActivity extends Activity @Override public void onDataFocusChanged(final int dataID, final boolean focused) { + boolean isPreview = isCameraPreview(dataID); + boolean isFullScreen = mFilmStripView.inFullScreen(); + if (isFullScreen && isPreview && CameraActivity.this.hasWindowFocus()){ + runOnUiThread(new Runnable() { + @Override + public void run() { + updateStorageSpaceAndHint(); + } + }); + } // Delay hiding action bar if there is any user interaction if (mMainHandler.hasMessages(HIDE_ACTION_BAR)) { mMainHandler.removeMessages(HIDE_ACTION_BAR); @@ -1216,6 +1230,7 @@ public class CameraActivity extends Activity protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQ_CODE_DONT_SWITCH_TO_PREVIEW) { mResetToPreviewOnResume = false; + mIsEditActivityInProgress = false; } else { super.onActivityResult(requestCode, resultCode, data); } @@ -1263,6 +1278,14 @@ public class CameraActivity extends Activity } mLocalImagesObserver.setActivityPaused(false); mLocalVideosObserver.setActivityPaused(false); + + //This is a temporal solution to share LED resource + //as Android doesn’t have any default intent to share the state. + // if the led flash light is open, turn it off + Log.d(TAG, "send the turn off LED Flashlight the broadcast"); + Intent intent = new Intent("qualcomm.android.LEDFlashlight.appWidgetUpdate"); + intent.putExtra("camera_led", true); + sendBroadcast(intent); } @Override @@ -1305,9 +1328,7 @@ public class CameraActivity extends Activity // Prevent software keyboard or voice search from showing up. if (keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_MENU) { - if (event.isLongPress()) { - return true; - } + return true; } } @@ -1326,6 +1347,7 @@ public class CameraActivity extends Activity public void onBackPressed() { if (!mFilmStripView.inCameraFullscreen()) { mFilmStripView.getController().goToFirstItem(); + mCurrentModule.resizeForPreviewAspectRatio(); } else if (!mCurrentModule.onBackPressed()) { super.onBackPressed(); } @@ -1457,14 +1479,17 @@ public class CameraActivity extends Activity * Launches an ACTION_EDIT intent for the given local data item. */ public void launchEditor(LocalData data) { - Intent intent = new Intent(Intent.ACTION_EDIT) - .setDataAndType(data.getContentUri(), data.getMimeType()) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - try { - startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW); - } catch (ActivityNotFoundException e) { - startActivityForResult(Intent.createChooser(intent, null), - REQ_CODE_DONT_SWITCH_TO_PREVIEW); + if (!mIsEditActivityInProgress) { + Intent intent = new Intent(Intent.ACTION_EDIT) + .setDataAndType(data.getContentUri(), data.getMimeType()) + .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + try { + startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW); + } catch (ActivityNotFoundException e) { + startActivityForResult(Intent.createChooser(intent, null), + REQ_CODE_DONT_SWITCH_TO_PREVIEW); + } + mIsEditActivityInProgress = true; } } @@ -1494,6 +1519,7 @@ public class CameraActivity extends Activity module.onPauseBeforeSuper(); module.onPauseAfterSuper(); ((ViewGroup) mCameraModuleRootView).removeAllViews(); + ((ViewGroup) mCameraModuleRootView).clearDisappearingChildren(); } private void performDeletion() { diff --git a/src/com/android/camera/CameraErrorCallback.java b/src/com/android/camera/CameraErrorCallback.java index 22f800ef9..7029ac427 100644 --- a/src/com/android/camera/CameraErrorCallback.java +++ b/src/com/android/camera/CameraErrorCallback.java @@ -25,7 +25,8 @@ public class CameraErrorCallback @Override public void onError(int error, android.hardware.Camera camera) { Log.e(TAG, "Got camera error callback. error=" + error); - if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { + if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED + || error == android.hardware.Camera.CAMERA_ERROR_UNKNOWN) { // We are not sure about the current state of the app (in preview or // snapshot or recording). Closing the app is better than creating a // new Camera object. diff --git a/src/com/android/camera/CameraHolder.java b/src/com/android/camera/CameraHolder.java index e3f2c11e7..0797fad44 100644 --- a/src/com/android/camera/CameraHolder.java +++ b/src/com/android/camera/CameraHolder.java @@ -222,7 +222,7 @@ public class CameraHolder { return null; } mCameraId = cameraId; - mParameters = mCameraDevice.getParameters(); + mParameters = mCameraDevice.getCamera().getParameters(); } else { if (!mCameraDevice.reconnect(handler, cb)) { Log.e(TAG, "fail to reconnect Camera:" + mCameraId + ", aborting."); diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java index 909e1ca75..8ad0d52d6 100644 --- a/src/com/android/camera/CameraManager.java +++ b/src/com/android/camera/CameraManager.java @@ -25,6 +25,7 @@ import android.hardware.Camera.Parameters; import android.os.Build; import android.os.Handler; import android.view.SurfaceHolder; +import android.hardware.Camera.CameraDataCallback; /** * An interface which provides possible camera device operations. @@ -349,5 +350,23 @@ public interface CameraManager { * {@code false} to disable it. */ public void enableShutterSound(boolean enable); + /** + * Set histogram Mode + * + * @param cb cameraDataCallback to use + */ + public void setHistogramMode(CameraDataCallback cb); + /** + * Send the Histogram Data. + * + */ + public void sendHistogramData(); + /** + * Enables/Disables longshot mode. + * + * @param enable {@code true} to enable longshot mode, + * {@code false} to disable it. + */ + public void setLongshot(boolean enable); } } diff --git a/src/com/android/camera/CameraModule.java b/src/com/android/camera/CameraModule.java index 55cae9f0c..48d7eec4a 100644 --- a/src/com/android/camera/CameraModule.java +++ b/src/com/android/camera/CameraModule.java @@ -66,4 +66,6 @@ public interface CameraModule { public void onMediaSaveServiceConnected(MediaSaveService s); public boolean arePreviewControlsVisible(); + + public void resizeForPreviewAspectRatio(); } diff --git a/src/com/android/camera/CameraPreference.java b/src/com/android/camera/CameraPreference.java index 407c1408c..f2a78e9cc 100644 --- a/src/com/android/camera/CameraPreference.java +++ b/src/com/android/camera/CameraPreference.java @@ -34,6 +34,7 @@ public abstract class CameraPreference { private final Context mContext; static public interface OnPreferenceChangedListener { + public void onSharedPreferenceChanged(ListPreference pref); public void onSharedPreferenceChanged(); public void onRestorePreferencesClicked(); public void onOverriddenPreferencesClicked(); diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java index 55867a1e8..c70ee9909 100644 --- a/src/com/android/camera/CameraSettings.java +++ b/src/com/android/camera/CameraSettings.java @@ -16,12 +16,14 @@ package com.android.camera; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Resources; import android.content.res.TypedArray; +import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; @@ -36,6 +38,8 @@ import com.android.camera2.R; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import android.os.Build; +import java.util.StringTokenizer; /** * Provides utilities and keys for Camera settings. @@ -61,17 +65,95 @@ public class CameraSettings { public static final String KEY_VIDEO_EFFECT = "pref_video_effect_key"; public static final String KEY_CAMERA_ID = "pref_camera_id_key"; public static final String KEY_CAMERA_HDR = "pref_camera_hdr_key"; + public static final String KEY_CAMERA_HQ = "pref_camera_hq_key"; public static final String KEY_CAMERA_HDR_PLUS = "pref_camera_hdr_plus_key"; public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN = "pref_camera_first_use_hint_shown_key"; public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN = "pref_video_first_use_hint_shown_key"; public static final String KEY_PHOTOSPHERE_PICTURESIZE = "pref_photosphere_picturesize_key"; public static final String KEY_STARTUP_MODULE_INDEX = "camera.startup_module"; + public static final String KEY_VIDEO_ENCODER = "pref_camera_videoencoder_key"; + public static final String KEY_AUDIO_ENCODER = "pref_camera_audioencoder_key"; + public static final String KEY_VIDEO_DURATION = "pref_camera_video_duration_key"; + public static final String KEY_POWER_MODE = "pref_camera_powermode_key"; + public static final String KEY_PICTURE_FORMAT = "pref_camera_pictureformat_key"; + public static final String KEY_ZSL = "pref_camera_zsl_key"; + public static final String KEY_CAMERA_SAVEPATH = "pref_camera_savepath_key"; + public static final String KEY_COLOR_EFFECT = "pref_camera_coloreffect_key"; + public static final String KEY_FACE_DETECTION = "pref_camera_facedetection_key"; + public static final String KEY_TOUCH_AF_AEC = "pref_camera_touchafaec_key"; + public static final String KEY_SELECTABLE_ZONE_AF = "pref_camera_selectablezoneaf_key"; + public static final String KEY_SATURATION = "pref_camera_saturation_key"; + public static final String KEY_CONTRAST = "pref_camera_contrast_key"; + public static final String KEY_SHARPNESS = "pref_camera_sharpness_key"; + public static final String KEY_AUTOEXPOSURE = "pref_camera_autoexposure_key"; + public static final String KEY_ANTIBANDING = "pref_camera_antibanding_key"; + public static final String KEY_ISO = "pref_camera_iso_key"; + public static final String KEY_LENSSHADING = "pref_camera_lensshading_key"; + public static final String KEY_HISTOGRAM = "pref_camera_histogram_key"; + public static final String KEY_DENOISE = "pref_camera_denoise_key"; + public static final String KEY_REDEYE_REDUCTION = "pref_camera_redeyereduction_key"; + public static final String KEY_AE_BRACKET_HDR = "pref_camera_ae_bracket_hdr_key"; + public static final String KEY_ADVANCED_FEATURES = "pref_camera_advanced_features_key"; + + public static final String KEY_VIDEO_SNAPSHOT_SIZE = "pref_camera_videosnapsize_key"; + public static final String KEY_VIDEO_HIGH_FRAME_RATE = "pref_camera_hfr_key"; + public static final String KEY_VIDEO_HDR = "pref_camera_video_hdr_key"; + public static final String DEFAULT_VIDEO_QUALITY_VALUE = "custom"; + public static final String KEY_SKIN_TONE_ENHANCEMENT = "pref_camera_skinToneEnhancement_key"; + public static final String KEY_SKIN_TONE_ENHANCEMENT_FACTOR = "pref_camera_skinToneEnhancement_factor_key"; + + public static final String KEY_FACE_RECOGNITION = "pref_camera_facerc_key"; + public static final String KEY_DIS = "pref_camera_dis_key"; + + public static final String KEY_LONGSHOT = "pref_camera_longshot_key"; + + private static final String KEY_QC_SUPPORTED_AE_BRACKETING_MODES = "ae-bracket-hdr-values"; + private static final String KEY_QC_SUPPORTED_AF_BRACKETING_MODES = "af-bracket-values"; + private static final String KEY_QC_SUPPORTED_CF_MODES = "chroma-flash-values"; + private static final String KEY_QC_SUPPORTED_OZ_MODES = "opti-zoom-values"; + private static final String KEY_QC_SUPPORTED_FACE_RECOGNITION_MODES = "face-recognition-values"; + private static final String KEY_QC_SUPPORTED_DIS_MODES = "dis-values"; + public static final String KEY_QC_AE_BRACKETING = "ae-bracket-hdr"; + public static final String KEY_QC_AF_BRACKETING = "af-bracket"; + public static final String KEY_QC_CHROMA_FLASH = "chroma-flash"; + public static final String KEY_QC_OPTI_ZOOM = "opti-zoom"; + public static final String KEY_QC_FACE_RECOGNITION = "face-recognition"; + public static final String KEY_QC_DIS_MODE = "dis"; + + public static final String KEY_INTERNAL_PREVIEW_RESTART = "internal-restart"; + public static final String KEY_QC_ZSL_HDR_SUPPORTED = "zsl-hdr-supported"; + public static final String KEY_QC_LONGSHOT_SUPPORTED = "longshot-supported"; + private static final String TRUE = "true"; + private static final String FALSE = "false"; + + //for flip + public static final String KEY_QC_PREVIEW_FLIP = "preview-flip"; + public static final String KEY_QC_VIDEO_FLIP = "video-flip"; + public static final String KEY_QC_SNAPSHOT_PICTURE_FLIP = "snapshot-picture-flip"; + public static final String KEY_QC_SUPPORTED_FLIP_MODES = "flip-mode-values"; + + public static final String FLIP_MODE_OFF = "off"; + public static final String FLIP_MODE_V = "flip-v"; + public static final String FLIP_MODE_H = "flip-h"; + public static final String FLIP_MODE_VH = "flip-vh"; + + private static final String KEY_QC_PICTURE_FORMAT = "picture-format-values"; + private static final String VIDEO_QUALITY_HIGH = "high"; + private static final String VIDEO_QUALITY_MMS = "mms"; + private static final String VIDEO_QUALITY_YOUTUBE = "youtube"; + + public static final String EXPOSURE_DEFAULT_VALUE = "0"; public static final int CURRENT_VERSION = 5; public static final int CURRENT_LOCAL_VERSION = 2; + public static final int DEFAULT_VIDEO_DURATION = 0; // no limit + private static final int MMS_VIDEO_DURATION = (CamcorderProfile.get(CamcorderProfile.QUALITY_LOW) != null) ? + CamcorderProfile.get(CamcorderProfile.QUALITY_LOW).duration :30; + private static final int YOUTUBE_VIDEO_DURATION = 15 * 60; // 15 mins + private static final String TAG = "CameraSettings"; private final Context mContext; @@ -96,10 +178,10 @@ public class CameraSettings { } public static String getSupportedHighestVideoQuality(int cameraId, - String defaultQuality) { + String defaultQuality,Parameters parameters) { // When launching the camera app first time, we will set the video quality // to the first one (i.e. highest quality) in the supported list - List<String> supported = getSupportedVideoQuality(cameraId); + List<String> supported = getSupportedVideoQuality(cameraId,parameters); if (supported == null) { Log.e(TAG, "No supported video quality is found"); return defaultQuality; @@ -156,6 +238,210 @@ public class CameraSettings { return duration; } + public static List<String> getSupportedFaceRecognitionModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_FACE_RECOGNITION_MODES); + if (str == null) { + return null; + } + return split(str); + } + + public static List<String> getSupportedDISModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_DIS_MODES); + if (str == null) { + return null; + } + return split(str); + } + + public static List<String> getSupportedAEBracketingModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_AE_BRACKETING_MODES); + if (str == null) { + return null; + } + return split(str); + } + + public List<String> getSupportedAdvancedFeatures(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_AF_BRACKETING_MODES); + str += ',' + params.get(KEY_QC_SUPPORTED_CF_MODES); + str += ',' + params.get(KEY_QC_SUPPORTED_OZ_MODES); + str += ',' + mContext.getString(R.string.pref_camera_advanced_feature_default); + return split(str); + } + + public static List<String> getSupportedAFBracketingModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_AF_BRACKETING_MODES); + if (str == null) { + return null; + } + return split(str); + } + + public static List<String> getSupportedChromaFlashModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_CF_MODES); + if (str == null) { + return null; + } + return split(str); + } + + public static List<String> getSupportedOptiZoomModes(Parameters params) { + String str = params.get(KEY_QC_SUPPORTED_OZ_MODES); + if (str == null) { + return null; + } + return split(str); + } + + + // Splits a comma delimited string to an ArrayList of String. + // Return null if the passing string is null or the size is 0. + private static ArrayList<String> split(String str) { + if (str == null) return null; + + // Use StringTokenizer because it is faster than split. + StringTokenizer tokenizer = new StringTokenizer(str, ","); + ArrayList<String> substrings = new ArrayList<String>(); + while (tokenizer.hasMoreElements()) { + substrings.add(tokenizer.nextToken()); + } + return substrings; + } + private List<String> getSupportedPictureFormatLists() { + String str = mParameters.get(KEY_QC_PICTURE_FORMAT); + if (str == null) { + str = "jpeg,raw"; // if not set, fall back to default behavior + } + return split(str); + } + + public static List<String> getSupportedFlipMode(Parameters params){ + String str = params.get(KEY_QC_SUPPORTED_FLIP_MODES); + if(str == null) + return null; + + return split(str); + } + + private void qcomInitPreferences(PreferenceGroup group){ + //Qcom Preference add here + ListPreference powerMode = group.findPreference(KEY_POWER_MODE); + ListPreference zsl = group.findPreference(KEY_ZSL); + ListPreference colorEffect = group.findPreference(KEY_COLOR_EFFECT); + ListPreference faceDetection = group.findPreference(KEY_FACE_DETECTION); + ListPreference touchAfAec = group.findPreference(KEY_TOUCH_AF_AEC); + ListPreference selectableZoneAf = group.findPreference(KEY_SELECTABLE_ZONE_AF); + ListPreference saturation = group.findPreference(KEY_SATURATION); + ListPreference contrast = group.findPreference(KEY_CONTRAST); + ListPreference sharpness = group.findPreference(KEY_SHARPNESS); + ListPreference autoExposure = group.findPreference(KEY_AUTOEXPOSURE); + ListPreference antiBanding = group.findPreference(KEY_ANTIBANDING); + ListPreference mIso = group.findPreference(KEY_ISO); + ListPreference lensShade = group.findPreference(KEY_LENSSHADING); + ListPreference histogram = group.findPreference(KEY_HISTOGRAM); + ListPreference denoise = group.findPreference(KEY_DENOISE); + ListPreference redeyeReduction = group.findPreference(KEY_REDEYE_REDUCTION); + ListPreference aeBracketing = group.findPreference(KEY_AE_BRACKET_HDR); + ListPreference advancedFeatures = group.findPreference(KEY_ADVANCED_FEATURES); + ListPreference faceRC = group.findPreference(KEY_FACE_RECOGNITION); + ListPreference jpegQuality = group.findPreference(KEY_JPEG_QUALITY); + ListPreference videoSnapSize = group.findPreference(KEY_VIDEO_SNAPSHOT_SIZE); + ListPreference videoHdr = group.findPreference(KEY_VIDEO_HDR); + ListPreference pictureFormat = group.findPreference(KEY_PICTURE_FORMAT); + ListPreference hfr = group.findPreference(KEY_VIDEO_HIGH_FRAME_RATE); + ListPreference longShot = group.findPreference(KEY_LONGSHOT); + + if (touchAfAec != null) { + filterUnsupportedOptions(group, + touchAfAec, mParameters.getSupportedTouchAfAec()); + } + + if (!mParameters.isPowerModeSupported() && powerMode != null) { + removePreference(group, powerMode.getKey()); + } + + if (selectableZoneAf != null) { + filterUnsupportedOptions(group, + selectableZoneAf, mParameters.getSupportedSelectableZoneAf()); + } + + if (mIso != null) { + filterUnsupportedOptions(group, + mIso, mParameters.getSupportedIsoValues()); + } + + if (redeyeReduction != null) { + filterUnsupportedOptions(group, + redeyeReduction, mParameters.getSupportedRedeyeReductionModes()); + } + + if (denoise != null) { + filterUnsupportedOptions(group, + denoise, mParameters.getSupportedDenoiseModes()); + } + + if (videoHdr != null) { + filterUnsupportedOptions(group, + videoHdr, mParameters.getSupportedVideoHDRModes()); + } + + if (colorEffect != null) { + filterUnsupportedOptions(group, + colorEffect, mParameters.getSupportedColorEffects()); + } + + if (aeBracketing != null) { + filterUnsupportedOptions(group, + aeBracketing, getSupportedAEBracketingModes(mParameters)); + } + + if (antiBanding != null) { + filterUnsupportedOptions(group, + antiBanding, mParameters.getSupportedAntibanding()); + } + + if (faceRC != null) { + filterUnsupportedOptions(group, + faceRC, getSupportedFaceRecognitionModes(mParameters)); + } + + if (autoExposure != null) { + filterUnsupportedOptions(group, + autoExposure, mParameters.getSupportedAutoexposure()); + } + + if (!mParameters.isPowerModeSupported()){ + filterUnsupportedOptions(group, + videoSnapSize, null); + } else { + filterUnsupportedOptions(group, videoSnapSize, sizeListToStringList( + mParameters.getSupportedPictureSizes())); + } + + if (histogram!= null) { + filterUnsupportedOptions(group, + histogram, mParameters.getSupportedHistogramModes()); + } + + if (pictureFormat!= null) { + filterUnsupportedOptions(group, + pictureFormat, getSupportedPictureFormatLists()); + } + + if (hfr != null) { + filterUnsupportedOptions(group, + hfr, mParameters.getSupportedVideoHighFrameRateModes()); + } + + if(advancedFeatures != null) { + filterUnsupportedOptions(group, + advancedFeatures, getSupportedAdvancedFeatures(mParameters)); + } + if (longShot!= null && !isLongshotSupported(mParameters)) { + removePreference(group, longShot.getKey()); + } + } private void initPreference(PreferenceGroup group) { ListPreference videoQuality = group.findPreference(KEY_VIDEO_QUALITY); ListPreference timeLapseInterval = group.findPreference(KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL); @@ -172,12 +458,21 @@ public class CameraSettings { group.findPreference(KEY_VIDEOCAMERA_FLASH_MODE); ListPreference videoEffect = group.findPreference(KEY_VIDEO_EFFECT); ListPreference cameraHdr = group.findPreference(KEY_CAMERA_HDR); + ListPreference disMode = group.findPreference(KEY_DIS); ListPreference cameraHdrPlus = group.findPreference(KEY_CAMERA_HDR_PLUS); + ListPreference videoHfrMode = + group.findPreference(KEY_VIDEO_HIGH_FRAME_RATE); // Since the screen could be loaded from different resources, we need // to check if the preference is available here + if ((videoHfrMode != null) && + (mParameters.getSupportedHfrSizes() == null)) { + filterUnsupportedOptions(group, videoHfrMode, null); + } + if (videoQuality != null) { - filterUnsupportedOptions(group, videoQuality, getSupportedVideoQuality(mCameraId)); + filterUnsupportedOptions(group, videoQuality, getSupportedVideoQuality( + mCameraId,mParameters)); } if (pictureSize != null) { @@ -197,13 +492,14 @@ public class CameraSettings { filterUnsupportedOptions(group, flashMode, mParameters.getSupportedFlashModes()); } + if (disMode != null) { + filterUnsupportedOptions(group, + disMode, getSupportedDISModes(mParameters)); + } if (focusMode != null) { if (!CameraUtil.isFocusAreaSupported(mParameters)) { filterUnsupportedOptions(group, focusMode, mParameters.getSupportedFocusModes()); - } else { - // Remove the focus mode if we can use tap-to-focus. - removePreference(group, focusMode.getKey()); } } if (videoFlashMode != null) { @@ -223,13 +519,13 @@ public class CameraSettings { || !CameraUtil.isCameraHdrSupported(mParameters))) { removePreference(group, cameraHdr.getKey()); } - int frontCameraId = CameraHolder.instance().getFrontCameraId(); boolean isFrontCamera = (frontCameraId == mCameraId); if (cameraHdrPlus != null && (!ApiHelper.HAS_CAMERA_HDR_PLUS || !GcamHelper.hasGcamCapture() || isFrontCamera)) { removePreference(group, cameraHdrPlus.getKey()); } + qcomInitPreferences(group); } private void buildExposureCompensation( @@ -424,12 +720,15 @@ public class CameraSettings { int n = CameraHolder.instance().getNumberOfCameras(); if (cameraId < 0 || cameraId >= n) { - writePreferredCameraId(pref, 0); + cameraId = 0; } + writePreferredCameraId(pref, cameraId); } public static int readPreferredCameraId(SharedPreferences pref) { - return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0")); + String rearCameraId = Integer.toString( + CameraHolder.instance().getBackCameraId()); + return Integer.parseInt(pref.getString(KEY_CAMERA_ID, rearCameraId)); } public static void writePreferredCameraId(SharedPreferences pref, @@ -484,19 +783,147 @@ public class CameraSettings { initialCameraPictureSize(context, parameters); writePreferredCameraId(preferences, currentCameraId); } + private static boolean checkSupportedVideoQuality(Parameters parameters,int width, int height){ + List <Size> supported = parameters.getSupportedVideoSizes(); + int flag = 0; + for (Size size : supported){ + //since we are having two profiles with same height, we are checking with height + if (size.height == 480) { + if (size.height == height && size.width == width) { + flag = 1; + break; + } + } else { + if (size.width == width) { + flag = 1; + break; + } + } + } + if (flag == 1) + return true; - private static ArrayList<String> getSupportedVideoQuality(int cameraId) { + return false; + } + private static ArrayList<String> getSupportedVideoQuality(int cameraId,Parameters parameters) { ArrayList<String> supported = new ArrayList<String>(); // Check for supported quality + if (ApiHelper.HAS_FINE_RESOLUTION_QUALITY_LEVELS) { + getFineResolutionQuality(supported,cameraId,parameters); + } else { + supported.add(Integer.toString(CamcorderProfile.QUALITY_HIGH)); + CamcorderProfile high = CamcorderProfile.get( + cameraId, CamcorderProfile.QUALITY_HIGH); + CamcorderProfile low = CamcorderProfile.get( + cameraId, CamcorderProfile.QUALITY_LOW); + if (high.videoFrameHeight * high.videoFrameWidth > + low.videoFrameHeight * low.videoFrameWidth) { + supported.add(Integer.toString(CamcorderProfile.QUALITY_LOW)); + } + } + + return supported; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + private static void getFineResolutionQuality(ArrayList<String> supported, + int cameraId,Parameters parameters) { + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_4kDCI)) { + if (checkSupportedVideoQuality(parameters,4096,2160)) { + supported.add(Integer.toString(CamcorderProfile.QUALITY_4kDCI)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_4kUHD)) { + if (checkSupportedVideoQuality(parameters,3840,2160)) { + supported.add(Integer.toString(CamcorderProfile.QUALITY_4kUHD)); + } + } if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) { - supported.add(Integer.toString(CamcorderProfile.QUALITY_1080P)); + if (checkSupportedVideoQuality(parameters,1920,1080)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_1080P)); + } } if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) { - supported.add(Integer.toString(CamcorderProfile.QUALITY_720P)); + if (checkSupportedVideoQuality(parameters,1280,720)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_720P)); + } } if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) { - supported.add(Integer.toString(CamcorderProfile.QUALITY_480P)); + if (checkSupportedVideoQuality(parameters,720,480)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_480P)); + } } - return supported; + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_FWVGA)) { + if (checkSupportedVideoQuality(parameters,864,480)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_FWVGA)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_WVGA)) { + if (checkSupportedVideoQuality(parameters,800,480)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_WVGA)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_VGA)) { + if (checkSupportedVideoQuality(parameters,640,480)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_VGA)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_CIF)) { + if (checkSupportedVideoQuality(parameters,352,288)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_CIF)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) { + if (checkSupportedVideoQuality(parameters,320,240)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_QVGA)); + } + } + if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QCIF)) { + if (checkSupportedVideoQuality(parameters,176,144)){ + supported.add(Integer.toString(CamcorderProfile.QUALITY_QCIF)); + } + } + + } + public static int getVideoDurationInMillis(String quality) { + if (VIDEO_QUALITY_MMS.equals(quality)) { + return MMS_VIDEO_DURATION * 1000; + } else if (VIDEO_QUALITY_YOUTUBE.equals(quality)) { + return YOUTUBE_VIDEO_DURATION * 1000; + } + return DEFAULT_VIDEO_DURATION * 1000; + } + + public static boolean isInternalPreviewSupported(Parameters params) { + boolean ret = false; + if (null != params) { + String val = params.get(KEY_INTERNAL_PREVIEW_RESTART); + if ((null != val) && (TRUE.equals(val))) { + ret = true; + } + } + return ret; + } + + public static boolean isLongshotSupported(Parameters params) { + boolean ret = false; + if (null != params) { + String val = params.get(KEY_QC_LONGSHOT_SUPPORTED); + if ((null != val) && (TRUE.equals(val))) { + ret = true; + } + } + return ret; + } + + public static boolean isZSLHDRSupported(Parameters params) { + boolean ret = false; + if (null != params) { + String val = params.get(KEY_QC_ZSL_HDR_SUPPORTED); + if ((null != val) && (TRUE.equals(val))) { + ret = true; + } + } + return ret; } } diff --git a/src/com/android/camera/ComboPreferences.java b/src/com/android/camera/ComboPreferences.java index 42cf62423..d0039ab9e 100644 --- a/src/com/android/camera/ComboPreferences.java +++ b/src/com/android/camera/ComboPreferences.java @@ -105,6 +105,7 @@ public class ComboPreferences implements movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, src); movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, src); movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_EFFECT, src); + movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_SAVEPATH, src); } public static String[] getSharedPreferencesNames(Context context) { @@ -143,15 +144,15 @@ public class ComboPreferences implements } private static boolean isGlobal(String key) { - return key.equals(CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL) - || key.equals(CameraSettings.KEY_CAMERA_ID) + return key.equals(CameraSettings.KEY_CAMERA_ID) || key.equals(CameraSettings.KEY_RECORD_LOCATION) || key.equals(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN) || key.equals(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN) || key.equals(CameraSettings.KEY_VIDEO_EFFECT) || key.equals(CameraSettings.KEY_TIMER) || key.equals(CameraSettings.KEY_TIMER_SOUND_EFFECTS) - || key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE); + || key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE) + || key.equals(CameraSettings.KEY_CAMERA_SAVEPATH); } @Override diff --git a/src/com/android/camera/CountDownTimerPreference.java b/src/com/android/camera/CountDownTimerPreference.java index 9a7e44bfb..14819fa48 100644 --- a/src/com/android/camera/CountDownTimerPreference.java +++ b/src/com/android/camera/CountDownTimerPreference.java @@ -39,7 +39,8 @@ public class CountDownTimerPreference extends ListPreference { entries[0] = context.getString(R.string.setting_off); // Off } else { entries[i] = context.getResources() - .getQuantityString(R.plurals.pref_camera_timer_entry, i, i); + .getQuantityString(R.plurals.pref_camera_timer_entry, i, + DURATIONS[i]); } } setEntries(entries); diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java index 797316258..602c31767 100644 --- a/src/com/android/camera/FocusOverlayManager.java +++ b/src/com/android/camera/FocusOverlayManager.java @@ -63,12 +63,12 @@ public class FocusOverlayManager { private static final int RESET_TOUCH_FOCUS_DELAY = 3000; private int mState = STATE_IDLE; - private static final int STATE_IDLE = 0; // Focus is not active. - private static final int STATE_FOCUSING = 1; // Focus is in progress. + public static final int STATE_IDLE = 0; // Focus is not active. + public static final int STATE_FOCUSING = 1; // Focus is in progress. // Focus is in progress and the camera should take a picture after focus finishes. - private static final int STATE_FOCUSING_SNAP_ON_FINISH = 2; - private static final int STATE_SUCCESS = 3; // Focus finishes and succeeds. - private static final int STATE_FAIL = 4; // Focus finishes and fails. + public static final int STATE_FOCUSING_SNAP_ON_FINISH = 2; + public static final int STATE_SUCCESS = 3; // Focus finishes and succeeds. + public static final int STATE_FAIL = 4; // Focus finishes and fails. private boolean mInitialized; private boolean mFocusAreaSupported; @@ -89,6 +89,9 @@ public class FocusOverlayManager { private Handler mHandler; Listener mListener; private boolean mPreviousMoving; + private boolean mZslEnabled = false; //QCom Parameter to disable focus for ZSL + private boolean mTouchAFRunning = false; + private boolean mIsAFRunning = false; private FocusUI mUI; private final Rect mPreviewRect = new Rect(0, 0, 0, 0); @@ -199,7 +202,7 @@ public class FocusOverlayManager { } private void lockAeAwbIfNeeded() { - if (mLockAeAwbNeeded && !mAeAwbLock) { + if (mLockAeAwbNeeded && !mAeAwbLock && !mZslEnabled) { mAeAwbLock = true; mListener.setFocusParameters(); } @@ -309,6 +312,10 @@ public class FocusOverlayManager { // Ignore if the camera has detected some faces. if (mUI.hasFaces()) { mUI.clearFocus(); + if (mIsAFRunning) { + mUI.onFocusSucceeded(true); + mIsAFRunning = false; + } return; } @@ -319,8 +326,10 @@ public class FocusOverlayManager { // animate on false->true trasition only b/8219520 if (moving && !mPreviousMoving) { mUI.onFocusStarted(); + mIsAFRunning = true; } else if (!moving) { mUI.onFocusSucceeded(true); + mIsAFRunning = false; } mPreviousMoving = moving; } @@ -378,6 +387,10 @@ public class FocusOverlayManager { // Use margin to set the focus indicator to the touched area. mUI.setFocusPosition(x, y); + if (mZslEnabled) { + mTouchAFRunning = true; + } + // Stop face detection because we want to specify focus and metering area. mListener.stopFaceDetection(); @@ -405,6 +418,7 @@ public class FocusOverlayManager { } public void onCameraReleased() { + mTouchAFRunning = false; onPreviewStopped(); } @@ -519,7 +533,18 @@ public class FocusOverlayManager { mUI.clearFocus(); // Initialize mFocusArea. mFocusArea = null; + // Initialize mMeteringArea. mMeteringArea = null; + + // Reset metering area when no specific region is selected. + if (mMeteringAreaSupported) { + resetMeteringAreas(); + } + + if (mTouchAFRunning && mZslEnabled) { + mTouchAFRunning = false; + mListener.setFocusParameters(); + } } private void calculateTapArea(int x, int y, float areaMultiple, Rect rect) { @@ -548,6 +573,10 @@ public class FocusOverlayManager { return mState == STATE_SUCCESS || mState == STATE_FAIL; } + public int getCurrentFocusState() { + return mState; + } + public boolean isFocusingSnapOnFinish() { return mState == STATE_FOCUSING_SNAP_ON_FINISH; } @@ -574,4 +603,17 @@ public class FocusOverlayManager { || focusMode.equals(Parameters.FOCUS_MODE_FIXED) || focusMode.equals(Parameters.FOCUS_MODE_EDOF)); } + + public void setZslEnable(boolean value) { + mZslEnabled = value; + } + + public boolean isZslEnabled() { + return mZslEnabled; + } + + public boolean isTouch() { + return mTouchAFRunning; + } + } diff --git a/src/com/android/camera/ListPreference.java b/src/com/android/camera/ListPreference.java index 909b32c55..2a33fb098 100644 --- a/src/com/android/camera/ListPreference.java +++ b/src/com/android/camera/ListPreference.java @@ -128,7 +128,9 @@ public class ListPreference extends CameraPreference { } public void setValue(String value) { - if (findIndexOfValue(value) < 0) throw new IllegalArgumentException(); + if (findIndexOfValue(value) < 0) { + value = findSupportedDefaultValue(); + } mValue = value; persistStringValue(value); } diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index e8ec08d57..c19dcd498 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -28,7 +28,7 @@ import android.os.Binder; import android.os.IBinder; import android.provider.MediaStore.Video; import android.util.Log; - +import com.android.camera.PhotoModule; import com.android.camera.exif.ExifInterface; import java.io.File; @@ -39,8 +39,8 @@ import java.io.File; public class MediaSaveService extends Service { public static final String VIDEO_BASE_URI = "content://media/external/video/media"; - // The memory limit for unsaved image is 20MB. - private static final int SAVE_TASK_MEMORY_LIMIT = 20 * 1024 * 1024; + // The memory limit for unsaved image is 50MB. + private static final int SAVE_TASK_MEMORY_LIMIT = 50 * 1024 * 1024; private static final String TAG = "CAM_" + MediaSaveService.class.getSimpleName(); private final IBinder mBinder = new LocalBinder(); @@ -87,14 +87,14 @@ public class MediaSaveService extends Service { public void addImage(final byte[] data, String title, long date, Location loc, int width, int height, int orientation, ExifInterface exif, - OnMediaSavedListener l, ContentResolver resolver) { + OnMediaSavedListener l, ContentResolver resolver, String pictureFormat) { if (isQueueFull()) { Log.e(TAG, "Cannot add image when the queue is full"); return; } ImageSaveTask t = new ImageSaveTask(data, title, date, (loc == null) ? null : new Location(loc), - width, height, orientation, exif, resolver, l); + width, height, orientation, exif, resolver, l, pictureFormat); mMemoryUse += data.length; if (isQueueFull()) { @@ -108,13 +108,14 @@ public class MediaSaveService extends Service { OnMediaSavedListener l, ContentResolver resolver) { // When dimensions are unknown, pass 0 as width and height, // and decode image for width and height later in a background thread - addImage(data, title, date, loc, 0, 0, orientation, exif, l, resolver); + addImage(data, title, date, loc, 0, 0, orientation, exif, l, resolver, + PhotoModule.PIXEL_FORMAT_JPEG); } public void addImage(final byte[] data, String title, Location loc, int width, int height, int orientation, ExifInterface exif, OnMediaSavedListener l, ContentResolver resolver) { addImage(data, title, System.currentTimeMillis(), loc, width, height, - orientation, exif, l, resolver); + orientation, exif, l, resolver,PhotoModule.PIXEL_FORMAT_JPEG); } public void addVideo(String path, long duration, ContentValues values, @@ -148,10 +149,11 @@ public class MediaSaveService extends Service { private ExifInterface exif; private ContentResolver resolver; private OnMediaSavedListener listener; + private String pictureFormat; public ImageSaveTask(byte[] data, String title, long date, Location loc, int width, int height, int orientation, ExifInterface exif, - ContentResolver resolver, OnMediaSavedListener listener) { + ContentResolver resolver, OnMediaSavedListener listener, String pictureFormat) { this.data = data; this.title = title; this.date = date; @@ -162,6 +164,7 @@ public class MediaSaveService extends Service { this.exif = exif; this.resolver = resolver; this.listener = listener; + this.pictureFormat = pictureFormat; } @Override @@ -180,7 +183,7 @@ public class MediaSaveService extends Service { height = options.outHeight; } return Storage.addImage( - resolver, title, date, loc, orientation, exif, data, width, height); + resolver, title, date, loc, orientation, exif, data, width, height, pictureFormat); } @Override diff --git a/src/com/android/camera/PauseButton.java b/src/com/android/camera/PauseButton.java new file mode 100644 index 000000000..a785050fd --- /dev/null +++ b/src/com/android/camera/PauseButton.java @@ -0,0 +1,82 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package com.android.camera; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.view.MotionEvent; +import android.view.View; +import android.util.Log; + +/** + * A button designed to be used for the on-screen recording + * pausing-continue button. + */ +public class PauseButton extends ImageView { + + public interface OnPauseButtonListener { + void onButtonPause(); + void onButtonContinue(); + } + + public PauseButton(Context context, AttributeSet attrs) { + super(context, attrs); + setClickable(true); + setSelected(false); + } + + public void setPaused(boolean paused) { + setSelected(paused); + } + + @Override + public boolean performClick() { + boolean result = super.performClick(); + if (isSelected()) { + setSelected(false); + if (mListener != null && getVisibility() == View.VISIBLE) { + mListener.onButtonContinue(); + } + } else { + setSelected(true); + if (mListener != null && getVisibility() == View.VISIBLE) { + mListener.onButtonPause(); + } + } + return result; + } + + public void setOnPauseButtonListener(OnPauseButtonListener listener) { + mListener = listener; + } + + private OnPauseButtonListener mListener; +} diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index 833c82574..c1c3a8562 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -31,6 +31,8 @@ public interface PhotoController extends OnShutterButtonListener { public static final int SNAPSHOT_IN_PROGRESS = 3; // Switching between cameras. public static final int SWITCHING_CAMERA = 4; + // Longshot mode + public static final int LONGSHOT = 5; // returns the actual set zoom value public int onZoomChanged(int requestedZoom); @@ -55,6 +57,8 @@ public interface PhotoController extends OnShutterButtonListener { public void onCountDownFinished(); + public void onScreenSizeChanged(int width, int height); + public void onPreviewRectChanged(Rect previewRect); public void updateCameraOrientation(); diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java index 08ce3374e..a9526962b 100644 --- a/src/com/android/camera/PhotoMenu.java +++ b/src/com/android/camera/PhotoMenu.java @@ -24,21 +24,43 @@ import android.hardware.Camera.Parameters; import com.android.camera.ui.AbstractSettingPopup; import com.android.camera.ui.CountdownTimerPopup; 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.camera2.R; +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.Toast; +import android.util.Log; + +import java.util.Locale; public class PhotoMenu extends PieController - implements CountdownTimerPopup.Listener, + implements MoreSettingPopup.Listener, + CountdownTimerPopup.Listener, ListPrefSettingPopup.Listener { private static String TAG = "PhotoMenu"; private final String mSettingOff; + private String[] mOtherKeys1; + private String[] mOtherKeys2; + private String[] mOtherKeys3; + private MoreSettingPopup mPopup1; + private MoreSettingPopup mPopup2; + private MoreSettingPopup mPopup3; + private static final int POPUP_NONE = 0; + private static final int POPUP_FIRST_LEVEL = 1; + private static final int POPUP_SECOND_LEVEL = 2; private PhotoUI mUI; + private int mPopupStatus; private AbstractSettingPopup mPopup; private CameraActivity mActivity; + private int popupNum = 0; + private PieItem mHdrItem = null; + private PieItem mHdrPlusItem = null; + private boolean mHdrOn = false; public PhotoMenu(CameraActivity activity, PhotoUI ui, PieRenderer pie) { super(activity, pie); @@ -50,39 +72,112 @@ public class PhotoMenu extends PieController public void initialize(PreferenceGroup group) { super.initialize(group); mPopup = null; + mPopup1 = null; + mPopup2 = null; + mPopup3 = null; + mPopupStatus = POPUP_NONE; PieItem item = null; + popupNum = 0; final Resources res = mActivity.getResources(); Locale locale = res.getConfiguration().locale; // The order is from left to right in the menu. // HDR+ (GCam). if (group.findPreference(CameraSettings.KEY_CAMERA_HDR_PLUS) != null) { - item = makeSwitchItem(CameraSettings.KEY_CAMERA_HDR_PLUS, true); - mRenderer.addItem(item); + mHdrPlusItem = makeSwitchItem(CameraSettings.KEY_CAMERA_HDR_PLUS, true); + mRenderer.addItem(mHdrPlusItem); } // HDR. if (group.findPreference(CameraSettings.KEY_CAMERA_HDR) != null) { - item = makeSwitchItem(CameraSettings.KEY_CAMERA_HDR, true); - mRenderer.addItem(item); - } - // Exposure compensation. - if (group.findPreference(CameraSettings.KEY_EXPOSURE) != null) { - item = makeItem(CameraSettings.KEY_EXPOSURE); - item.setLabel(res.getString(R.string.pref_exposure_label)); - mRenderer.addItem(item); - } - // More settings. - PieItem more = makeItem(R.drawable.ic_settings_holo_light); - more.setLabel(res.getString(R.string.camera_menu_more_label)); - mRenderer.addItem(more); - - // Flash. - if (group.findPreference(CameraSettings.KEY_FLASH_MODE) != null) { - item = makeItem(CameraSettings.KEY_FLASH_MODE); - item.setLabel(res.getString(R.string.pref_camera_flashmode_label)); - mRenderer.addItem(item); + mHdrItem = makeSwitchItem(CameraSettings.KEY_CAMERA_HDR, true); + mRenderer.addItem(mHdrItem); } + + mOtherKeys1 = new String[] { + CameraSettings.KEY_SCENE_MODE, + CameraSettings.KEY_RECORD_LOCATION, + CameraSettings.KEY_PICTURE_SIZE, + CameraSettings.KEY_HISTOGRAM, + CameraSettings.KEY_JPEG_QUALITY, + CameraSettings.KEY_ZSL, + CameraSettings.KEY_TIMER, + CameraSettings.KEY_TIMER_SOUND_EFFECTS, + CameraSettings.KEY_CAMERA_SAVEPATH, + CameraSettings.KEY_LONGSHOT + }; + + mOtherKeys2 = new String[] { + CameraSettings.KEY_COLOR_EFFECT, + CameraSettings.KEY_FACE_DETECTION, + CameraSettings.KEY_FACE_RECOGNITION, + CameraSettings.KEY_TOUCH_AF_AEC, + CameraSettings.KEY_SELECTABLE_ZONE_AF, + CameraSettings.KEY_PICTURE_FORMAT, + CameraSettings.KEY_SATURATION, + CameraSettings.KEY_CONTRAST, + CameraSettings.KEY_SHARPNESS, + CameraSettings.KEY_AUTOEXPOSURE + }; + + mOtherKeys3 = new String[] { + CameraSettings.KEY_ANTIBANDING, + CameraSettings.KEY_ISO, + CameraSettings.KEY_DENOISE, + CameraSettings.KEY_ADVANCED_FEATURES, + CameraSettings.KEY_EXPOSURE, + CameraSettings.KEY_WHITE_BALANCE, + CameraSettings.KEY_FLASH_MODE, + CameraSettings.KEY_FOCUS_MODE, + CameraSettings.KEY_REDEYE_REDUCTION, + CameraSettings.KEY_AE_BRACKET_HDR + }; + + PieItem item1 = makeItem(R.drawable.ic_settings_holo_light); + item1.setLabel(mActivity.getResources().getString(R.string.camera_menu_more_label)); + item1.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup1 == null || mPopupStatus != POPUP_FIRST_LEVEL){ + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + } + mUI.showPopup(mPopup1); + popupNum = 1; + } + }); + mRenderer.addItem(item1); + + PieItem item2 = makeItem(R.drawable.ic_settings_holo_light); + item2.setLabel(mActivity.getResources().getString(R.string.camera_menu_more_label)); + item2.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup2 == null || mPopupStatus != POPUP_FIRST_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + } + mUI.showPopup(mPopup2); + popupNum = 2; + } + }); + mRenderer.addItem(item2); + + PieItem item3= makeItem(R.drawable.ic_settings_holo_light); + item3.setLabel(mActivity.getResources().getString(R.string.camera_menu_more_label)); + item3.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup3 == null || mPopupStatus != POPUP_FIRST_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + } + mUI.showPopup(mPopup3); + popupNum = 3; + } + }); + mRenderer.addItem(item3); + // Camera switcher. if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { item = makeSwitchItem(CameraSettings.KEY_CAMERA_ID, false); @@ -105,79 +200,170 @@ public class PhotoMenu extends PieController }); mRenderer.addItem(item); } - // Location. - if (group.findPreference(CameraSettings.KEY_RECORD_LOCATION) != null) { - item = makeSwitchItem(CameraSettings.KEY_RECORD_LOCATION, true); - more.addItem(item); - if (mActivity.isSecureCamera()) { - // Prevent location preference from getting changed in secure camera mode - item.setEnabled(false); - } - } - // Countdown timer. - final ListPreference ctpref = group.findPreference(CameraSettings.KEY_TIMER); - final ListPreference beeppref = group.findPreference(CameraSettings.KEY_TIMER_SOUND_EFFECTS); - item = makeItem(R.drawable.ic_timer); - item.setLabel(res.getString(R.string.pref_camera_timer_title).toUpperCase(locale)); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - CountdownTimerPopup timerPopup = (CountdownTimerPopup) mActivity.getLayoutInflater().inflate( - R.layout.countdown_setting_popup, null, false); - timerPopup.initialize(ctpref, beeppref); - timerPopup.setSettingChangedListener(PhotoMenu.this); - mUI.dismissPopup(); - mPopup = timerPopup; - mUI.showPopup(mPopup); - } - }); - more.addItem(item); - // Image size. - item = makeItem(R.drawable.ic_imagesize); - final ListPreference sizePref = group.findPreference(CameraSettings.KEY_PICTURE_SIZE); - item.setLabel(res.getString(R.string.pref_camera_picturesize_title).toUpperCase(locale)); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - ListPrefSettingPopup popup = (ListPrefSettingPopup) mActivity.getLayoutInflater().inflate( - R.layout.list_pref_setting_popup, null, false); - popup.initialize(sizePref); - popup.setSettingChangedListener(PhotoMenu.this); - mUI.dismissPopup(); - mPopup = popup; - mUI.showPopup(mPopup); - } - }); - more.addItem(item); - // White balance. - if (group.findPreference(CameraSettings.KEY_WHITE_BALANCE) != null) { - item = makeItem(CameraSettings.KEY_WHITE_BALANCE); - item.setLabel(res.getString(R.string.pref_camera_whitebalance_label)); - more.addItem(item); - } - // Scene mode. - if (group.findPreference(CameraSettings.KEY_SCENE_MODE) != null) { - IconListPreference pref = (IconListPreference) group.findPreference( - CameraSettings.KEY_SCENE_MODE); - pref.setUseSingleIcon(true); - item = makeItem(CameraSettings.KEY_SCENE_MODE); - more.addItem(item); - } } @Override // Hit when an item in a popup gets selected public void onListPrefChanged(ListPreference pref) { - if (mPopup != null) { - mUI.dismissPopup(); + if (mPopup != null && mPopup1 != null && mPopup2 != null && mPopup3 != null) { + mUI.dismissPopup(); } onSettingChanged(pref); } - public void popupDismissed() { - if (mPopup != null) { - mPopup = null; + @Override + public void overrideSettings(final String ... keyvalues) { + super.overrideSettings(keyvalues); + if ((mPopup1 == null) && (mPopup2 == null) && (mPopup3 == null)) initializePopup(); + mPopup1.overrideSettings(keyvalues); + mPopup2.overrideSettings(keyvalues); + mPopup3.overrideSettings(keyvalues); + } + + protected void initializePopup() { + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + MoreSettingPopup popup1 = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup1.setSettingChangedListener(this); + popup1.initialize(mPreferenceGroup, mOtherKeys1); + if (mActivity.isSecureCamera()) { + // Prevent location preference from getting changed in secure camera mode + popup1.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION,false); + } + mPopup1 = popup1; + + MoreSettingPopup popup2 = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup2.setSettingChangedListener(this); + popup2.initialize(mPreferenceGroup, mOtherKeys2); + mPopup2 = popup2; + + MoreSettingPopup popup3 = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup3.setSettingChangedListener(this); + popup3.initialize(mPreferenceGroup, mOtherKeys3); + mPopup3 = popup3; + + ListPreference pref = mPreferenceGroup.findPreference( + CameraSettings.KEY_SCENE_MODE); + String sceneMode = (pref != null) ? pref.getValue() : null; + pref = mPreferenceGroup.findPreference(CameraSettings.KEY_FACE_DETECTION); + String faceDetection = (pref != null) ? pref.getValue() : null; + pref = mPreferenceGroup.findPreference(CameraSettings.KEY_ZSL); + String zsl = (pref != null) ? pref.getValue() : null; + if ((sceneMode != null) && !Parameters.SCENE_MODE_AUTO.equals(sceneMode)){ + popup3.setPreferenceEnabled(CameraSettings.KEY_FOCUS_MODE,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_AUTOEXPOSURE,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_TOUCH_AF_AEC,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_SATURATION,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_CONTRAST,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_SHARPNESS,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_COLOR_EFFECT,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_FLASH_MODE,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_WHITE_BALANCE,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_EXPOSURE,false); + } + if ((zsl != null) && Parameters.ZSL_ON.equals(zsl)) { + popup3.setPreferenceEnabled(CameraSettings.KEY_FOCUS_MODE,false); + } + if ((faceDetection != null) && !Parameters.FACE_DETECTION_ON.equals(faceDetection)){ + popup2.setPreferenceEnabled(CameraSettings.KEY_FACE_RECOGNITION,false); + } + popup1.setPreferenceEnabled(CameraSettings.KEY_ZSL, !mUI.isCountingDown()); + + pref = mPreferenceGroup.findPreference(CameraSettings.KEY_ADVANCED_FEATURES); + String advancedFeatures = (pref != null) ? pref.getValue() : null; + + String ubiFocusOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_ubifocus_on); + String chromaFlashOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_chromaflash_on); + String optiZoomOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_optizoom_on); + + if ((zsl != null) && Parameters.ZSL_OFF.equals(zsl)) { + popup3.overrideSettings(CameraSettings.KEY_ADVANCED_FEATURES, + mActivity.getString(R.string.pref_camera_advanced_feature_default)); + + popup3.setPreferenceEnabled(CameraSettings.KEY_ADVANCED_FEATURES,false); + if (mHdrItem != null) { + mHdrItem.setEnabled(true); + } + if (mHdrPlusItem != null) { + mHdrPlusItem.setEnabled(true); + } + } else { + if ((advancedFeatures != null) && (advancedFeatures.equals(ubiFocusOn) || + advancedFeatures.equals(chromaFlashOn) || + advancedFeatures.equals(optiZoomOn))) { + popup3.setPreferenceEnabled(CameraSettings.KEY_FOCUS_MODE,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_FLASH_MODE,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_AE_BRACKET_HDR,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_REDEYE_REDUCTION,false); + popup3.setPreferenceEnabled(CameraSettings.KEY_EXPOSURE,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_COLOR_EFFECT,false); + popup2.setPreferenceEnabled(CameraSettings.KEY_TOUCH_AF_AEC,false); + popup1.setPreferenceEnabled(CameraSettings.KEY_SCENE_MODE,false); + + setPreference(CameraSettings.KEY_CAMERA_HDR, mSettingOff); + + if (mHdrItem != null) { + mHdrItem.setEnabled(false); + } + if (mHdrPlusItem != null) { + mHdrPlusItem.setEnabled(false); + } + } else { + if (mHdrItem != null) { + mHdrItem.setEnabled(true); + } + if (mHdrPlusItem != null) { + mHdrPlusItem.setEnabled(true); + } + } + } + + if (mListener != null) { + mListener.onSharedPreferenceChanged(); + } + } + + public void popupDismissed(boolean dismissAll) { + if (!dismissAll && mPopupStatus == POPUP_SECOND_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + if (popupNum == 1) + mUI.showPopup(mPopup1); + else if (popupNum == 2) + mUI.showPopup(mPopup2); + else if (popupNum == 3) + mUI.showPopup(mPopup3); + if(mPopup1 != null) mPopup1 = null; + if(mPopup2 != null) mPopup2 = null; + if(mPopup3 != null) mPopup3 = null; + } else { + initializePopup(); } + + } + + @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); + ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( + R.layout.list_pref_setting_popup, null, false); + basic.initialize(pref); + basic.setSettingChangedListener(this); + mUI.dismissPopup(); + mPopup = basic; + mUI.showPopup(mPopup); + mPopupStatus = POPUP_SECOND_LEVEL; } // Return true if the preference has the specified key but not the value. @@ -185,7 +371,7 @@ public class PhotoMenu extends PieController return (key.equals(pref.getKey()) && !value.equals(pref.getValue())); } - private void setPreference(String key, String value) { + public void setPreference(String key, String value) { ListPreference pref = mPreferenceGroup.findPreference(key); if (pref != null && !value.equals(pref.getValue())) { pref.setValue(value); @@ -199,9 +385,29 @@ public class PhotoMenu extends PieController // set to non-auto. if (notSame(pref, CameraSettings.KEY_CAMERA_HDR, mSettingOff)) { setPreference(CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO); + Toast.makeText(mActivity, R.string.hdr_enable_message, + Toast.LENGTH_LONG).show(); + mHdrOn = true; } else if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) { setPreference(CameraSettings.KEY_CAMERA_HDR, mSettingOff); + if (mHdrOn) { + Toast.makeText(mActivity, R.string.scene_enable_message, + Toast.LENGTH_LONG).show(); + } + mHdrOn = false; + } else if (notSame(pref,CameraSettings.KEY_AE_BRACKET_HDR,"Off")) { + Toast.makeText(mActivity, + R.string.flash_aebracket_message,Toast.LENGTH_SHORT).show(); + setPreference(CameraSettings.KEY_FLASH_MODE,Parameters.FLASH_MODE_OFF); + } else if (notSame(pref,CameraSettings.KEY_FLASH_MODE,"Off")) { + ListPreference aePref = + mPreferenceGroup.findPreference(CameraSettings.KEY_AE_BRACKET_HDR); + if (notSame(aePref,CameraSettings.KEY_AE_BRACKET_HDR,"Off")) { + Toast.makeText(mActivity, + R.string.flash_aebracket_message,Toast.LENGTH_SHORT).show(); + } } super.onSettingChanged(pref); } + } diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 2afaf5bf5..3d6218281 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -30,6 +30,7 @@ import android.graphics.SurfaceTexture; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; +import android.hardware.Camera; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -50,6 +51,12 @@ import android.view.KeyEvent; import android.view.OrientationEventListener; import android.view.View; import android.view.WindowManager; +import android.widget.Toast; +import android.widget.ProgressBar; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.LinearLayout; +import android.widget.TextView; import com.android.camera.CameraManager.CameraAFCallback; import com.android.camera.CameraManager.CameraAFMoveCallback; @@ -76,6 +83,14 @@ import java.io.IOException; import java.io.OutputStream; import java.util.List; import java.util.Vector; +import java.util.HashMap; +import android.util.AttributeSet; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.SystemProperties; +import java.util.Collections; +import java.util.Formatter; public class PhotoModule implements CameraModule, @@ -89,6 +104,20 @@ public class PhotoModule private static final String TAG = "CAM_PhotoModule"; + //QCom data members + public static boolean mBrightnessVisible = true; + private static final int MAX_SHARPNESS_LEVEL = 6; + private boolean mRestartPreview = false; + private int mSnapshotMode; + private int mBurstSnapNum = 1; + private int mReceivedSnapNum = 0; + public boolean mFaceDetectionEnabled = false; + + /*Histogram variables*/ + private GraphView mGraphView; + private static final int STATS_DATA = 257; + public static int statsdata[] = new int[STATS_DATA]; + public boolean mHiston = false; // We number the request code from 1000 to avoid collision with Gallery. private static final int REQUEST_CROP = 1000; @@ -102,7 +131,10 @@ public class PhotoModule private static final int CAMERA_OPEN_DONE = 8; private static final int OPEN_CAMERA_FAIL = 9; private static final int CAMERA_DISABLED = 10; - private static final int SWITCH_TO_GCAM_MODULE = 11; + private static final int SET_SKIN_TONE_FACTOR = 11; + private static final int SET_PHOTO_UI_PARAMS = 12; + private static final int SWITCH_TO_GCAM_MODULE = 13; + private static final int CONFIGURE_SKIN_TONE_FACTOR = 14; // The subset of parameters we need to update in setCameraParameters(). private static final int UPDATE_PARAM_INITIALIZE = 1; @@ -122,6 +154,7 @@ public class PhotoModule private int mCameraId; private Parameters mParameters; private boolean mPaused; + private View mRootView; private PhotoUI mUI; @@ -146,6 +179,8 @@ public class PhotoModule private boolean mAeLockSupported; private boolean mAwbLockSupported; private boolean mContinuousFocusSupported; + private boolean mTouchAfAecFlag; + private boolean mLongshotSave = false; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -156,6 +191,33 @@ public class PhotoModule private ContentProviderClient mMediaProviderClient; private boolean mFaceDetectionStarted = false; + private static final String PERSIST_LONG_ENABLE = "persist.camera.longshot.enable"; + private static final String PERSIST_LONG_SAVE = "persist.camera.longshot.save"; + private static final String PERSIST_PREVIEW_RESTART = "persist.camera.feature.restart"; + + private static final int MINIMUM_BRIGHTNESS = 0; + private static final int MAXIMUM_BRIGHTNESS = 6; + private int mbrightness = 3; + private int mbrightness_step = 1; + private ProgressBar brightnessProgressBar; + // Constant from android.hardware.Camera.Parameters + private static final String KEY_PICTURE_FORMAT = "picture-format"; + private static final String KEY_QC_RAW_PICUTRE_SIZE = "raw-size"; + public static final String PIXEL_FORMAT_JPEG = "jpeg"; + + private static final int MIN_SCE_FACTOR = -10; + private static final int MAX_SCE_FACTOR = +10; + private int SCE_FACTOR_STEP = 10; + private int mskinToneValue = 0; + private boolean mSkinToneSeekBar= false; + private boolean mSeekBarInitialized = false; + private SeekBar skinToneSeekBar; + private TextView LeftValue; + private TextView RightValue; + private TextView Title; + + private boolean mPreviewRestartSupport = false; + // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. private String mCropValue; private Uri mSaveUri; @@ -215,6 +277,7 @@ public class PhotoModule : null; private final CameraErrorCallback mErrorCallback = new CameraErrorCallback(); + private final StatsCallback mStatsCallback = new StatsCallback(); private long mFocusStartTime; private long mShutterCallbackTime; @@ -236,8 +299,10 @@ public class PhotoModule private FocusOverlayManager mFocusManager; private String mSceneMode; + private String mCurrTouchAfAec = Parameters.TOUCH_AF_AEC_ON; private final Handler mHandler = new MainHandler(); + private MessageQueue.IdleHandler mIdleHandler = null; private PreferenceGroup mPreferenceGroup; @@ -347,10 +412,47 @@ public class PhotoModule R.string.camera_disabled); break; } + case SET_SKIN_TONE_FACTOR: { + Log.v(TAG, "set tone bar: mSceneMode = " + mSceneMode); + setSkinToneFactor(); + mSeekBarInitialized = true; + // skin tone ie enabled only for party and portrait BSM + // when color effects are not enabled + String colorEffect = mPreferences.getString( + CameraSettings.KEY_COLOR_EFFECT, + mActivity.getString(R.string.pref_camera_coloreffect_default)); + if((Parameters.SCENE_MODE_PARTY.equals(mSceneMode) || + Parameters.SCENE_MODE_PORTRAIT.equals(mSceneMode))&& + (Parameters.EFFECT_NONE.equals(colorEffect))) { + ; + } + else{ + Log.v(TAG, "Skin tone bar: disable"); + disableSkinToneSeekBar(); + } + break; + } + case SET_PHOTO_UI_PARAMS: { + setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); + mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, + mPreferences); + break; + } case SWITCH_TO_GCAM_MODULE: { mActivity.onModuleSelected(ModuleSwitcher.GCAM_MODULE_INDEX); } + + case CONFIGURE_SKIN_TONE_FACTOR: { + if ((mCameraDevice != null) && isCameraIdle()) { + synchronized (mCameraDevice) { + mParameters = mCameraDevice.getParameters(); + mParameters.set("skinToneEnhancement", String.valueOf(msg.arg1)); + mCameraDevice.setParameters(mParameters); + } + } + break; + } } } } @@ -359,6 +461,7 @@ public class PhotoModule @Override public void init(CameraActivity activity, View parent) { mActivity = activity; + mRootView = parent; mUI = new PhotoUI(activity, this, parent); mPreferences = new ComboPreferences(mActivity); CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); @@ -379,6 +482,23 @@ public class PhotoModule mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); mLocationManager = new LocationManager(mActivity, mUI); mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE)); + + brightnessProgressBar = (ProgressBar)mRootView.findViewById(R.id.progress); + if (brightnessProgressBar instanceof SeekBar) { + SeekBar seeker = (SeekBar) brightnessProgressBar; + seeker.setOnSeekBarChangeListener(mSeekListener); + } + brightnessProgressBar.setMax(MAXIMUM_BRIGHTNESS); + brightnessProgressBar.setProgress(mbrightness); + skinToneSeekBar = (SeekBar) mRootView.findViewById(R.id.skintoneseek); + skinToneSeekBar.setOnSeekBarChangeListener(mskinToneSeekListener); + skinToneSeekBar.setVisibility(View.INVISIBLE); + Title = (TextView)mRootView.findViewById(R.id.skintonetitle); + RightValue = (TextView)mRootView.findViewById(R.id.skintoneright); + LeftValue = (TextView)mRootView.findViewById(R.id.skintoneleft); + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + } private void initializeControlByIntent() { @@ -392,6 +512,7 @@ public class PhotoModule setCameraState(IDLE); startFaceDetection(); locationFirstRun(); + mUI.enableShutter(true); } // Prompt the user to pick to record location for the very first run of @@ -447,6 +568,7 @@ public class PhotoModule int height = root.getHeight(); mFocusManager.setPreviewSize(width, height); openCameraCommon(); + resizeForPreviewAspectRatio(); } private void switchCamera() { @@ -461,6 +583,7 @@ public class PhotoModule closeCamera(); mUI.collapseCameraControls(); mUI.clearFaces(); + disableSkinToneSeekBar(); if (mFocusManager != null) mFocusManager.removeMessages(); // Restart the camera and initialize the UI. From onCreate. @@ -484,6 +607,7 @@ public class PhotoModule // reset zoom value index mZoomValue = 0; + resizeForPreviewAspectRatio(); openCameraCommon(); // Start switch camera animation. Post a message because @@ -505,13 +629,18 @@ public class PhotoModule mUI.overrideSettings(CameraSettings.KEY_CAMERA_HDR_PLUS, mActivity.getString(R.string.setting_off_value)); } - updateSceneMode(); + updateCameraSettings(); showTapToFocusToastIfNeeded(); } @Override + public void onScreenSizeChanged(int width, int height) { + if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); + } + + @Override public void onPreviewRectChanged(Rect previewRect) { if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect); } @@ -526,6 +655,29 @@ public class PhotoModule } } + void setPreviewFrameLayoutCameraOrientation(){ + CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; + //if camera mount angle is 0 or 180, we want to resize preview + if (info.orientation % 180 == 0){ + mUI.cameraOrientationPreviewResize(true); + } else{ + mUI.cameraOrientationPreviewResize(false); + } + } + + @Override + public void resizeForPreviewAspectRatio() { + if ( mCameraDevice == null || mParameters == null) { + Log.e(TAG, "Camera not yet initialized"); + return; + } + setPreviewFrameLayoutCameraOrientation(); + Size size = mParameters.getPreviewSize(); + Log.e(TAG,"Width = "+ size.width+ "Height = "+size.height); + mUI.setAspectRatio((float) size.width / size.height); + } + + private void keepMediaProviderInstance() { // We want to keep a reference to MediaProvider in camera's lifecycle. // TODO: Utilize mMediaProviderClient instance to replace @@ -560,8 +712,15 @@ public class PhotoModule } mNamedImages = new NamedImages(); + mGraphView = (GraphView)mRootView.findViewById(R.id.graph_view); + if(mGraphView == null){ + Log.e(TAG, "mGraphView is null"); + } else{ + mGraphView.setPhotoModuleObject(this); + } mFirstTimeInitialized = true; + Log.d(TAG, "addIdleHandler in first time initialization"); addIdleHandler(); mActivity.updateStorageSpaceAndHint(); @@ -579,6 +738,9 @@ public class PhotoModule s.setListener(this); } mNamedImages = new NamedImages(); + if (!mIsImageCaptureIntent) { + mUI.showSwitcher(); + } mUI.initializeSecondTime(mParameters); keepMediaProviderInstance(); } @@ -593,19 +755,32 @@ public class PhotoModule } private void addIdleHandler() { - MessageQueue queue = Looper.myQueue(); - queue.addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - Storage.ensureOSXCompatible(); - return false; - } - }); + if (mIdleHandler == null) { + mIdleHandler = new MessageQueue.IdleHandler() { + @Override + public boolean queueIdle() { + Storage.ensureOSXCompatible(); + return false; + } + }; + + MessageQueue queue = Looper.myQueue(); + queue.addIdleHandler(mIdleHandler); + } + } + + private void removeIdleHandler() { + if (mIdleHandler != null) { + MessageQueue queue = Looper.myQueue(); + queue.removeIdleHandler(mIdleHandler); + mIdleHandler = null; + } } @Override public void startFaceDetection() { - if (mFaceDetectionStarted) return; + if (mFaceDetectionEnabled == false + || mFaceDetectionStarted || mCameraState != IDLE) return; if (mParameters.getMaxNumDetectedFaces() > 0) { mFaceDetectionStarted = true; CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; @@ -618,7 +793,7 @@ public class PhotoModule @Override public void stopFaceDetection() { - if (!mFaceDetectionStarted) return; + if (mFaceDetectionEnabled == false || !mFaceDetectionStarted) return; if (mParameters.getMaxNumDetectedFaces() > 0) { mFaceDetectionStarted = false; mCameraDevice.setFaceDetectionCallback(null, null); @@ -627,6 +802,34 @@ public class PhotoModule } } + private final class LongshotShutterCallback + implements CameraShutterCallback { + + @Override + public void onShutter(CameraProxy camera) { + mShutterCallbackTime = System.currentTimeMillis(); + mShutterLag = mShutterCallbackTime - mCaptureStartTime; + Log.e(TAG, "[KPI Perf] PROFILE_SHUTTER_LAG mShutterLag = " + mShutterLag + "ms"); + synchronized(mCameraDevice) { + + if (mCameraState != LONGSHOT) { + return; + } + + if (mLongshotSave) { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new LongshotPictureCallback(null)); + } else { + mCameraDevice.takePicture(mHandler,new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(null)); + } + } + } + } + private final class ShutterCallback implements CameraShutterCallback { @@ -640,7 +843,7 @@ public class PhotoModule public void onShutter(CameraProxy camera) { mShutterCallbackTime = System.currentTimeMillis(); mShutterLag = mShutterCallbackTime - mCaptureStartTime; - Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); + Log.e(TAG, "[KPI Perf] PROFILE_SHUTTER_LAG mShutterLag = " + mShutterLag + "ms"); if (mNeedsAnimation) { mActivity.runOnUiThread(new Runnable() { @Override @@ -651,7 +854,26 @@ public class PhotoModule } } } - + private final class StatsCallback + implements android.hardware.Camera.CameraDataCallback { + @Override + public void onCameraData(int [] data, android.hardware.Camera camera) { + //if(!mPreviewing || !mHiston || !mFirstTimeInitialized){ + if(!mHiston || !mFirstTimeInitialized){ + return; + } + /*The first element in the array stores max hist value . Stats data begin from second value*/ + synchronized(statsdata) { + System.arraycopy(data,0,statsdata,0,STATS_DATA); + } + mActivity.runOnUiThread(new Runnable() { + public void run() { + if(mGraphView != null) + mGraphView.PreviewChanged(); + } + }); + } + } private final class PostViewPictureCallback implements CameraPictureCallback { @Override @@ -673,6 +895,64 @@ public class PhotoModule } } + private final class LongshotPictureCallback implements CameraPictureCallback { + Location mLocation; + + public LongshotPictureCallback(Location loc) { + mLocation = loc; + } + + @Override + public void onPictureTaken(final byte [] jpegData, CameraProxy camera) { + if (mPaused) { + return; + } + + mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. + + String jpegFilePath = new String(jpegData); + mNamedImages.nameNewImage(mCaptureStartTime); + NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + long date = (name == null) ? -1 : name.date; + + if (title == null) { + Log.e(TAG, "Unbalanced name/data pair"); + return; + } + + + if (date == -1 ) { + Log.e(TAG, "Invalid filename date"); + return; + } + + String dstPath = Storage.DIRECTORY; + File sdCard = android.os.Environment.getExternalStorageDirectory(); + File dstFile = new File(dstPath); + if (dstFile == null) { + Log.e(TAG, "Destination file path invalid"); + return; + } + + File srcFile = new File(jpegFilePath); + if (srcFile == null) { + Log.e(TAG, "Source file path invalid"); + return; + } + + if ( srcFile.renameTo(dstFile) ) { + Size s = mParameters.getPictureSize(); + String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT); + mActivity.getMediaSaveService().addImage( + null, title, date, mLocation, s.width, s.height, + 0, null, mOnMediaSavedListener, mContentResolver, pictureFormat); + } else { + Log.e(TAG, "Failed to move jpeg file"); + } + } + } + private final class JpegPictureCallback implements CameraPictureCallback { Location mLocation; @@ -695,7 +975,15 @@ public class PhotoModule mUI.setSwipingEnabled(true); } + mReceivedSnapNum = mReceivedSnapNum + 1; mJpegPictureCallbackTime = System.currentTimeMillis(); + if(mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { + Log.v(TAG, "JpegPictureCallback : in zslmode"); + mParameters = mCameraDevice.getParameters(); + mBurstSnapNum = mParameters.getInt("num-snaps-per-shutter"); + } + Log.v(TAG, "JpegPictureCallback: Received = " + mReceivedSnapNum + + "Burst count = " + mBurstSnapNum); // If postview callback has arrived, the captured image is displayed // in postview callback. If not, the captured image is displayed in // raw picture callback. @@ -714,14 +1002,37 @@ public class PhotoModule + mPictureDisplayedToJpegCallbackTime + "ms"); mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. - if (!mIsImageCaptureIntent) { + + boolean needRestartPreview = !mIsImageCaptureIntent + && !mPreviewRestartSupport + && (mCameraState != LONGSHOT) + && (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) + && (mReceivedSnapNum == mBurstSnapNum); + if (needRestartPreview) { setupPreview(); + if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals( + mFocusManager.getFocusMode())) { + mCameraDevice.cancelAutoFocus(); + } + }else if ((mReceivedSnapNum == mBurstSnapNum) + && (mCameraState != LONGSHOT)){ + mFocusManager.resetTouchFocus(); + if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals( + mFocusManager.getFocusMode())) { + mCameraDevice.cancelAutoFocus(); + } + mUI.resumeFaceDetection(); + setCameraState(IDLE); } ExifInterface exif = Exif.getExif(jpegData); int orientation = Exif.getOrientation(exif); if (!mIsImageCaptureIntent) { + // Burst snapshot. Generate new image name. + if (mReceivedSnapNum > 1) + mNamedImages.nameNewImage(mCaptureStartTime); + // Calculate the width and the height of the jpeg. Size s = mParameters.getPictureSize(); int width, height; @@ -732,6 +1043,19 @@ public class PhotoModule width = s.height; height = s.width; } + + String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT); + if (pictureFormat != null && !pictureFormat.equalsIgnoreCase(PIXEL_FORMAT_JPEG)) { + // overwrite width and height if raw picture + String pair = mParameters.get(KEY_QC_RAW_PICUTRE_SIZE); + if (pair != null) { + int pos = pair.indexOf('x'); + if (pos != -1) { + width = Integer.parseInt(pair.substring(0, pos)); + height = Integer.parseInt(pair.substring(pos + 1)); + } + } + } NamedEntity name = mNamedImages.getNextNameEntity(); String title = (name == null) ? null : name.title; long date = (name == null) ? -1 : name.date; @@ -762,12 +1086,22 @@ public class PhotoModule exif.setTag(directionRefTag); exif.setTag(directionTag); } + String mPictureFormat = mParameters.get(KEY_PICTURE_FORMAT); mActivity.getMediaSaveService().addImage( jpegData, title, date, mLocation, width, height, - orientation, exif, mOnMediaSavedListener, mContentResolver); + orientation, exif, mOnMediaSavedListener, mContentResolver, mPictureFormat); } // Animate capture with real jpeg data instead of a preview frame. - mUI.animateCapture(jpegData, orientation, mMirror); + if (mCameraState != LONGSHOT) { + Size pic_size = mParameters.getPictureSize(); + if ((pic_size.width <= 352) && (pic_size.height<= 288)) { + mUI.setDownFactor(2); //Downsample by 2 for CIF & below + } + else { + mUI.setDownFactor(4); + } + mUI.animateCapture(jpegData, orientation, mMirror); + } } else { mJpegImageData = jpegData; if (!mQuickCapture) { @@ -787,10 +1121,69 @@ public class PhotoModule mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; Log.v(TAG, "mJpegCallbackFinishTime = " + mJpegCallbackFinishTime + "ms"); - mJpegPictureCallbackTime = 0; + + if (mReceivedSnapNum == mBurstSnapNum) + mJpegPictureCallbackTime = 0; + + if (mHiston && (mSnapshotMode ==CameraInfo.CAMERA_SUPPORT_MODE_ZSL)) { + mActivity.runOnUiThread(new Runnable() { + public void run() { + if (mGraphView != null) { + mGraphView.setVisibility(View.VISIBLE); + mGraphView.PreviewChanged(); + } + } + }); + } + if (mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL && + mCameraState != LONGSHOT && + mReceivedSnapNum == mBurstSnapNum) { + cancelAutoFocus(); + } } } + private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { + public void onStartTrackingTouch(SeekBar bar) { + // no support + } + public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) { + } + public void onStopTrackingTouch(SeekBar bar) { + } + }; + + private OnSeekBarChangeListener mskinToneSeekListener = new OnSeekBarChangeListener() { + public void onStartTrackingTouch(SeekBar bar) { + // no support + } + public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) { + int value = (progress + MIN_SCE_FACTOR) * SCE_FACTOR_STEP; + if(progress > (MAX_SCE_FACTOR - MIN_SCE_FACTOR)/2){ + RightValue.setText(String.valueOf(value)); + LeftValue.setText(""); + } else if (progress < (MAX_SCE_FACTOR - MIN_SCE_FACTOR)/2){ + LeftValue.setText(String.valueOf(value)); + RightValue.setText(""); + } else { + LeftValue.setText(""); + RightValue.setText(""); + } + if (value != mskinToneValue && mCameraDevice != null) { + mskinToneValue = value; + Message msg = mHandler.obtainMessage(CONFIGURE_SKIN_TONE_FACTOR, mskinToneValue, 0); + mHandler.sendMessage(msg); + } + } + + public void onStopTrackingTouch(SeekBar bar) { + Log.v(TAG, "Set onStopTrackingTouch mskinToneValue = " + mskinToneValue); + Editor editor = mPreferences.edit(); + editor.putString(CameraSettings.KEY_SKIN_TONE_ENHANCEMENT_FACTOR, + Integer.toString(mskinToneValue)); + editor.apply(); + } + }; private final class AutoFocusCallback implements CameraAFCallback { @Override public void onAutoFocus( @@ -799,7 +1192,16 @@ public class PhotoModule mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime; Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); - setCameraState(IDLE); + //don't reset the camera state while capture is in progress + //otherwise, it might result in another takepicture + switch (mCameraState) { + case PhotoController.LONGSHOT: + case SNAPSHOT_IN_PROGRESS: + break; + default: + setCameraState(IDLE); + break; + } mFocusManager.onAutoFocus(focused, mUI.isShutterPressed()); } } @@ -851,6 +1253,7 @@ public class PhotoModule switch (state) { case PhotoController.PREVIEW_STOPPED: case PhotoController.SNAPSHOT_IN_PROGRESS: + case PhotoController.LONGSHOT: case PhotoController.SWITCHING_CAMERA: mUI.enableGestures(false); break; @@ -884,6 +1287,18 @@ public class PhotoModule mJpegImageData = null; final boolean animateBefore = (mSceneMode == CameraUtil.SCENE_MODE_HDR); + if(mHiston) { + if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { + mHiston = false; + mCameraDevice.setHistogramMode(null); + } + mActivity.runOnUiThread(new Runnable() { + public void run() { + if(mGraphView != null) + mGraphView.setVisibility(View.INVISIBLE); + } + }); + } if (animateBefore) { animateAfterShutter(); @@ -900,22 +1315,55 @@ public class PhotoModule } mJpegRotation = CameraUtil.getJpegRotation(mCameraId, orientation); mParameters.setRotation(mJpegRotation); - Location loc = mLocationManager.getCurrentLocation(); + String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT); + Location loc = null; + if (pictureFormat != null && + PIXEL_FORMAT_JPEG.equalsIgnoreCase(pictureFormat)) { + loc = mLocationManager.getCurrentLocation(); + } CameraUtil.setGpsParameters(mParameters, loc); mCameraDevice.setParameters(mParameters); + mParameters = mCameraDevice.getParameters(); + + mBurstSnapNum = mParameters.getInt("num-snaps-per-shutter"); + mReceivedSnapNum = 0; + mPreviewRestartSupport = SystemProperties.getBoolean( + PERSIST_PREVIEW_RESTART, false); + mPreviewRestartSupport &= CameraSettings.isInternalPreviewSupported( + mParameters); + mPreviewRestartSupport &= (mBurstSnapNum == 1); + mPreviewRestartSupport &= PIXEL_FORMAT_JPEG.equalsIgnoreCase( + pictureFormat); // We don't want user to press the button again while taking a // multi-second HDR photo. mUI.enableShutter(false); - mCameraDevice.takePicture(mHandler, - new ShutterCallback(!animateBefore), - mRawPictureCallback, mPostViewPictureCallback, - new JpegPictureCallback(loc)); + + if (mCameraState == LONGSHOT) { + if(mLongshotSave) { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new LongshotPictureCallback(loc)); + } else { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(loc)); + } + } else { + mCameraDevice.takePicture(mHandler, + new ShutterCallback(!animateBefore), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(loc)); + setCameraState(SNAPSHOT_IN_PROGRESS); + } mNamedImages.nameNewImage(mCaptureStartTime); - mFaceDetectionStarted = false; - setCameraState(SNAPSHOT_IN_PROGRESS); + if (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { + mFaceDetectionStarted = false; + } UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_CAPTURE_DONE, "Photo", 0, UsageStatistics.hashFileName(mNamedImages.mQueue.lastElement().title + ".jpg")); @@ -938,29 +1386,168 @@ public class PhotoModule } } - private void updateSceneMode() { - // If scene mode is set, we cannot set flash mode, white balance, and - // focus mode, instead, we read it from driver + private void updateCameraSettings() { + String sceneMode = null; + String flashMode = null; + String redeyeReduction = null; + String aeBracketing = null; + String focusMode = null; + String colorEffect = null; + String exposureCompensation = null; + String touchAfAec = null; + + String ubiFocusOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_ubifocus_on); + String continuousShotOn = + mActivity.getString(R.string.setting_on_value); + String chromaFlashOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_chromaflash_on); + String optiZoomOn = mActivity.getString(R.string. + pref_camera_advanced_feature_value_optizoom_on); + String optiZoom = + mParameters.get(CameraSettings.KEY_QC_OPTI_ZOOM); + String chromaFlash = + mParameters.get(CameraSettings.KEY_QC_CHROMA_FLASH); + String ubiFocus = + mParameters.get(CameraSettings.KEY_QC_AF_BRACKETING); + String continuousShot = + mParameters.get("long-shot"); + + if ((continuousShot != null) && continuousShot.equals(continuousShotOn)) { + String pictureFormat = mActivity.getString(R.string. + pref_camera_picture_format_value_jpeg); + mUI.overrideSettings(CameraSettings.KEY_PICTURE_FORMAT, pictureFormat); + } else { + mUI.overrideSettings(CameraSettings.KEY_PICTURE_FORMAT, null); + } + if ((ubiFocus != null && ubiFocus.equals(ubiFocusOn)) || + (chromaFlash != null && chromaFlash.equals(chromaFlashOn)) || + (optiZoom != null && optiZoom.equals(optiZoomOn))) { + mSceneMode = sceneMode = Parameters.SCENE_MODE_AUTO; + flashMode = Parameters.FLASH_MODE_OFF; + focusMode = Parameters.FOCUS_MODE_INFINITY; + redeyeReduction = mActivity.getString(R.string. + pref_camera_redeyereduction_entry_disable); + aeBracketing = mActivity.getString(R.string. + pref_camera_ae_bracket_hdr_entry_off); + colorEffect = mActivity.getString(R.string. + pref_camera_coloreffect_default); + exposureCompensation = CameraSettings.EXPOSURE_DEFAULT_VALUE; + + overrideCameraSettings(flashMode, null, focusMode, + exposureCompensation, touchAfAec, null, + null, null, null, colorEffect, + sceneMode, redeyeReduction, aeBracketing); + } + + // If scene mode is set, for flash mode, white balance and focus mode + // read settings from preferences so we retain user preferences. if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { - overrideCameraSettings(mParameters.getFlashMode(), - mParameters.getWhiteBalance(), mParameters.getFocusMode()); + flashMode = mPreferences.getString( + CameraSettings.KEY_FLASH_MODE, + mActivity.getString(R.string.pref_camera_flashmode_default)); + String whiteBalance = mPreferences.getString( + CameraSettings.KEY_WHITE_BALANCE, + mActivity.getString(R.string.pref_camera_whitebalance_default)); + focusMode = mFocusManager.getFocusMode(); + colorEffect = mParameters.getColorEffect(); + exposureCompensation = + Integer.toString(mParameters.getExposureCompensation()); + touchAfAec = mCurrTouchAfAec; + + overrideCameraSettings(flashMode, whiteBalance, focusMode, + exposureCompensation, touchAfAec, + mParameters.getAutoExposure(), + Integer.toString(mParameters.getSaturation()), + Integer.toString(mParameters.getContrast()), + Integer.toString(mParameters.getSharpness()), + colorEffect, + sceneMode, redeyeReduction, aeBracketing); + if (CameraUtil.SCENE_MODE_HDR.equals(mSceneMode)) { + mUI.overrideSettings(CameraSettings.KEY_LONGSHOT, + mActivity.getString(R.string.setting_off_value)); + } + } else if (mFocusManager.isZslEnabled()) { + focusMode = mParameters.getFocusMode(); + overrideCameraSettings(flashMode, null, focusMode, + exposureCompensation, touchAfAec, null, + null, null, null, colorEffect, + sceneMode, redeyeReduction, aeBracketing); } else { - overrideCameraSettings(null, null, null); + overrideCameraSettings(flashMode, null, focusMode, + exposureCompensation, touchAfAec, null, + null, null, null, colorEffect, + sceneMode, redeyeReduction, aeBracketing); + } + /* Disable focus if aebracket is ON */ + String aeBracket = mParameters.get(CameraSettings.KEY_QC_AE_BRACKETING); + if (!aeBracket.equalsIgnoreCase("off")) { + String fMode = Parameters.FLASH_MODE_OFF; + mUI.overrideSettings(CameraSettings.KEY_FLASH_MODE, fMode); + mParameters.setFlashMode(fMode); + } + if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { + mUI.overrideSettings(CameraSettings.KEY_LONGSHOT, null); } } private void overrideCameraSettings(final String flashMode, - final String whiteBalance, final String focusMode) { + final String whiteBalance, final String focusMode, + final String exposureMode, final String touchMode, + final String autoExposure, final String saturation, + final String contrast, final String sharpness, + final String coloreffect, final String sceneMode, + final String redeyeReduction, final String aeBracketing) { mUI.overrideSettings( CameraSettings.KEY_FLASH_MODE, flashMode, CameraSettings.KEY_WHITE_BALANCE, whiteBalance, - CameraSettings.KEY_FOCUS_MODE, focusMode); + CameraSettings.KEY_FOCUS_MODE, focusMode, + CameraSettings.KEY_EXPOSURE, exposureMode, + CameraSettings.KEY_TOUCH_AF_AEC, touchMode, + CameraSettings.KEY_AUTOEXPOSURE, autoExposure, + CameraSettings.KEY_SATURATION, saturation, + CameraSettings.KEY_CONTRAST, contrast, + CameraSettings.KEY_SHARPNESS, sharpness, + CameraSettings.KEY_COLOR_EFFECT, coloreffect, + CameraSettings.KEY_SCENE_MODE, sceneMode, + CameraSettings.KEY_REDEYE_REDUCTION, redeyeReduction, + CameraSettings.KEY_AE_BRACKET_HDR, aeBracketing); } private void loadCameraPreferences() { CameraSettings settings = new CameraSettings(mActivity, mInitialParams, mCameraId, CameraHolder.instance().getCameraInfo()); mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences); + + int numOfCams = Camera.getNumberOfCameras(); + int backCamId = CameraHolder.instance().getBackCameraId(); + int frontCamId = CameraHolder.instance().getFrontCameraId(); + // We need to swap the list preference contents if back camera and front camera + // IDs are not 0 and 1 respectively + if ((numOfCams == 2) && ((backCamId != CameraInfo.CAMERA_FACING_BACK) + || (frontCamId != CameraInfo.CAMERA_FACING_FRONT))) { + Log.e(TAG,"loadCameraPreferences() updating camera_id pref"); + + IconListPreference switchIconPref = + (IconListPreference)mPreferenceGroup.findPreference( + CameraSettings.KEY_CAMERA_ID); + + int[] iconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back}; + switchIconPref.setIconIds(iconIds); + + String[] entries = {mActivity.getResources().getString( + R.string.pref_camera_id_entry_front), mActivity.getResources(). + getString(R.string.pref_camera_id_entry_back)}; + switchIconPref.setEntries(entries); + + String[] labels = {mActivity.getResources().getString( + R.string.pref_camera_id_label_front), mActivity.getResources(). + getString(R.string.pref_camera_id_label_back)}; + switchIconPref.setLabels(labels); + + int[] largeIconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back}; + switchIconPref.setLargeIconIds(largeIconIds); + } } @Override @@ -969,13 +1556,27 @@ public class PhotoModule // the camera then point the camera to floor or sky, we still have // the correct orientation. if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return; + int oldOrientation = mOrientation; mOrientation = CameraUtil.roundOrientation(orientation, mOrientation); + if (oldOrientation != mOrientation) { + Log.v(TAG, "onOrientationChanged, update parameters"); + if (mParameters != null && mCameraDevice != null) { + onSharedPreferenceChanged(); + } + } // Show the toast after getting the first orientation changed. if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) { mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST); showTapToFocusToast(); } + + // need to re-initialize mGraphView to show histogram on rotate + mGraphView = (GraphView)mRootView.findViewById(R.id.graph_view); + if(mGraphView != null){ + mGraphView.setPhotoModuleObject(this); + mGraphView.PreviewChanged(); + } } @Override @@ -1089,6 +1690,23 @@ public class PhotoModule || (mCameraState == SNAPSHOT_IN_PROGRESS) || (mCameraState == PREVIEW_STOPPED)) return; + synchronized(mCameraDevice) { + if (mCameraState == LONGSHOT) { + mCameraDevice.setLongshot(false); + if (!mFocusManager.isZslEnabled()) { + setupPreview(); + } else { + setCameraState(IDLE); + mFocusManager.resetTouchFocus(); + if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals( + mFocusManager.getFocusMode())) { + mCameraDevice.cancelAutoFocus(); + } + mUI.resumeFaceDetection(); + } + } + } + // Do not do focus if there is not enough storage. if (pressed && !canTakePicture()) return; @@ -1121,6 +1739,14 @@ public class PhotoModule mUI.hideSwitcher(); mUI.setSwipingEnabled(false); } + + //Need to disable focus for ZSL mode + if(mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { + mFocusManager.setZslEnable(true); + } else { + mFocusManager.setZslEnable(false); + } + // If the user wants to do a snapshot while the previous one is still // in progress, remember the fact and do it after we finish the previous // one and re-start the preview. Snapshot in progress also includes the @@ -1146,6 +1772,9 @@ public class PhotoModule mUI.cancelCountDown(); } if (seconds > 0) { + String zsl = mPreferences.getString(CameraSettings.KEY_ZSL, + mActivity.getString(R.string.pref_camera_zsl_default)); + mUI.overrideSettings(CameraSettings.KEY_ZSL, zsl); mUI.startCountDown(seconds, playSound); } else { mSnapshotOnIdle = false; @@ -1154,6 +1783,32 @@ public class PhotoModule } @Override + public void onShutterButtonLongClick() { + // Do not take the picture if there is not enough storage. + if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) { + Log.i(TAG, "Not enough space or storage not ready. remaining=" + + mActivity.getStorageSpaceBytes()); + return; + } + + if ((null != mCameraDevice) && ((mCameraState == IDLE) || (mCameraState == FOCUSING))) { + //Add on/off Menu for longshot + String longshot_enable = mPreferences.getString( + CameraSettings.KEY_LONGSHOT, + mActivity.getString(R.string.pref_camera_longshot_default)); + + Log.d(TAG, "longshot_enable = " + longshot_enable); + if (longshot_enable.equals("on")) { + boolean enable = SystemProperties.getBoolean(PERSIST_LONG_SAVE, false); + mLongshotSave = enable; + mCameraDevice.setLongshot(true); + setCameraState(PhotoController.LONGSHOT); + mFocusManager.doSnap(); + } + } + } + + @Override public void installIntentFilter() { // Do nothing. } @@ -1212,6 +1867,12 @@ public class PhotoModule Log.v(TAG, "On resume."); onResumeTasks(); } + mHandler.post(new Runnable(){ + @Override + public void run(){ + mActivity.updateStorageSpaceAndHint(); + } + }); } private void onResumeTasks() { @@ -1226,6 +1887,11 @@ public class PhotoModule return; } + if (mSkinToneSeekBar != true) + { + Log.v(TAG, "Send tone bar: mSkinToneSeekBar = " + mSkinToneSeekBar); + mHandler.sendEmptyMessage(SET_SKIN_TONE_FACTOR); + } // If first time initialization is not finished, put it in the // message queue. if (!mFirstTimeInitialized) { @@ -1262,6 +1928,9 @@ public class PhotoModule if (msensor != null) { mSensorManager.unregisterListener(this, msensor); } + + Log.d(TAG, "remove idle handleer in onPause"); + removeIdleHandler(); } @Override @@ -1329,6 +1998,7 @@ public class PhotoModule public void onConfigurationChanged(Configuration newConfig) { Log.v(TAG, "onConfigurationChanged"); setDisplayOrientation(); + resizeForPreviewAspectRatio(); } @Override @@ -1361,6 +2031,10 @@ public class PhotoModule } } + protected CameraManager.CameraProxy getCamera() { + return mCameraDevice; + } + private boolean canTakePicture() { return isCameraIdle() && (mActivity.getStorageSpaceBytes() > Storage.LOW_STORAGE_THRESHOLD_BYTES); } @@ -1374,9 +2048,11 @@ public class PhotoModule @Override public void cancelAutoFocus() { - mCameraDevice.cancelAutoFocus(); - setCameraState(IDLE); - setCameraParameters(UPDATE_PARAM_PREFERENCE); + if (null != mCameraDevice ) { + mCameraDevice.cancelAutoFocus(); + setCameraState(IDLE); + setCameraParameters(UPDATE_PARAM_PREFERENCE); + } } // Preview area is touched. Handle touch focus. @@ -1388,7 +2064,10 @@ public class PhotoModule || mCameraState == PREVIEW_STOPPED) { return; } - + //If Touch AF/AEC is disabled in UI, return + if(this.mTouchAfAecFlag == false) { + return; + } // Check if metering area or focus area is supported. if (!mFocusAreaSupported && !mMeteringAreaSupported) return; mFocusManager.onSingleTapUp(x, y); @@ -1417,6 +2096,40 @@ public class PhotoModule onShutterButtonClick(); } return true; + case KeyEvent.KEYCODE_DPAD_LEFT: + if ( (mCameraState != PREVIEW_STOPPED) && + (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING) && + (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING_SNAP_ON_FINISH) ) { + if (mbrightness > MINIMUM_BRIGHTNESS) { + mbrightness-=mbrightness_step; + synchronized (mCameraDevice) { + /* Set the "luma-adaptation" parameter */ + mParameters = mCameraDevice.getParameters(); + mParameters.set("luma-adaptation", String.valueOf(mbrightness)); + mCameraDevice.setParameters(mParameters); + } + } + brightnessProgressBar.setProgress(mbrightness); + brightnessProgressBar.setVisibility(View.VISIBLE); + } + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if ( (mCameraState != PREVIEW_STOPPED) && + (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING) && + (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING_SNAP_ON_FINISH) ) { + if (mbrightness < MAXIMUM_BRIGHTNESS) { + mbrightness+=mbrightness_step; + synchronized (mCameraDevice) { + /* Set the "luma-adaptation" parameter */ + mParameters = mCameraDevice.getParameters(); + mParameters.set("luma-adaptation", String.valueOf(mbrightness)); + mCameraDevice.setParameters(mParameters); + } + } + brightnessProgressBar.setProgress(mbrightness); + brightnessProgressBar.setVisibility(View.VISIBLE); + } + break; case KeyEvent.KEYCODE_DPAD_CENTER: // If we get a dpad center event without any focused view, move // the focus to the shutter button and press it. @@ -1547,7 +2260,6 @@ public class PhotoModule if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { Log.v(TAG, "stopPreview"); mCameraDevice.stopPreview(); - mFaceDetectionStarted = false; } setCameraState(PREVIEW_STOPPED); if (mFocusManager != null) mFocusManager.onPreviewStopped(); @@ -1577,10 +2289,402 @@ public class PhotoModule private void updateCameraParametersZoom() { // Set zoom. if (mParameters.isZoomSupported()) { + Parameters p = mCameraDevice.getParameters(); + mZoomValue = p.getZoom(); mParameters.setZoom(mZoomValue); } } + private boolean needRestart() { + mRestartPreview = false; + String zsl = mPreferences.getString(CameraSettings.KEY_ZSL, + mActivity.getString(R.string.pref_camera_zsl_default)); + if(zsl.equals("on") && mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL + && mCameraState != PREVIEW_STOPPED) { + //Switch on ZSL Camera mode + Log.v(TAG, "Switching to ZSL Camera Mode. Restart Preview"); + mRestartPreview = true; + return mRestartPreview; + } + if(zsl.equals("off") && mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_NONZSL + && mCameraState != PREVIEW_STOPPED) { + //Switch on Normal Camera mode + Log.v(TAG, "Switching to Normal Camera Mode. Restart Preview"); + mRestartPreview = true; + return mRestartPreview; + } + return mRestartPreview; + } + + private void qcomUpdateAdvancedFeatures(String ubiFocus, + String chromaFlash, + String optiZoom) { + if (CameraUtil.isSupported(ubiFocus, + CameraSettings.getSupportedAFBracketingModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_AF_BRACKETING, ubiFocus); + } + if (CameraUtil.isSupported(chromaFlash, + CameraSettings.getSupportedChromaFlashModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_CHROMA_FLASH, chromaFlash); + } + if (CameraUtil.isSupported(optiZoom, + CameraSettings.getSupportedOptiZoomModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_OPTI_ZOOM, optiZoom); + } + } + private void qcomUpdateCameraParametersPreference() { + //qcom Related Parameter update + //Set Brightness. + mParameters.set("luma-adaptation", String.valueOf(mbrightness)); + + String longshot_enable = mPreferences.getString( + CameraSettings.KEY_LONGSHOT, + mActivity.getString(R.string.pref_camera_longshot_default)); + mParameters.set("long-shot", longshot_enable); + + if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode) || + CameraUtil.SCENE_MODE_HDR.equals(mSceneMode)) { + // Set Touch AF/AEC parameter. + String touchAfAec = mPreferences.getString( + CameraSettings.KEY_TOUCH_AF_AEC, + mActivity.getString(R.string.pref_camera_touchafaec_default)); + if (CameraUtil.isSupported(touchAfAec, mParameters.getSupportedTouchAfAec())) { + mCurrTouchAfAec = touchAfAec; + mParameters.setTouchAfAec(touchAfAec); + } + } else { + mParameters.setTouchAfAec(mParameters.TOUCH_AF_AEC_OFF); + mFocusManager.resetTouchFocus(); + } + try { + if(mParameters.getTouchAfAec().equals(mParameters.TOUCH_AF_AEC_ON)) + this.mTouchAfAecFlag = true; + else + this.mTouchAfAecFlag = false; + } catch(Exception e){ + Log.e(TAG, "Handled NULL pointer Exception"); + } + + // Set Picture Format + // Picture Formats specified in UI should be consistent with + // PIXEL_FORMAT_JPEG and PIXEL_FORMAT_RAW constants + String pictureFormat = mPreferences.getString( + CameraSettings.KEY_PICTURE_FORMAT, + mActivity.getString(R.string.pref_camera_picture_format_default)); + + //Change picture format to JPEG if camera is start from other APK by intent. + if (mIsImageCaptureIntent && !pictureFormat.equals(PIXEL_FORMAT_JPEG)) { + pictureFormat = PIXEL_FORMAT_JPEG; + Editor editor = mPreferences.edit(); + editor.putString(CameraSettings.KEY_PICTURE_FORMAT, + mActivity.getString(R.string.pref_camera_picture_format_value_jpeg)); + editor.apply(); + } + Log.v(TAG, "Picture format value =" + pictureFormat); + mParameters.set(KEY_PICTURE_FORMAT, pictureFormat); + + // Set JPEG quality. + String jpegQuality = mPreferences.getString( + CameraSettings.KEY_JPEG_QUALITY, + mActivity.getString(R.string.pref_camera_jpegquality_default)); + //mUnsupportedJpegQuality = false; + Size pic_size = mParameters.getPictureSize(); + if (pic_size == null) { + Log.e(TAG, "error getPictureSize: size is null"); + } + else{ + if("100".equals(jpegQuality) && (pic_size.width >= 3200)){ + //mUnsupportedJpegQuality = true; + }else { + mParameters.setJpegQuality(JpegEncodingQualityMappings.getQualityNumber(jpegQuality)); + } + } + + // Set Selectable Zone Af parameter. + String selectableZoneAf = mPreferences.getString( + CameraSettings.KEY_SELECTABLE_ZONE_AF, + mActivity.getString(R.string.pref_camera_selectablezoneaf_default)); + List<String> str = mParameters.getSupportedSelectableZoneAf(); + if (CameraUtil.isSupported(selectableZoneAf, mParameters.getSupportedSelectableZoneAf())) { + mParameters.setSelectableZoneAf(selectableZoneAf); + } + + // Set wavelet denoise mode + if (mParameters.getSupportedDenoiseModes() != null) { + String Denoise = mPreferences.getString( CameraSettings.KEY_DENOISE, + mActivity.getString(R.string.pref_camera_denoise_default)); + mParameters.setDenoise(Denoise); + } + // Set Redeye Reduction + String redeyeReduction = mPreferences.getString( + CameraSettings.KEY_REDEYE_REDUCTION, + mActivity.getString(R.string.pref_camera_redeyereduction_default)); + if (CameraUtil.isSupported(redeyeReduction, + mParameters.getSupportedRedeyeReductionModes())) { + mParameters.setRedeyeReductionMode(redeyeReduction); + } + // Set ISO parameter + String iso = mPreferences.getString( + CameraSettings.KEY_ISO, + mActivity.getString(R.string.pref_camera_iso_default)); + if (CameraUtil.isSupported(iso, + mParameters.getSupportedIsoValues())) { + mParameters.setISOValue(iso); + } + // Set color effect parameter. + String colorEffect = mPreferences.getString( + CameraSettings.KEY_COLOR_EFFECT, + mActivity.getString(R.string.pref_camera_coloreffect_default)); + Log.v(TAG, "Color effect value =" + colorEffect); + if (CameraUtil.isSupported(colorEffect, mParameters.getSupportedColorEffects())) { + mParameters.setColorEffect(colorEffect); + } + //Set Saturation + String saturationStr = mPreferences.getString( + CameraSettings.KEY_SATURATION, + mActivity.getString(R.string.pref_camera_saturation_default)); + int saturation = Integer.parseInt(saturationStr); + Log.v(TAG, "Saturation value =" + saturation); + if((0 <= saturation) && (saturation <= mParameters.getMaxSaturation())){ + mParameters.setSaturation(saturation); + } + // Set contrast parameter. + String contrastStr = mPreferences.getString( + CameraSettings.KEY_CONTRAST, + mActivity.getString(R.string.pref_camera_contrast_default)); + int contrast = Integer.parseInt(contrastStr); + Log.v(TAG, "Contrast value =" +contrast); + if((0 <= contrast) && (contrast <= mParameters.getMaxContrast())){ + mParameters.setContrast(contrast); + } + // Set sharpness parameter + String sharpnessStr = mPreferences.getString( + CameraSettings.KEY_SHARPNESS, + mActivity.getString(R.string.pref_camera_sharpness_default)); + int sharpness = Integer.parseInt(sharpnessStr) * + (mParameters.getMaxSharpness()/MAX_SHARPNESS_LEVEL); + Log.v(TAG, "Sharpness value =" + sharpness); + if((0 <= sharpness) && (sharpness <= mParameters.getMaxSharpness())){ + mParameters.setSharpness(sharpness); + } + // Set Face Recognition + String faceRC = mPreferences.getString( + CameraSettings.KEY_FACE_RECOGNITION, + mActivity.getString(R.string.pref_camera_facerc_default)); + Log.v(TAG, "Face Recognition value = " + faceRC); + if (CameraUtil.isSupported(faceRC, + CameraSettings.getSupportedFaceRecognitionModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_FACE_RECOGNITION, faceRC); + } + // Set AE Bracketing + String aeBracketing = mPreferences.getString( + CameraSettings.KEY_AE_BRACKET_HDR, + mActivity.getString(R.string.pref_camera_ae_bracket_hdr_default)); + Log.v(TAG, "AE Bracketing value =" + aeBracketing); + if (CameraUtil.isSupported(aeBracketing, + CameraSettings.getSupportedAEBracketingModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_AE_BRACKETING, aeBracketing); + } + // Set Advanced features. + String advancedFeature = mPreferences.getString( + CameraSettings.KEY_ADVANCED_FEATURES, + mActivity.getString(R.string.pref_camera_advanced_feature_default)); + Log.v(TAG, " advancedFeature value =" + advancedFeature); + + if(advancedFeature != null) { + String ubiFocusOff = mActivity.getString(R.string. + pref_camera_advanced_feature_value_ubifocus_off); + String chromaFlashOff = mActivity.getString(R.string. + pref_camera_advanced_feature_value_chromaflash_off); + String optiZoomOff = mActivity.getString(R.string. + pref_camera_advanced_feature_value_optizoom_off); + + if (advancedFeature.equals(mActivity.getString(R.string. + pref_camera_advanced_feature_value_ubifocus_on))) { + qcomUpdateAdvancedFeatures(advancedFeature, + chromaFlashOff, + optiZoomOff); + } else if (advancedFeature.equals(mActivity.getString(R.string. + pref_camera_advanced_feature_value_chromaflash_on))) { + qcomUpdateAdvancedFeatures(ubiFocusOff, + advancedFeature, + optiZoomOff); + } else if (advancedFeature.equals(mActivity.getString(R.string. + pref_camera_advanced_feature_value_optizoom_on))) { + qcomUpdateAdvancedFeatures(ubiFocusOff, + chromaFlashOff, + advancedFeature); + } else { + qcomUpdateAdvancedFeatures(ubiFocusOff, + chromaFlashOff, + optiZoomOff); + } + } + // Set auto exposure parameter. + String autoExposure = mPreferences.getString( + CameraSettings.KEY_AUTOEXPOSURE, + mActivity.getString(R.string.pref_camera_autoexposure_default)); + Log.v(TAG, "autoExposure value =" + autoExposure); + if (CameraUtil.isSupported(autoExposure, mParameters.getSupportedAutoexposure())) { + mParameters.setAutoExposure(autoExposure); + } + + // Set anti banding parameter. + String antiBanding = mPreferences.getString( + CameraSettings.KEY_ANTIBANDING, + mActivity.getString(R.string.pref_camera_antibanding_default)); + Log.v(TAG, "antiBanding value =" + antiBanding); + if (CameraUtil.isSupported(antiBanding, mParameters.getSupportedAntibanding())) { + mParameters.setAntibanding(antiBanding); + } + + String zsl = mPreferences.getString(CameraSettings.KEY_ZSL, + mActivity.getString(R.string.pref_camera_zsl_default)); + mParameters.setZSLMode(zsl); + if(zsl.equals("on")) { + //Switch on ZSL Camera mode + mSnapshotMode = CameraInfo.CAMERA_SUPPORT_MODE_ZSL; + mParameters.setCameraMode(1); + mFocusManager.setZslEnable(true); + + //Raw picture format is not supported under ZSL mode + mParameters.set(KEY_PICTURE_FORMAT, PIXEL_FORMAT_JPEG); + Editor editor = mPreferences.edit(); + editor.putString(CameraSettings.KEY_PICTURE_FORMAT, mActivity.getString(R.string.pref_camera_picture_format_value_jpeg)); + editor.apply(); + mUI.overrideSettings(CameraSettings.KEY_PICTURE_FORMAT, mActivity.getString(R.string.pref_camera_picture_format_entry_jpeg)); + + //Try to set CAF for ZSL + if(CameraUtil.isSupported(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE, + mParameters.getSupportedFocusModes()) && !mFocusManager.isTouch()) { + mFocusManager.overrideFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + mParameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + } else if (mFocusManager.isTouch()) { + mFocusManager.overrideFocusMode(null); + mParameters.setFocusMode(mFocusManager.getFocusMode()); + } else { + // If not supported use the current mode + mFocusManager.overrideFocusMode(mFocusManager.getFocusMode()); + } + + if(!pictureFormat.equals(PIXEL_FORMAT_JPEG)) { + mActivity.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(mActivity, R.string.error_app_unsupported_raw, + Toast.LENGTH_SHORT).show(); + } + }); + } + } else if(zsl.equals("off")) { + mSnapshotMode = CameraInfo.CAMERA_SUPPORT_MODE_NONZSL; + mParameters.setCameraMode(0); + mFocusManager.setZslEnable(false); + mFocusManager.overrideFocusMode(null); + mParameters.setFocusMode(mFocusManager.getFocusMode()); + } + // Set face detetction parameter. + String faceDetection = mPreferences.getString( + CameraSettings.KEY_FACE_DETECTION, + mActivity.getString(R.string.pref_camera_facedetection_default)); + if (CameraUtil.isSupported(faceDetection, mParameters.getSupportedFaceDetectionModes())) { + mParameters.setFaceDetectionMode(faceDetection); + if(faceDetection.equals("on") && mFaceDetectionEnabled == false) { + mFaceDetectionEnabled = true; + startFaceDetection(); + } + if(faceDetection.equals("off") && mFaceDetectionEnabled == true) { + stopFaceDetection(); + mFaceDetectionEnabled = false; + } + } + // skin tone ie enabled only for auto,party and portrait BSM + // when color effects are not enabled + if((Parameters.SCENE_MODE_PARTY.equals(mSceneMode) || + Parameters.SCENE_MODE_PORTRAIT.equals(mSceneMode)) && + (Parameters.EFFECT_NONE.equals(colorEffect))) { + //Set Skin Tone Correction factor + Log.v(TAG, "set tone bar: mSceneMode = " + mSceneMode); + if(mSeekBarInitialized == true) + mHandler.sendEmptyMessage(SET_SKIN_TONE_FACTOR); + } + + //Set Histogram + String histogram = mPreferences.getString( + CameraSettings.KEY_HISTOGRAM, + mActivity.getString(R.string.pref_camera_histogram_default)); + if (CameraUtil.isSupported(histogram, + mParameters.getSupportedHistogramModes()) && mCameraDevice != null) { + // Call for histogram + if(histogram.equals("enable")) { + mActivity.runOnUiThread(new Runnable() { + public void run() { + if(mGraphView != null) { + mGraphView.setVisibility(View.VISIBLE); + mGraphView.PreviewChanged(); + } + } + }); + mCameraDevice.setHistogramMode(mStatsCallback); + mHiston = true; + } else { + mHiston = false; + mActivity.runOnUiThread(new Runnable() { + public void run() { + if (mGraphView != null) + mGraphView.setVisibility(View.INVISIBLE); + } + }); + mCameraDevice.setHistogramMode(null); + } + } + // Read Flip mode from adb command + //value: 0(default) - FLIP_MODE_OFF + //value: 1 - FLIP_MODE_H + //value: 2 - FLIP_MODE_V + //value: 3 - FLIP_MODE_VH + int preview_flip_value = SystemProperties.getInt("debug.camera.preview.flip", 0); + int video_flip_value = SystemProperties.getInt("debug.camera.video.flip", 0); + int picture_flip_value = SystemProperties.getInt("debug.camera.picture.flip", 0); + int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation); + mParameters.setRotation(rotation); + if (rotation == 90 || rotation == 270) { + // in case of 90 or 270 degree, V/H flip should reverse + if (preview_flip_value == 1) { + preview_flip_value = 2; + } else if (preview_flip_value == 2) { + preview_flip_value = 1; + } + if (video_flip_value == 1) { + video_flip_value = 2; + } else if (video_flip_value == 2) { + video_flip_value = 1; + } + if (picture_flip_value == 1) { + picture_flip_value = 2; + } else if (picture_flip_value == 2) { + picture_flip_value = 1; + } + } + String preview_flip = CameraUtil.getFilpModeString(preview_flip_value); + String video_flip = CameraUtil.getFilpModeString(video_flip_value); + String picture_flip = CameraUtil.getFilpModeString(picture_flip_value); + if(CameraUtil.isSupported(preview_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_PREVIEW_FLIP, preview_flip); + } + if(CameraUtil.isSupported(video_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_VIDEO_FLIP, video_flip); + } + if(CameraUtil.isSupported(picture_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_SNAPSHOT_PICTURE_FLIP, picture_flip); + } + /* Disable focus if aebracket is ON */ + String aeBracket = mParameters.get(CameraSettings.KEY_QC_AE_BRACKETING); + if (!aeBracket.equalsIgnoreCase("off")) { + String fMode = Parameters.FLASH_MODE_OFF; + mUI.overrideSettings(CameraSettings.KEY_FLASH_MODE, fMode); + mParameters.setFlashMode(fMode); + } + } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void setAutoExposureLockIfSupported() { if (mAeLockSupported) { @@ -1623,9 +2727,19 @@ public class PhotoModule if (pictureSize == null) { CameraSettings.initialCameraPictureSize(mActivity, mParameters); } else { + Size old_size = mParameters.getPictureSize(); + Log.v(TAG, "old picture_size = " + old_size.width + " x " + old_size.height); List<Size> supported = mParameters.getSupportedPictureSizes(); CameraSettings.setCameraPictureSize( pictureSize, supported, mParameters); + Size size = mParameters.getPictureSize(); + Log.v(TAG, "new picture_size = " + size.width + " x " + size.height); + if (old_size != null && size != null) { + if(!size.equals(old_size) && mCameraState != PREVIEW_STOPPED) { + Log.v(TAG, "Picture Size changed. Restart Preview"); + mRestartPreview = true; + } + } } Size size = mParameters.getPictureSize(); @@ -1647,12 +2761,10 @@ public class PhotoModule mCameraDevice.setParameters(mParameters); } mParameters = mCameraDevice.getParameters(); + Log.v(TAG, "Preview Size changed. Restart Preview"); + mRestartPreview = true; } - if(optimalSize.width != 0 && optimalSize.height != 0) { - mUI.updatePreviewAspectRatio((float) optimalSize.width - / (float) optimalSize.height); - } Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height); // Since changing scene mode may change supported values, set scene mode @@ -1673,6 +2785,11 @@ public class PhotoModule } else { if (hdrOn) { mSceneMode = CameraUtil.SCENE_MODE_HDR; + if (!(Parameters.SCENE_MODE_AUTO).equals(mParameters.getSceneMode())) { + mParameters.setSceneMode(Parameters.SCENE_MODE_AUTO); + mCameraDevice.setParameters(mParameters); + mParameters = mCameraDevice.getParameters(); + } } else { mSceneMode = mPreferences.getString( CameraSettings.KEY_SCENE_MODE, @@ -1749,12 +2866,15 @@ public class PhotoModule mParameters.setFocusMode(mFocusManager.getFocusMode()); } else { mFocusManager.overrideFocusMode(mParameters.getFocusMode()); + if (hdrOn) + mParameters.setFlashMode(Parameters.FLASH_MODE_OFF); } if (mContinuousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { updateAutoFocusMoveCallback(); } - + //QCom related parameters updated here. + qcomUpdateCameraParametersPreference(); return doGcamModeSwitch; } @@ -1772,25 +2892,27 @@ public class PhotoModule // the subsets actually need updating. The PREFERENCE set needs extra // locking because the preference can be changed from GLThread as well. private void setCameraParameters(int updateSet) { - boolean doModeSwitch = false; + synchronized (mCameraDevice) { + boolean doModeSwitch = false; - if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) { - updateCameraParametersInitialize(); - } + if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) { + updateCameraParametersInitialize(); + } - if ((updateSet & UPDATE_PARAM_ZOOM) != 0) { - updateCameraParametersZoom(); - } + if ((updateSet & UPDATE_PARAM_ZOOM) != 0) { + updateCameraParametersZoom(); + } - if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) { - doModeSwitch = updateCameraParametersPreference(); - } + if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) { + doModeSwitch = updateCameraParametersPreference(); + } - mCameraDevice.setParameters(mParameters); + mCameraDevice.setParameters(mParameters); - // Switch to gcam module if HDR+ was selected - if (doModeSwitch && !mIsImageCaptureIntent) { - mHandler.sendEmptyMessage(SWITCH_TO_GCAM_MODULE); + // Switch to gcam module if HDR+ was selected + if (doModeSwitch && !mIsImageCaptureIntent) { + mHandler.sendEmptyMessage(SWITCH_TO_GCAM_MODULE); + } } } @@ -1805,7 +2927,15 @@ public class PhotoModule return; } else if (isCameraIdle()) { setCameraParameters(mUpdateSet); - updateSceneMode(); + if(mRestartPreview && mCameraState != PREVIEW_STOPPED) { + Log.v(TAG, "Restarting Preview..."); + stopPreview(); + resizeForPreviewAspectRatio(); + startPreview(); + setCameraState(IDLE); + } + mRestartPreview = false; + updateCameraSettings(); mUpdateSet = 0; } else { if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) { @@ -1838,6 +2968,30 @@ public class PhotoModule } } + // 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())); + } + + @Override + public void onSharedPreferenceChanged(ListPreference pref) { + // ignore the events after "onPause()" + if (mPaused) return; + + //filter off unsupported settings + final String settingOff = mActivity.getString(R.string.setting_off_value); + if (!CameraSettings.isZSLHDRSupported(mParameters)) { + if (notSame(pref, CameraSettings.KEY_CAMERA_HDR, settingOff)) { + mUI.setPreference(CameraSettings.KEY_ZSL,settingOff); + } else if (notSame(pref,CameraSettings.KEY_ZSL,settingOff)) { + mUI.setPreference(CameraSettings.KEY_CAMERA_HDR, settingOff); + } + } + + //call generic onSharedPreferenceChanged + onSharedPreferenceChanged(); + } + @Override public void onSharedPreferenceChanged() { // ignore the events after "onPause()" @@ -1846,9 +3000,44 @@ public class PhotoModule boolean recordLocation = RecordLocationPreference.get( mPreferences, mContentResolver); mLocationManager.recordLocation(recordLocation); - - setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); - mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences); + if(needRestart()){ + Log.v(TAG, "Restarting Preview... Camera Mode Changhed"); + stopPreview(); + startPreview(); + setCameraState(IDLE); + mRestartPreview = false; + } + /* Check if the PhotoUI Menu is initialized or not. This + * should be initialized during onCameraOpen() which should + * have been called by now. But for some reason that is not + * executed till now, then schedule these functionality for + * later by posting a message to the handler */ + if (mUI.mMenuInitialized) { + setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); + mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, + mPreferences); + } else { + mHandler.sendEmptyMessage(SET_PHOTO_UI_PARAMS); + } + resizeForPreviewAspectRatio(); + if (mSeekBarInitialized == true){ + Log.v(TAG, "onSharedPreferenceChanged Skin tone bar: change"); + // skin tone is enabled only for party and portrait BSM + // when color effects are not enabled + String colorEffect = mPreferences.getString( + CameraSettings.KEY_COLOR_EFFECT, + mActivity.getString(R.string.pref_camera_coloreffect_default)); + if((Parameters.SCENE_MODE_PARTY.equals(mSceneMode) || + Parameters.SCENE_MODE_PORTRAIT.equals(mSceneMode)) && + (Parameters.EFFECT_NONE.equals(colorEffect))) { + Log.v(TAG, "Party/Portrait + No effect, SkinToneBar enabled"); + } else { + disableSkinToneSeekBar(); + } + } + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + mActivity.updateStorageSpaceAndHint(); } @Override @@ -1921,6 +3110,7 @@ public class PhotoModule mSnapshotOnIdle = false; mFocusManager.doSnap(); mFocusManager.onShutterUp(); + mUI.overrideSettings(CameraSettings.KEY_ZSL, null); } @Override @@ -1988,12 +3178,91 @@ public class PhotoModule mHeading += 360; } } - @Override public void onPreviewFocusChanged(boolean previewFocused) { mUI.onPreviewFocusChanged(previewFocused); } + // TODO: Delete this function after old camera code is removed + @Override + public void onRestorePreferencesClicked() {} + private void setSkinToneFactor() { + if(mCameraDevice == null || mParameters == null || skinToneSeekBar == null) + return; + + String skinToneEnhancementPref = "enable"; + if(CameraUtil.isSupported(skinToneEnhancementPref, + mParameters.getSupportedSkinToneEnhancementModes())) { + if(skinToneEnhancementPref.equals("enable")) { + int skinToneValue =0; + int progress; + //get the value for the first time! + if (mskinToneValue ==0) { + String factor = mPreferences.getString( + CameraSettings.KEY_SKIN_TONE_ENHANCEMENT_FACTOR, "0"); + skinToneValue = Integer.parseInt(factor); + } + + Log.v(TAG, "Skin tone bar: enable = " + mskinToneValue); + enableSkinToneSeekBar(); + //As a wrokaround set progress again to show the actually progress on screen. + if (skinToneValue != 0) { + progress = (skinToneValue/SCE_FACTOR_STEP)-MIN_SCE_FACTOR; + skinToneSeekBar.setProgress(progress); + } + } else { + Log.v(TAG, "Skin tone bar: disable"); + disableSkinToneSeekBar(); + } + } else { + Log.v(TAG, "Skin tone bar: Not supported"); + skinToneSeekBar.setVisibility(View.INVISIBLE); + } + } + private void enableSkinToneSeekBar() { + int progress; + if(brightnessProgressBar != null) + brightnessProgressBar.setVisibility(View.INVISIBLE); + skinToneSeekBar.setMax(MAX_SCE_FACTOR-MIN_SCE_FACTOR); + skinToneSeekBar.setVisibility(View.VISIBLE); + skinToneSeekBar.requestFocus(); + if (mskinToneValue != 0) { + progress = (mskinToneValue/SCE_FACTOR_STEP)-MIN_SCE_FACTOR; + mskinToneSeekListener.onProgressChanged(skinToneSeekBar, progress, false); + } else { + progress = (MAX_SCE_FACTOR-MIN_SCE_FACTOR)/2; + RightValue.setText(""); + LeftValue.setText(""); + } + skinToneSeekBar.setProgress(progress); + mActivity.findViewById(R.id.linear).bringToFront(); + skinToneSeekBar.bringToFront(); + Title.setText("Skin Tone Enhancement"); + Title.setVisibility(View.VISIBLE); + RightValue.setVisibility(View.VISIBLE); + LeftValue.setVisibility(View.VISIBLE); + mSkinToneSeekBar = true; + } + + private void disableSkinToneSeekBar() { + skinToneSeekBar.setVisibility(View.INVISIBLE); + Title.setVisibility(View.INVISIBLE); + RightValue.setVisibility(View.INVISIBLE); + LeftValue.setVisibility(View.INVISIBLE); + mskinToneValue = 0; + mSkinToneSeekBar = false; + Editor editor = mPreferences.edit(); + editor.putString(CameraSettings.KEY_SKIN_TONE_ENHANCEMENT_FACTOR, + Integer.toString(mskinToneValue - MIN_SCE_FACTOR)); + editor.apply(); + if(brightnessProgressBar != null) + brightnessProgressBar.setVisibility(View.VISIBLE); +} + +/* + * Provide a mapping for Jpeg encoding quality levels + * from String representation to numeric representation. + */ @Override public boolean arePreviewControlsVisible() { return mUI.arePreviewControlsVisible(); @@ -2019,13 +3288,141 @@ public class PhotoModule } } } +} /* Below is no longer needed, except to get rid of compile error * TODO: Remove these */ +class JpegEncodingQualityMappings { + private static final String TAG = "JpegEncodingQualityMappings"; + private static final int DEFAULT_QUALITY = 85; + private static HashMap<String, Integer> mHashMap = + new HashMap<String, Integer>(); + + static { + mHashMap.put("normal", CameraProfile.QUALITY_LOW); + mHashMap.put("fine", CameraProfile.QUALITY_MEDIUM); + mHashMap.put("superfine", CameraProfile.QUALITY_HIGH); + } + + // Retrieve and return the Jpeg encoding quality number + // for the given quality level. + public static int getQualityNumber(String jpegQuality) { + try{ + int qualityPercentile = Integer.parseInt(jpegQuality); + if(qualityPercentile >= 0 && qualityPercentile <=100) + return qualityPercentile; + else + return DEFAULT_QUALITY; + } catch(NumberFormatException nfe){ + //chosen quality is not a number, continue + } + Integer quality = mHashMap.get(jpegQuality); + if (quality == null) { + Log.w(TAG, "Unknown Jpeg quality: " + jpegQuality); + return DEFAULT_QUALITY; + } + return CameraProfile.getJpegEncodingQualityParameter(quality.intValue()); + } +} - // TODO: Delete this function after old camera code is removed +class GraphView extends View { + private Bitmap mBitmap; + private Paint mPaint = new Paint(); + private Paint mPaintRect = new Paint(); + private Canvas mCanvas = new Canvas(); + private float mScale = (float)3; + private float mWidth; + private float mHeight; + private PhotoModule mPhotoModule; + private CameraManager.CameraProxy mGraphCameraDevice; + private float scaled; + private static final int STATS_SIZE = 256; + private static final String TAG = "GraphView"; + + + public GraphView(Context context, AttributeSet attrs) { + super(context,attrs); + + mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); + mPaintRect.setColor(0xFFFFFFFF); + mPaintRect.setStyle(Paint.Style.FILL); + } @Override - public void onRestorePreferencesClicked() {} + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); + mCanvas.setBitmap(mBitmap); + mWidth = w; + mHeight = h; + super.onSizeChanged(w, h, oldw, oldh); + } + @Override + protected void onDraw(Canvas canvas) { + Log.v(TAG, "in Camera.java ondraw"); + if(mPhotoModule == null || !mPhotoModule.mHiston ) { + Log.e(TAG, "returning as histogram is off "); + return; + } + if (mBitmap != null) { + final Paint paint = mPaint; + final Canvas cavas = mCanvas; + final float border = 5; + float graphheight = mHeight - (2 * border); + float graphwidth = mWidth - (2 * border); + float left,top,right,bottom; + float bargap = 0.0f; + float barwidth = graphwidth/STATS_SIZE; + + cavas.drawColor(0xFFAAAAAA); + paint.setColor(Color.BLACK); + + for (int k = 0; k <= (graphheight /32) ; k++) { + float y = (float)(32 * k)+ border; + cavas.drawLine(border, y, graphwidth + border , y, paint); + } + for (int j = 0; j <= (graphwidth /32); j++) { + float x = (float)(32 * j)+ border; + cavas.drawLine(x, border, x, graphheight + border, paint); + } + synchronized(PhotoModule.statsdata) { + //Assumption: The first element contains + // the maximum value. + int maxValue = Integer.MIN_VALUE; + if ( 0 == PhotoModule.statsdata[0] ) { + for ( int i = 1 ; i <= STATS_SIZE ; i++ ) { + if ( maxValue < PhotoModule.statsdata[i] ) { + maxValue = PhotoModule.statsdata[i]; + } + } + } else { + maxValue = PhotoModule.statsdata[0]; + } + mScale = ( float ) maxValue; + for(int i=1 ; i<=STATS_SIZE ; i++) { + scaled = (PhotoModule.statsdata[i]/mScale)*STATS_SIZE; + if(scaled >= (float)STATS_SIZE) + scaled = (float)STATS_SIZE; + left = (bargap * (i+1)) + (barwidth * i) + border; + top = graphheight + border; + right = left + barwidth; + bottom = top - scaled; + cavas.drawRect(left, top, right, bottom, mPaintRect); + } + } + canvas.drawBitmap(mBitmap, 0, 0, null); + } + if (mPhotoModule.mHiston && mPhotoModule!= null) { + mGraphCameraDevice = mPhotoModule.getCamera(); + if (mGraphCameraDevice != null){ + mGraphCameraDevice.sendHistogramData(); + } + } + } + public void PreviewChanged() { + invalidate(); + } + public void setPhotoModuleObject(PhotoModule photoModule) { + mPhotoModule = photoModule; + } } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index 5018c16d6..b0c642a8b 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -19,6 +19,7 @@ package com.android.camera; import android.app.AlertDialog; import android.content.DialogInterface; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Matrix; @@ -67,7 +68,7 @@ public class PhotoUI implements PieListener, CameraManager.CameraFaceDetectionCallback { private static final String TAG = "CAM_UI"; - private static final int DOWN_SAMPLE_FACTOR = 4; + private int mDownSampleFactor = 4; private final AnimationManager mAnimationManager; private CameraActivity mActivity; private PhotoController mController; @@ -106,6 +107,7 @@ public class PhotoUI implements PieListener, private int mPreviewWidth = 0; private int mPreviewHeight = 0; + public boolean mMenuInitialized = false; private float mSurfaceTextureUncroppedWidth; private float mSurfaceTextureUncroppedHeight; @@ -116,6 +118,10 @@ public class PhotoUI implements PieListener, private TextureView mTextureView; private Matrix mMatrix = null; private float mAspectRatio = 4f / 3f; + private boolean mAspectRatioResize; + + private boolean mOrientationResize; + private boolean mPrevOrientationResize; private View mPreviewCover; private final Object mSurfaceTextureLock = new Object(); @@ -129,10 +135,15 @@ public class PhotoUI implements PieListener, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { int width = right - left; int height = bottom - top; - if (mPreviewWidth != width || mPreviewHeight != height) { + if (mPreviewWidth != width || mPreviewHeight != height + || (mOrientationResize != mPrevOrientationResize) + || mAspectRatioResize) { mPreviewWidth = width; mPreviewHeight = height; setTransformMatrix(width, height); + mController.onScreenSizeChanged((int) mSurfaceTextureUncroppedWidth, + (int) mSurfaceTextureUncroppedHeight); + mAspectRatioResize = false; } } }; @@ -151,8 +162,8 @@ public class PhotoUI implements PieListener, @Override protected Bitmap doInBackground(Void... params) { // Decode image in background. - Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR); - if (mOrientation != 0 || mMirror) { + Bitmap bitmap = CameraUtil.downSample(mData, mDownSampleFactor); + if ((mOrientation != 0 || mMirror) && (bitmap != null)) { Matrix m = new Matrix(); if (mMirror) { // Flip horizontally @@ -218,44 +229,63 @@ public class PhotoUI implements PieListener, } mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); mAnimationManager = new AnimationManager(); + + mOrientationResize = false; + mPrevOrientationResize = false; } - public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) { - mSurfaceTextureSizeListener = listener; + public void setDownFactor(int factor) { + mDownSampleFactor = factor; } - public void updatePreviewAspectRatio(float aspectRatio) { - if (aspectRatio <= 0) { - Log.e(TAG, "Invalid aspect ratio: " + aspectRatio); - return; - } - if (aspectRatio < 1f) { - aspectRatio = 1f / aspectRatio; - } + public void cameraOrientationPreviewResize(boolean orientation){ + mPrevOrientationResize = mOrientationResize; + mOrientationResize = orientation; + } - if (mAspectRatio != aspectRatio) { - mAspectRatio = aspectRatio; - // Update transform matrix with the new aspect ratio. - if (mPreviewWidth != 0 && mPreviewHeight != 0) { - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } + public void setAspectRatio(float ratio) { + if (ratio <= 0.0) throw new IllegalArgumentException(); + + if (mOrientationResize && + mActivity.getResources().getConfiguration().orientation + != Configuration.ORIENTATION_PORTRAIT) { + ratio = 1 / ratio; } + + Log.d(TAG,"setAspectRatio() ratio["+ratio+"] mAspectRatio["+mAspectRatio+"]"); + mAspectRatio = ratio; + mAspectRatioResize = true; + mTextureView.requestLayout(); + } + + public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) { + mSurfaceTextureSizeListener = listener; } private void setTransformMatrix(int width, int height) { mMatrix = mTextureView.getTransform(mMatrix); float scaleX = 1f, scaleY = 1f; float scaledTextureWidth, scaledTextureHeight; - if (width > height) { - scaledTextureWidth = Math.max(width, - (int) (height * mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int)(width / mAspectRatio)); + if (mOrientationResize){ + scaledTextureWidth = height * mAspectRatio; + if(scaledTextureWidth > width){ + scaledTextureWidth = width; + scaledTextureHeight = scaledTextureWidth / mAspectRatio; + } else { + scaledTextureHeight = height; + } } else { - scaledTextureWidth = Math.max(width, - (int) (height / mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int) (width * mAspectRatio)); + if (width > height) { + scaledTextureWidth = Math.max(width, + (int) (height * mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int)(width / mAspectRatio)); + } else { + scaledTextureWidth = Math.max(width, + (int) (height / mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int) (width * mAspectRatio)); + } } if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || @@ -341,6 +371,7 @@ public class PhotoUI implements PieListener, mMenu.setListener(listener); } mMenu.initialize(prefGroup); + mMenuInitialized = true; if (mZoomRenderer == null) { mZoomRenderer = new ZoomRenderer(mActivity); @@ -516,12 +547,13 @@ public class PhotoUI implements PieListener, public void hideGpsOnScreenIndicator() { } public void overrideSettings(final String ... keyvalues) { + if (mMenu == null) return; mMenu.overrideSettings(keyvalues); } public void updateOnScreenIndicators(Camera.Parameters params, PreferenceGroup group, ComboPreferences prefs) { - if (params == null) return; + if (params == null || group == null) return; mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode()); mOnScreenIndicators.updateExposureOnScreenIndicator(params, CameraSettings.readExposure(prefs)); @@ -613,7 +645,8 @@ public class PhotoUI implements PieListener, @Override public void onDismiss() { mPopup = null; - mMenu.popupDismissed(); + mMenu.popupDismissed(mDismissAll); + mDismissAll = false; showUI(); // Switch back into fullscreen/lights-out mode after popup @@ -633,6 +666,14 @@ public class PhotoUI implements PieListener, } } + private boolean mDismissAll = false; + public void dismissAllPopup() { + mDismissAll = true; + if (mPopup != null && mPopup.isShowing()) { + mPopup.dismiss(); + } + } + public void onShowSwitcherPopup() { if (mPieRenderer != null && mPieRenderer.showsItems()) { mPieRenderer.hide(); @@ -655,7 +696,7 @@ public class PhotoUI implements PieListener, // Remove all the popups/dialog boxes boolean ret = false; if (mPopup != null) { - dismissPopup(); + dismissAllPopup(); ret = true; } onShowSwitcherPopup(); @@ -728,6 +769,7 @@ public class PhotoUI implements PieListener, @Override public void onZoomStart() { if (mPieRenderer != null) { + mPieRenderer.hide(); mPieRenderer.setBlockFocus(true); } } @@ -773,6 +815,7 @@ public class PhotoUI implements PieListener, (ViewGroup) mRootView, true); mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); + mCountDownView.bringToFront(); } public boolean isCountingDown() { @@ -893,4 +936,8 @@ public class PhotoUI implements PieListener, mController.updateCameraOrientation(); } + public void setPreference(String key, String value) { + mMenu.setPreference(key, value); + } + } diff --git a/src/com/android/camera/PieController.java b/src/com/android/camera/PieController.java index 622440151..d2e5b72c1 100644 --- a/src/com/android/camera/PieController.java +++ b/src/com/android/camera/PieController.java @@ -19,12 +19,14 @@ package com.android.camera; import android.app.Activity; import android.graphics.drawable.Drawable; import android.util.Log; +import android.widget.Toast; import com.android.camera.CameraPreference.OnPreferenceChangedListener; import com.android.camera.drawable.TextDrawable; import com.android.camera.ui.PieItem; import com.android.camera.ui.PieItem.OnClickListener; import com.android.camera.ui.PieRenderer; +import com.android.camera2.R; import java.util.ArrayList; import java.util.HashMap; @@ -65,11 +67,13 @@ public class PieController { mRenderer.clearItems(); mPreferenceMap.clear(); setPreferenceGroup(group); + mPreferences.clear(); + mOverrides.clear(); } public void onSettingChanged(ListPreference pref) { if (mListener != null) { - mListener.onSharedPreferenceChanged(); + mListener.onSharedPreferenceChanged(pref); } } @@ -165,6 +169,12 @@ public class PieController { CharSequence[] values = pref.getEntryValues(); index = (index + 1) % values.length; pref.setValueIndex(index); + // when enable HDR,inform to disable Continuous Shot + if (index == 1 && prefKey == CameraSettings.KEY_CAMERA_HDR) + { + Toast.makeText(mActivity, R.string.HDR_disable_continuous_shot, + Toast.LENGTH_LONG).show(); + } fitem.setLabel(pref.getLabels()[index]); fitem.setImageResource(mActivity, ((IconListPreference) pref).getLargeIconIds()[index]); diff --git a/src/com/android/camera/SDCard.java b/src/com/android/camera/SDCard.java new file mode 100644 index 000000000..dad354007 --- /dev/null +++ b/src/com/android/camera/SDCard.java @@ -0,0 +1,107 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.camera; + +import android.content.Context; +import android.os.StatFs; +import android.os.Environment; +import android.os.storage.StorageVolume; +import android.os.storage.IMountService; +import android.os.ServiceManager; +import android.util.Log; + +public class SDCard { + private static final String TAG = "SDCard"; + + private static final int VOLUME_SDCARD_INDEX = 1; + private IMountService mMountService = null; + private StorageVolume mVolume = null; + private String path = null; + private String rawpath = null; + private static SDCard sSDCard; + + public boolean isWriteable() { + if (mVolume == null) return false; + final String state = getSDCardStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; + } + + public String getDirectory() { + if (mVolume == null) { + return null; + } + if (path == null) { + path = mVolume.getPath() + "/DCIM/Camera"; + } + return path; + } + + public String getRawDirectory() { + if (mVolume == null) { + return null; + } + if (rawpath == null) { + rawpath = mVolume.getPath() + "/DCIM/Camera/raw"; + } + return rawpath; + } + + public static synchronized SDCard instance() { + if (sSDCard == null) { + sSDCard = new SDCard(); + } + return sSDCard; + } + + private String getSDCardStorageState() { + try { + return mMountService.getVolumeState(mVolume.getPath()); + } catch (Exception e) { + Log.w(TAG, "Failed to read SDCard storage state; assuming REMOVED: " + e); + return Environment.MEDIA_REMOVED; + } + } + + private SDCard() { + try { + mMountService = IMountService.Stub.asInterface(ServiceManager + .getService("mount")); + final StorageVolume[] volumes = mMountService.getVolumeList(); + if (volumes.length > VOLUME_SDCARD_INDEX) { + mVolume = volumes[VOLUME_SDCARD_INDEX]; + } + } catch (Exception e) { + Log.e(TAG, "couldn't talk to MountService", e); + } + } + +} diff --git a/src/com/android/camera/ShutterButton.java b/src/com/android/camera/ShutterButton.java index a1bbb1a0d..f1d969f9d 100755..100644 --- a/src/com/android/camera/ShutterButton.java +++ b/src/com/android/camera/ShutterButton.java @@ -29,7 +29,18 @@ import android.widget.ImageView; */ public class ShutterButton extends ImageView { + private class LongClickListener implements View.OnLongClickListener { + public boolean onLongClick(View v) { + if ( null != mListener ) { + mListener.onShutterButtonLongClick(); + return true; + } + return false; + } + } + private boolean mTouchEnabled = true; + private LongClickListener mLongClick = new LongClickListener(); /** * A callback to be invoked when a ShutterButton's pressed state changes. @@ -42,6 +53,7 @@ public class ShutterButton extends ImageView { */ void onShutterButtonFocus(boolean pressed); void onShutterButtonClick(); + void onShutterButtonLongClick(); } private OnShutterButtonListener mListener; @@ -53,6 +65,7 @@ public class ShutterButton extends ImageView { public void setOnShutterButtonListener(OnShutterButtonListener listener) { mListener = listener; + setOnLongClickListener(mLongClick); } @Override @@ -66,6 +79,7 @@ public class ShutterButton extends ImageView { public void enableTouch(boolean enable) { mTouchEnabled = enable; + setLongClickable(enable); } /** diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index b09eedafe..d27cf259f 100644 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -43,6 +43,7 @@ public class Storage { Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(); public static final String DIRECTORY = DCIM + "/Camera"; + public static final String RAW_DIRECTORY = DCIM + "/Camera/raw"; public static final String JPEG_POSTFIX = ".jpg"; // Match the code in MediaProvider.computeBucketValues(). @@ -54,6 +55,16 @@ public class Storage { public static final long UNKNOWN_SIZE = -3L; public static final long LOW_STORAGE_THRESHOLD_BYTES = 50000000; + private static boolean sSaveSDCard = false; + + public static boolean isSaveSDCard() { + return sSaveSDCard; + } + + public static void setSaveSDCard(boolean saveSDCard) { + sSaveSDCard = saveSDCard; + } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private static void setImageSize(ContentValues values, int width, int height) { // The two fields are available since ICS but got published in JB @@ -63,14 +74,20 @@ public class Storage { } } - public static void writeFile(String path, byte[] jpeg, ExifInterface exif) { - if (exif != null) { + public static void writeFile(String path, byte[] jpeg, ExifInterface exif, + String mimeType) { + if (exif != null && (mimeType == null || + mimeType.equalsIgnoreCase("jpeg"))) { try { exif.writeExif(jpeg, path); } catch (Exception e) { Log.e(TAG, "Failed to write data", e); } - } else { + } else if (jpeg != null) { + if (!(mimeType.equalsIgnoreCase("jpeg") || mimeType == null)) { + File dir = new File(RAW_DIRECTORY); + dir.mkdirs(); + } writeFile(path, jpeg); } } @@ -91,22 +108,13 @@ public class Storage { } } - // Save the image and add it to the MediaStore. - public static Uri addImage(ContentResolver resolver, String title, long date, - Location location, int orientation, ExifInterface exif, byte[] jpeg, int width, - int height) { - - return addImage(resolver, title, date, location, orientation, exif, jpeg, width, height, - LocalData.MIME_TYPE_JPEG); - } - // Save the image with a given mimeType and add it the MediaStore. public static Uri addImage(ContentResolver resolver, String title, long date, Location location, int orientation, ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) { - String path = generateFilepath(title); - writeFile(path, jpeg, exif); + String path = generateFilepath(title, mimeType); + writeFile(path, jpeg, exif, mimeType); return addImage(resolver, title, date, location, orientation, jpeg.length, path, width, height, mimeType); } @@ -115,12 +123,18 @@ public class Storage { public static ContentValues getContentValuesForData(String title, long date, Location location, int orientation, int jpegLength, String path, int width, int height, String mimeType) { - - ContentValues values = new ContentValues(11); + // Insert into MediaStore. + ContentValues values = new ContentValues(9); values.put(ImageColumns.TITLE, title); - values.put(ImageColumns.DISPLAY_NAME, title + JPEG_POSTFIX); + if (mimeType.equalsIgnoreCase("jpeg") || + mimeType.equalsIgnoreCase("image/jpeg") || + mimeType == null) { + values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); + } else { + values.put(ImageColumns.DISPLAY_NAME, title + ".raw"); + } values.put(ImageColumns.DATE_TAKEN, date); - values.put(ImageColumns.MIME_TYPE, mimeType); + values.put(ImageColumns.MIME_TYPE, "image/jpeg"); // Clockwise rotation in degrees. 0, 90, 180, or 270. values.put(ImageColumns.ORIENTATION, orientation); values.put(ImageColumns.DATA, path); @@ -152,8 +166,8 @@ public class Storage { public static void updateImage(Uri imageUri, ContentResolver resolver, String title, long date, Location location, int orientation, ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) { - String path = generateFilepath(title); - writeFile(path, jpeg, exif); + String path = generateFilepath(title, mimeType); + writeFile(path, jpeg, exif, mimeType); updateImage(imageUri, resolver, title, date, location, orientation, jpeg.length, path, width, height, mimeType); } @@ -190,33 +204,55 @@ public class Storage { } } - public static String generateFilepath(String title) { - return DIRECTORY + '/' + title + ".jpg"; + public static String generateFilepath(String title, String pictureFormat) { + if (pictureFormat == null || pictureFormat.equalsIgnoreCase("jpeg")) { + if (isSaveSDCard() && SDCard.instance().isWriteable()) { + return SDCard.instance().getDirectory() + '/' + title + ".jpg"; + } else { + return DIRECTORY + '/' + title + ".jpg"; + } + } else { + return RAW_DIRECTORY + '/' + title + ".raw"; + } } public static long getAvailableSpace() { - String state = Environment.getExternalStorageState(); - Log.d(TAG, "External storage state=" + state); - if (Environment.MEDIA_CHECKING.equals(state)) { - return PREPARING; - } - if (!Environment.MEDIA_MOUNTED.equals(state)) { - return UNAVAILABLE; - } + if (isSaveSDCard() && SDCard.instance().isWriteable()) { + File dir = new File(SDCard.instance().getDirectory()); + dir.mkdirs(); + try { + StatFs stat = new StatFs(SDCard.instance().getDirectory()); + long ret = stat.getAvailableBlocks() * (long) stat.getBlockSize(); + return ret; + } catch (Exception e) { + } + return UNKNOWN_SIZE; + } else if (isSaveSDCard() && !SDCard.instance().isWriteable()) { + return UNKNOWN_SIZE; + } else { + String state = Environment.getExternalStorageState(); + Log.d(TAG, "External storage state=" + state); + if (Environment.MEDIA_CHECKING.equals(state)) { + return PREPARING; + } + if (!Environment.MEDIA_MOUNTED.equals(state)) { + return UNAVAILABLE; + } - File dir = new File(DIRECTORY); - dir.mkdirs(); - if (!dir.isDirectory() || !dir.canWrite()) { - return UNAVAILABLE; - } + File dir = new File(DIRECTORY); + dir.mkdirs(); + if (!dir.isDirectory() || !dir.canWrite()) { + return UNAVAILABLE; + } - try { - StatFs stat = new StatFs(DIRECTORY); - return stat.getAvailableBlocks() * (long) stat.getBlockSize(); - } catch (Exception e) { - Log.i(TAG, "Fail to access external storage", e); + try { + StatFs stat = new StatFs(DIRECTORY); + return stat.getAvailableBlocks() * (long) stat.getBlockSize(); + } catch (Exception e) { + Log.i(TAG, "Fail to access external storage", e); + } + return UNKNOWN_SIZE; } - return UNKNOWN_SIZE; } /** diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java index e84654821..cf694a391 100644 --- a/src/com/android/camera/VideoController.java +++ b/src/com/android/camera/VideoController.java @@ -19,8 +19,9 @@ package com.android.camera; import android.view.View; import com.android.camera.ShutterButton.OnShutterButtonListener; +import com.android.camera.PauseButton.OnPauseButtonListener; -public interface VideoController extends OnShutterButtonListener { +public interface VideoController extends OnShutterButtonListener, OnPauseButtonListener { public void onReviewDoneClicked(View view); public void onReviewCancelClicked(View viwe); diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java index f0c7db272..440c70c46 100644 --- a/src/com/android/camera/VideoMenu.java +++ b/src/com/android/camera/VideoMenu.java @@ -36,13 +36,17 @@ public class VideoMenu extends PieController private static String TAG = "CAM_VideoMenu"; private VideoUI mUI; - private String[] mOtherKeys; - private AbstractSettingPopup mPopup; + private String[] mOtherKeys1; + private String[] mOtherKeys2; + + private AbstractSettingPopup mPopup1; + private AbstractSettingPopup mPopup2; 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; + private int popupNum; private CameraActivity mActivity; public VideoMenu(CameraActivity activity, VideoUI ui, PieRenderer pie) { @@ -51,37 +55,66 @@ public class VideoMenu extends PieController mActivity = activity; } - public void initialize(PreferenceGroup group) { super.initialize(group); - mPopup = null; + mPopup1 = null; + mPopup2 = null; + popupNum = 0; mPopupStatus = POPUP_NONE; PieItem item = null; - // white balance - if (group.findPreference(CameraSettings.KEY_WHITE_BALANCE) != null) { - item = makeItem(CameraSettings.KEY_WHITE_BALANCE); - mRenderer.addItem(item); - } // settings popup - mOtherKeys = new String[] { + mOtherKeys1 = new String[] { + CameraSettings.KEY_DIS, CameraSettings.KEY_VIDEO_EFFECT, CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, CameraSettings.KEY_VIDEO_QUALITY, - CameraSettings.KEY_RECORD_LOCATION + CameraSettings.KEY_VIDEO_ENCODER, + CameraSettings.KEY_AUDIO_ENCODER, + CameraSettings.KEY_VIDEO_DURATION, + CameraSettings.KEY_RECORD_LOCATION, + CameraSettings.KEY_CAMERA_SAVEPATH }; - item = makeItem(R.drawable.ic_settings_holo_light); - item.setLabel(mActivity.getResources().getString(R.string.camera_menu_settings_label)); - item.setOnClickListener(new OnClickListener() { + + //settings popup + mOtherKeys2 = new String[] { + CameraSettings.KEY_COLOR_EFFECT, + CameraSettings.KEY_VIDEO_HDR, + CameraSettings.KEY_POWER_MODE, + CameraSettings.KEY_WHITE_BALANCE, + CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE, + CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, + }; + + PieItem item1 = makeItem(R.drawable.ic_settings_holo_light); + item1.setLabel(mActivity.getResources().getString(R.string.camera_menu_more_label)); + item1.setOnClickListener(new OnClickListener() { @Override public void onClick(PieItem item) { - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { + if (mPopup1 == null || mPopupStatus != POPUP_FIRST_LEVEL) { initializePopup(); mPopupStatus = POPUP_FIRST_LEVEL; } - mUI.showPopup(mPopup); + mUI.showPopup(mPopup1); + popupNum = 1; } }); - mRenderer.addItem(item); + mRenderer.addItem(item1); + + PieItem item2 = makeItem(R.drawable.ic_settings_holo_light); + item2.setLabel(mActivity.getResources().getString(R.string.camera_menu_more_label)); + item2.setOnClickListener(new OnClickListener() { + @Override + public void onClick(PieItem item) { + if (mPopup2 == null || mPopupStatus != POPUP_FIRST_LEVEL) { + initializePopup(); + mPopupStatus = POPUP_FIRST_LEVEL; + } + mUI.showPopup(mPopup2); + popupNum = 2; + } + }); + mRenderer.addItem(item2); + // camera switcher if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { item = makeItem(R.drawable.ic_switch_back); @@ -114,37 +147,38 @@ public class VideoMenu extends PieController }); mRenderer.addItem(item); } - // flash - if (group.findPreference(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE) != null) { - item = makeItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE); - mRenderer.addItem(item); - } } @Override public void reloadPreferences() { super.reloadPreferences(); - if (mPopup != null) { - mPopup.reloadPreference(); + if (mPopup1 != null) { + mPopup1.reloadPreference(); + } + if (mPopup2 != null) { + mPopup2.reloadPreference(); } } @Override public void overrideSettings(final String ... keyvalues) { super.overrideSettings(keyvalues); - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { + if (((mPopup1 == null) && (mPopup2 == null)) || mPopupStatus != POPUP_FIRST_LEVEL) { mPopupStatus = POPUP_FIRST_LEVEL; initializePopup(); } - ((MoreSettingPopup) mPopup).overrideSettings(keyvalues); + ((MoreSettingPopup) mPopup1).overrideSettings(keyvalues); + ((MoreSettingPopup) mPopup2).overrideSettings(keyvalues); } @Override // Hit when an item in the second-level popup gets selected public void onListPrefChanged(ListPreference pref) { - if (mPopup != null) { + if (mPopup1 != null && mPopup2 != null) { if (mPopupStatus == POPUP_SECOND_LEVEL) { mUI.dismissPopup(true); + mPopup1.reloadPreference(); + mPopup2.reloadPreference(); } } super.onSettingChanged(pref); @@ -154,15 +188,21 @@ public class VideoMenu extends PieController LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( Context.LAYOUT_INFLATER_SERVICE); - MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( + MoreSettingPopup popup1 = (MoreSettingPopup) inflater.inflate( R.layout.more_setting_popup, null, false); - popup.setSettingChangedListener(this); - popup.initialize(mPreferenceGroup, mOtherKeys); + popup1.setSettingChangedListener(this); + popup1.initialize(mPreferenceGroup, mOtherKeys1); if (mActivity.isSecureCamera()) { // Prevent location preference from getting changed in secure camera mode - popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); + popup1.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); } - mPopup = popup; + mPopup1 = popup1; + + MoreSettingPopup popup2 = (MoreSettingPopup) inflater.inflate( + R.layout.more_setting_popup, null, false); + popup2.setSettingChangedListener(this); + popup2.initialize(mPreferenceGroup, mOtherKeys2); + mPopup2 = popup2; } public void popupDismissed(boolean topPopupOnly) { @@ -170,7 +210,12 @@ public class VideoMenu extends PieController if (mPopupStatus == POPUP_SECOND_LEVEL) { initializePopup(); mPopupStatus = POPUP_FIRST_LEVEL; - if (topPopupOnly) mUI.showPopup(mPopup); + if (topPopupOnly) { + if(popupNum == 1) mUI.showPopup(mPopup1); + else if(popupNum == 2) mUI.showPopup(mPopup2); + } + } else { + initializePopup(); } } @@ -189,16 +234,17 @@ public class VideoMenu extends PieController timeInterval.initialize((IconListPreference) pref); timeInterval.setSettingChangedListener(this); mUI.dismissPopup(true); - mPopup = timeInterval; + mPopup1 = timeInterval; } else { ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( R.layout.list_pref_setting_popup, null, false); basic.initialize(pref); basic.setSettingChangedListener(this); mUI.dismissPopup(true); - mPopup = basic; + mPopup1 = basic; } - mUI.showPopup(mPopup); + mUI.showPopup(mPopup1); mPopupStatus = POPUP_SECOND_LEVEL; } + } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 92a2a9493..20b11d61e 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -29,6 +29,8 @@ import android.content.SharedPreferences.Editor; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.SurfaceTexture; +import android.graphics.ImageFormat; +import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; @@ -41,6 +43,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.provider.MediaStore; @@ -52,6 +55,8 @@ import android.view.OrientationEventListener; import android.view.View; import android.view.WindowManager; import android.widget.Toast; +import android.media.EncoderCapabilities; +import android.media.EncoderCapabilities.VideoEncoderCap; import com.android.camera.CameraManager.CameraPictureCallback; import com.android.camera.CameraManager.CameraProxy; @@ -63,13 +68,14 @@ import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; import com.android.camera.util.UsageStatistics; import com.android.camera2.R; - +import com.android.camera.PhotoModule; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.HashMap; public class VideoModule implements CameraModule, VideoController, @@ -113,6 +119,8 @@ public class VideoModule implements CameraModule, private ComboPreferences mPreferences; private PreferenceGroup mPreferenceGroup; + private boolean mSaveToSDCard = false; + // Preference must be read before starting preview. We check this before starting // preview. private boolean mPreferenceRead; @@ -124,7 +132,9 @@ public class VideoModule implements CameraModule, private boolean mSwitchingCamera; private boolean mMediaRecorderRecording = false; + private boolean mMediaRecorderPausing = false; private long mRecordingStartTime; + private long mRecordingTotalTime; private boolean mRecordingTimeCountsDown = false; private long mOnResumeTime; // The video file that the hardware camera is about to record into @@ -161,7 +171,6 @@ public class VideoModule implements CameraModule, private LocationManager mLocationManager; private OrientationManager mOrientationManager; - private int mPendingSwitchCameraId; private final Handler mHandler = new MainHandler(); private VideoUI mUI; @@ -172,6 +181,14 @@ public class VideoModule implements CameraModule, private int mZoomValue; // The current zoom value. + private boolean mStartRecPending = false; + private boolean mStopRecPending = false; + private boolean mStartPrevPending = false; + private boolean mStopPrevPending = false; + + // The preview window is on focus + private boolean mPreviewFocused = false; + private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener = new MediaSaveService.OnMediaSavedListener() { @Override @@ -214,8 +231,78 @@ public class VideoModule implements CameraModule, return; } mParameters = mCameraDevice.getParameters(); + mPreviewFocused = true; + } + + //QCOM data Members Starts here + static class DefaultHashMap<K, V> extends HashMap<K, V> { + private V mDefaultValue; + + public void putDefault(V defaultValue) { + mDefaultValue = defaultValue; + } + + @Override + public V get(Object key) { + V value = super.get(key); + return (value == null) ? mDefaultValue : value; + } + public K getKey(V toCheck) { + Iterator<K> it = this.keySet().iterator(); + V val; + K key; + while(it.hasNext()) { + key = it.next(); + val = this.get(key); + if (val.equals(toCheck)) { + return key; + } + } + return null; + } } + + private static final DefaultHashMap<String, Integer> + OUTPUT_FORMAT_TABLE = new DefaultHashMap<String, Integer>(); + private static final DefaultHashMap<String, Integer> + VIDEO_ENCODER_TABLE = new DefaultHashMap<String, Integer>(); + private static final DefaultHashMap<String, Integer> + AUDIO_ENCODER_TABLE = new DefaultHashMap<String, Integer>(); + private static final DefaultHashMap<String, Integer> + VIDEOQUALITY_BITRATE_TABLE = new DefaultHashMap<String, Integer>(); + + static { + OUTPUT_FORMAT_TABLE.put("3gp", MediaRecorder.OutputFormat.THREE_GPP); + OUTPUT_FORMAT_TABLE.put("mp4", MediaRecorder.OutputFormat.MPEG_4); + OUTPUT_FORMAT_TABLE.putDefault(MediaRecorder.OutputFormat.DEFAULT); + + VIDEO_ENCODER_TABLE.put("h263", MediaRecorder.VideoEncoder.H263); + VIDEO_ENCODER_TABLE.put("h264", MediaRecorder.VideoEncoder.H264); + VIDEO_ENCODER_TABLE.put("m4v", MediaRecorder.VideoEncoder.MPEG_4_SP); + VIDEO_ENCODER_TABLE.putDefault(MediaRecorder.VideoEncoder.DEFAULT); + + AUDIO_ENCODER_TABLE.put("amrnb", MediaRecorder.AudioEncoder.AMR_NB); + // Enabled once support is added in MediaRecorder. + // AUDIO_ENCODER_TABLE.put("qcelp", MediaRecorder.AudioEncoder.QCELP); + // AUDIO_ENCODER_TABLE.put("evrc", MediaRecorder.AudioEncoder.EVRC); + AUDIO_ENCODER_TABLE.put("amrwb", MediaRecorder.AudioEncoder.AMR_WB); + AUDIO_ENCODER_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC); + AUDIO_ENCODER_TABLE.putDefault(MediaRecorder.AudioEncoder.DEFAULT); + + } + + private int mVideoEncoder; + private int mAudioEncoder; + private boolean mRestartPreview = false; + private int videoWidth; + private int videoHeight; + boolean mUnsupportedResolution = false; + private boolean mUnsupportedHFRVideoSize = false; + private boolean mUnsupportedHSRVideoSize = false; + private boolean mUnsupportedHFRVideoCodec = false; + private String mDefaultAntibanding = null; + // This Handler is used to post message back onto the main thread of the // application private class MainHandler extends Handler { @@ -342,6 +429,9 @@ public class VideoModule implements CameraModule, mContentResolver = mActivity.getContentResolver(); + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + mSaveToSDCard = Storage.isSaveSDCard(); // Surface texture is from camera screen nail and startPreview needs it. // This must be done before startPreview. mIsVideoCaptureIntent = isVideoCaptureIntent(); @@ -378,12 +468,14 @@ public class VideoModule implements CameraModule, // Preview area is touched. Take a picture. @Override public void onSingleTapUp(View view, int x, int y) { + if (mMediaRecorderPausing) return; takeASnapshot(); } private void takeASnapshot() { // Only take snapshots if video snapshot is supported by device - if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { + if (CameraUtil.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent + && !is4KEnabled()) { if (!mMediaRecorderRecording || mPaused || mSnapshotInProgress) { return; } @@ -418,6 +510,36 @@ public class VideoModule implements CameraModule, // Remove the video quality preference setting when the quality is given in the intent. mPreferenceGroup = filterPreferenceScreenByIntent( settings.getPreferenceGroup(R.xml.video_preferences)); + + int numOfCams = Camera.getNumberOfCameras(); + int backCamId = CameraHolder.instance().getBackCameraId(); + int frontCamId = CameraHolder.instance().getFrontCameraId(); + // We need to swap the list preference contents if back camera and front camera + // IDs are not 0 and 1 respectively + if( (numOfCams == 2) && ((backCamId != CameraInfo.CAMERA_FACING_BACK) + || (frontCamId != CameraInfo.CAMERA_FACING_FRONT))) { + Log.e(TAG,"loadCameraPreferences() updating camera_id pref"); + + IconListPreference switchIconPref = + (IconListPreference)mPreferenceGroup.findPreference( + CameraSettings.KEY_CAMERA_ID); + + int[] iconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back}; + switchIconPref.setIconIds(iconIds); + + String[] entries = {mActivity.getResources().getString( + R.string.pref_camera_id_entry_front), mActivity.getResources(). + getString(R.string.pref_camera_id_entry_back)}; + switchIconPref.setEntries(entries); + + String[] labels = {mActivity.getResources().getString( + R.string.pref_camera_id_label_front), mActivity.getResources(). + getString(R.string.pref_camera_id_label_back)}; + switchIconPref.setLabels(labels); + + int[] largeIconIds = {R.drawable.ic_switch_front, R.drawable.ic_switch_back}; + switchIconPref.setLargeIconIds(largeIconIds); + } } private void initializeVideoControl() { @@ -435,6 +557,10 @@ public class VideoModule implements CameraModule, if (mOrientation != newOrientation) { mOrientation = newOrientation; + Log.v(TAG, "onOrientationChanged, update parameters"); + if ((mParameters != null) && (true == mPreviewing) && !mMediaRecorderRecording){ + setCameraParameters(); + } } // Show the toast after getting the first orientation changed. @@ -520,12 +646,33 @@ public class VideoModule implements CameraModule, // Consume clicks } + public boolean isPreviewReady() { + if ((mStartPrevPending == true || mStopPrevPending == true)) + return false; + else + return true; + } + + public boolean isRecorderReady() { + if ((mStartRecPending == true || mStopRecPending == true)) + return false; + else + return true; + } + @Override public void onShutterButtonClick() { - if (mUI.collapseCameraControls() || mSwitchingCamera) return; + if (mPaused || mUI.collapseCameraControls() || + mSwitchingCamera) return; boolean stop = mMediaRecorderRecording; + if (isPreviewReady() == false) + return; + + if (isRecorderReady() == false) + return; + if (stop) { onStopVideoRecording(); } else { @@ -547,15 +694,81 @@ public class VideoModule implements CameraModule, mUI.setShutterPressed(pressed); } + @Override + public void onShutterButtonLongClick() {} + + private void qcomReadVideoPreferences() { + String videoEncoder = mPreferences.getString( + CameraSettings.KEY_VIDEO_ENCODER, + mActivity.getString(R.string.pref_camera_videoencoder_default)); + mVideoEncoder = VIDEO_ENCODER_TABLE.get(videoEncoder); + + Log.v(TAG, "Video Encoder selected = " +mVideoEncoder); + + String audioEncoder = mPreferences.getString( + CameraSettings.KEY_AUDIO_ENCODER, + mActivity.getString(R.string.pref_camera_audioencoder_default)); + mAudioEncoder = AUDIO_ENCODER_TABLE.get(audioEncoder); + + Log.v(TAG, "Audio Encoder selected = " +mAudioEncoder); + + String minutesStr = mPreferences.getString( + CameraSettings.KEY_VIDEO_DURATION, + mActivity.getString(R.string.pref_camera_video_duration_default)); + int minutes = -1; + try { + minutes = Integer.parseInt(minutesStr); + } catch(NumberFormatException npe) { + // use default value continue + minutes = Integer.parseInt(mActivity.getString( + R.string.pref_camera_video_duration_default)); + } + if (minutes == -1) { + // User wants lowest, set 30s */ + mMaxVideoDurationInMs = 30000; + } else { + // 1 minute = 60000ms + mMaxVideoDurationInMs = 60000 * minutes; + } + + if(mParameters.isPowerModeSupported()) { + String powermode = mPreferences.getString( + CameraSettings.KEY_POWER_MODE, + mActivity.getString(R.string.pref_camera_powermode_default)); + Log.v(TAG, "read videopreferences power mode =" +powermode); + String old_mode = mParameters.getPowerMode(); + if(!old_mode.equals(powermode) && mPreviewing) + mRestartPreview = true; + + mParameters.setPowerMode(powermode); + } + + // Set wavelet denoise mode + if (mParameters.getSupportedDenoiseModes() != null) { + String denoise = mPreferences.getString(CameraSettings.KEY_DENOISE, + mActivity.getString(R.string.pref_camera_denoise_default)); + mParameters.setDenoise(denoise); + } + } + private void readVideoPreferences() { // The preference stores values from ListPreference and is thus string type for all values. // We need to convert it to int manually. String videoQuality = mPreferences.getString(CameraSettings.KEY_VIDEO_QUALITY, null); if (videoQuality == null) { - // check for highest quality before setting default value - videoQuality = CameraSettings.getSupportedHighestVideoQuality(mCameraId, - mActivity.getResources().getString(R.string.pref_video_quality_default)); + mParameters = mCameraDevice.getParameters(); + String defaultQuality = mActivity.getResources().getString( + R.string.pref_video_quality_default); + boolean hasProfile = CamcorderProfile.hasProfile( + Integer.parseInt(defaultQuality)); + if (hasProfile == true){ + videoQuality = defaultQuality; + } else { + // check for highest quality if default quality is not supported + videoQuality = CameraSettings.getSupportedHighestVideoQuality(mCameraId, + defaultQuality, mParameters); + } mPreferences.edit().putString(CameraSettings.KEY_VIDEO_QUALITY, videoQuality); } int quality = Integer.valueOf(videoQuality); @@ -592,9 +805,19 @@ public class VideoModule implements CameraModule, if (mCaptureTimeLapse) quality += 1000; mProfile = CamcorderProfile.get(mCameraId, quality); getDesiredPreviewSize(); + qcomReadVideoPreferences(); mPreferenceRead = true; } + private boolean is4KEnabled() { + if (mProfile.quality == CamcorderProfile.QUALITY_4kUHD || + mProfile.quality == CamcorderProfile.QUALITY_4kDCI) { + return true; + } else { + return false; + } + } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void getDesiredPreviewSize() { if (mCameraDevice == null) { @@ -626,7 +849,19 @@ public class VideoModule implements CameraModule, ". mDesiredPreviewHeight=" + mDesiredPreviewHeight); } - private void resizeForPreviewAspectRatio() { + void setPreviewFrameLayoutCameraOrientation(){ + CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; + + //if camera mount angle is 0 or 180, we want to resize preview + if (info.orientation % 180 == 0) + mUI.cameraOrientationPreviewResize(true); + else + mUI.cameraOrientationPreviewResize(false); + } + + @Override + public void resizeForPreviewAspectRatio() { + setPreviewFrameLayoutCameraOrientation(); mUI.setAspectRatio( (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight); } @@ -686,6 +921,12 @@ public class VideoModule implements CameraModule, UsageStatistics.onContentViewChanged( UsageStatistics.COMPONENT_CAMERA, "VideoModule"); + mHandler.post(new Runnable(){ + @Override + public void run(){ + mActivity.updateStorageSpaceAndHint(); + } + }); } private void setDisplayOrientation() { @@ -721,10 +962,12 @@ public class VideoModule implements CameraModule, private void startPreview() { Log.v(TAG, "startPreview"); + mStartPrevPending = true; SurfaceTexture surfaceTexture = mUI.getSurfaceTexture(); if (!mPreferenceRead || surfaceTexture == null || mPaused == true || mCameraDevice == null) { + mStartPrevPending = false; return; } @@ -746,6 +989,7 @@ public class VideoModule implements CameraModule, closeCamera(); throw new RuntimeException("startPreview failed", ex); } + mStartPrevPending = false; } private void onPreviewStarted() { @@ -754,9 +998,16 @@ public class VideoModule implements CameraModule, @Override public void stopPreview() { - if (!mPreviewing) return; + mStopPrevPending = true; + + if (!mPreviewing) { + mStopPrevPending = false; + return; + } mCameraDevice.stopPreview(); mPreviewing = false; + mStopPrevPending = false; + mUI.enableShutter(false); } private void closeCamera() { @@ -771,6 +1022,7 @@ public class VideoModule implements CameraModule, mCameraDevice = null; mPreviewing = false; mSnapshotInProgress = false; + mPreviewFocused = false; } private void releasePreviewResources() { @@ -946,6 +1198,35 @@ public class VideoModule implements CameraModule, Intent intent = mActivity.getIntent(); Bundle myExtras = intent.getExtras(); + videoWidth = mProfile.videoFrameWidth; + videoHeight = mProfile.videoFrameHeight; + mUnsupportedResolution = false; + + //check if codec supports the resolution, otherwise throw toast + List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders(); + for (VideoEncoderCap videoEncoder: videoEncoders) { + if (videoEncoder.mCodec == mVideoEncoder){ + if (videoWidth > videoEncoder.mMaxFrameWidth || + videoWidth < videoEncoder.mMinFrameWidth || + videoHeight > videoEncoder.mMaxFrameHeight || + videoHeight < videoEncoder.mMinFrameHeight){ + Log.e(TAG,"Selected codec "+mVideoEncoder+ + " does not support "+ videoWidth + "x" + videoHeight + +" resolution"); + Log.e(TAG, "Codec capabilities: " + + "mMinFrameWidth = " + videoEncoder.mMinFrameWidth + " , "+ + "mMinFrameHeight = " + videoEncoder.mMinFrameHeight + " , "+ + "mMaxFrameWidth = " + videoEncoder.mMaxFrameWidth + " , "+ + "mMaxFrameHeight = " + videoEncoder.mMaxFrameHeight); + mUnsupportedResolution = true; + Toast.makeText(mActivity, R.string.error_app_unsupported, + Toast.LENGTH_LONG).show(); + return; + } + break; + } + } + long requestedSizeLimit = 0; closeVideoFileDescriptor(); mCurrentVideoUriFromMediaSaved = false; @@ -968,10 +1249,19 @@ public class VideoModule implements CameraModule, // Unlock the camera object before passing it to media recorder. mCameraDevice.unlock(); mMediaRecorder.setCamera(mCameraDevice.getCamera()); - if (!mCaptureTimeLapse) { + String hfr = mParameters.getVideoHighFrameRate(); + if (!mCaptureTimeLapse && ((hfr == null) || ("off".equals(hfr)))) { mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); + mProfile.audioCodec = mAudioEncoder; + } else { + mProfile.audioCodec = -1; //not set } + mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + + mProfile.videoCodec = mVideoEncoder; + mProfile.duration = mMaxVideoDurationInMs; + mMediaRecorder.setProfile(mProfile); mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight); mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs); @@ -1065,7 +1355,12 @@ public class VideoModule implements CameraModule, // Used when emailing. String filename = title + convertOutputFormatToFileExt(outputFileFormat); String mime = convertOutputFormatToMimeType(outputFileFormat); - String path = Storage.DIRECTORY + '/' + filename; + String path = null; + if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) { + path = SDCard.instance().getDirectory() + '/' + filename; + } else { + path = Storage.DIRECTORY + '/' + filename; + } String tmpPath = path + ".tmp"; mCurrentVideoValues = new ContentValues(9); mCurrentVideoValues.put(Video.Media.TITLE, title); @@ -1088,7 +1383,7 @@ public class VideoModule implements CameraModule, private void saveVideo() { if (mVideoFileDescriptor == null) { - long duration = SystemClock.uptimeMillis() - mRecordingStartTime; + long duration = SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime; if (duration > 0) { if (mCaptureTimeLapse) { duration = getTimeLapseVideoLength(duration); @@ -1096,6 +1391,29 @@ public class VideoModule implements CameraModule, } else { Log.w(TAG, "Video duration <= 0 : " + duration); } + + File origFile = new File(mCurrentVideoFilename); + if (!origFile.exists() || origFile.length() <= 0) { + Log.e(TAG, "Invalid file"); + mCurrentVideoValues = null; + return; + } + + /* Change the duration as per HFR selection */ + String hfr = mParameters.getVideoHighFrameRate(); + int defaultFps = 30; + int hfrRatio = 1; + if (!("off".equals(hfr))) { + try { + int hfrFps = Integer.parseInt(hfr); + hfrRatio = hfrFps / defaultFps; + } catch(NumberFormatException ex) { + //Default value will be used + Log.e(TAG,"Invalid hfr values:"+hfr); + } + } + duration = duration * hfrRatio; + mActivity.getMediaSaveService().addVideo(mCurrentVideoFilename, duration, mCurrentVideoValues, mOnVideoSavedListener, mContentResolver); @@ -1130,9 +1448,9 @@ public class VideoModule implements CameraModule, @Override public void onError(MediaRecorder mr, int what, int extra) { Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra); + stopVideoRecording(); if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { // We may have run out of space on the sdcard. - stopVideoRecording(); mActivity.updateStorageSpaceAndHint(); } } @@ -1171,22 +1489,51 @@ public class VideoModule implements CameraModule, private void startVideoRecording() { Log.v(TAG, "startVideoRecording"); + mStartRecPending = true; mUI.cancelAnimations(); mUI.setSwipingEnabled(false); mActivity.updateStorageSpaceAndHint(); if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) { Log.v(TAG, "Storage issue, ignore the start request"); + mStartRecPending = false; + return; + } + + if( mUnsupportedHFRVideoSize == true) { + Log.e(TAG, "Unsupported HFR and video size combinations"); + Toast.makeText(mActivity,R.string.error_app_unsupported_hfr, Toast.LENGTH_SHORT).show(); + mStartRecPending = false; return; } + if (mUnsupportedHSRVideoSize == true) { + Log.e(TAG, "Unsupported HSR and video size combinations"); + Toast.makeText(mActivity,R.string.error_app_unsupported_hsr, Toast.LENGTH_SHORT).show(); + mStartRecPending = false; + return; + } + + if( mUnsupportedHFRVideoCodec == true) { + Log.e(TAG, "Unsupported HFR and video codec combinations"); + Toast.makeText(mActivity, R.string.error_app_unsupported_hfr_codec, + Toast.LENGTH_SHORT).show(); + mStartRecPending = false; + return; + } //?? //if (!mCameraDevice.waitDone()) return; mCurrentVideoUri = null; initializeRecorder(); + if (mUnsupportedResolution == true) { + Log.v(TAG, "Unsupported Resolution according to target"); + mStartRecPending = false; + return; + } if (mMediaRecorder == null) { Log.e(TAG, "Fail to initialize media recorder"); + mStartRecPending = false; return; } @@ -1199,6 +1546,7 @@ public class VideoModule implements CameraModule, releaseMediaRecorder(); // If start fails, frameworks will not lock the camera for us. mCameraDevice.lock(); + mStartRecPending = false; return; } @@ -1219,7 +1567,10 @@ public class VideoModule implements CameraModule, mUI.enableCameraControls(false); mMediaRecorderRecording = true; + mMediaRecorderPausing = false; + mUI.resetPauseButton(); mOrientationManager.lockOrientation(); + mRecordingTotalTime = 0L; mRecordingStartTime = SystemClock.uptimeMillis(); mUI.showRecordingUI(true); @@ -1227,6 +1578,7 @@ public class VideoModule implements CameraModule, keepScreenOn(); UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_CAPTURE_START, "Video"); + mStartRecPending = false; } private Bitmap getVideoThumbnail() { @@ -1266,8 +1618,24 @@ public class VideoModule implements CameraModule, mUI.showTimeLapseUI(false); } + private void pauseVideoRecording() { + Log.v(TAG, "pauseVideoRecording"); + mMediaRecorderPausing = true; + mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime; + mMediaRecorder.pause(); + } + + private void resumeVideoRecording() { + Log.v(TAG, "resumeVideoRecording"); + mMediaRecorderPausing = false; + mRecordingStartTime = SystemClock.uptimeMillis(); + updateRecordingTime(); + mMediaRecorder.start(); + } + private boolean stopVideoRecording() { Log.v(TAG, "stopVideoRecording"); + mStopRecPending = true; mUI.setSwipingEnabled(true); if (!isVideoCaptureIntent()) { mUI.showSwitcher(); @@ -1293,6 +1661,12 @@ public class VideoModule implements CameraModule, fail = true; } mMediaRecorderRecording = false; + + //If recording stops while snapshot is in progress, we might not get jpeg callback + //because cameraservice will disable picture related messages. Hence reset the + //flag here so that we can take liveshots in the next recording session. + mSnapshotInProgress = false; + mOrientationManager.unlockOrientation(); // If the activity is paused, this means activity is interrupted @@ -1336,7 +1710,8 @@ public class VideoModule implements CameraModule, UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, fail ? UsageStatistics.ACTION_CAPTURE_FAIL : UsageStatistics.ACTION_CAPTURE_DONE, "Video", - SystemClock.uptimeMillis() - mRecordingStartTime); + SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime); + mStopRecPending = false; return fail; } @@ -1412,8 +1787,12 @@ public class VideoModule implements CameraModule, if (!mMediaRecorderRecording) { return; } + if (mMediaRecorderPausing) { + return; + } + long now = SystemClock.uptimeMillis(); - long delta = now - mRecordingStartTime; + long delta = now - mRecordingStartTime + mRecordingTotalTime; // Starting a minute before reaching the max duration // limit, we'll countdown the remaining time instead. @@ -1461,8 +1840,245 @@ public class VideoModule implements CameraModule, return supported == null ? false : supported.indexOf(value) >= 0; } + private void qcomSetCameraParameters(){ + // add QCOM Parameters here + // Set color effect parameter. + String colorEffect = mPreferences.getString( + CameraSettings.KEY_COLOR_EFFECT, + mActivity.getString(R.string.pref_camera_coloreffect_default)); + Log.v(TAG, "Color effect value =" + colorEffect); + if (isSupported(colorEffect, mParameters.getSupportedColorEffects())) { + mParameters.setColorEffect(colorEffect); + } + + String disMode = mPreferences.getString( + CameraSettings.KEY_DIS, + mActivity.getString(R.string.pref_camera_dis_default)); + Log.v(TAG, "DIS value =" + disMode); + if (isSupported(disMode, + CameraSettings.getSupportedDISModes(mParameters))) { + mParameters.set(CameraSettings.KEY_QC_DIS_MODE, disMode); + } + + if (mDefaultAntibanding == null) { + mDefaultAntibanding = mParameters.getAntibanding(); + Log.d(TAG, "default antibanding value = " + mDefaultAntibanding); + } + + if (disMode.equals("enable")) { + Log.d(TAG, "dis is enabled, set antibanding to auto."); + if (isSupported(Parameters.ANTIBANDING_AUTO, mParameters.getSupportedAntibanding())) { + mParameters.setAntibanding(Parameters.ANTIBANDING_AUTO); + } + } else { + if (isSupported(mDefaultAntibanding, mParameters.getSupportedAntibanding())) { + mParameters.setAntibanding(mDefaultAntibanding); + } + } + Log.d(TAG, "antiBanding value = " + mParameters.getAntibanding()); + + mUnsupportedHFRVideoSize = false; + mUnsupportedHFRVideoCodec = false; + // To set preview format as YV12 , run command + // "adb shell setprop "debug.camera.yv12" true" + String yv12formatset = SystemProperties.get("debug.camera.yv12"); + if(yv12formatset.equals("true")) { + Log.v(TAG, "preview format set to YV12"); + mParameters.setPreviewFormat (ImageFormat.YV12); + } + + // Set High Frame Rate. + String HighFrameRate = mPreferences.getString( + CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE, + mActivity. getString(R.string.pref_camera_hfr_default)); + + if(!("off".equals(HighFrameRate)) && !("hsr".equals(HighFrameRate))){ + mUnsupportedHFRVideoSize = true; + String hfrsize = videoWidth+"x"+videoHeight; + Log.v(TAG, "current set resolution is : "+hfrsize); + try { + Size size = null; + if (isSupported(HighFrameRate,mParameters.getSupportedVideoHighFrameRateModes())) { + int index = mParameters.getSupportedVideoHighFrameRateModes().indexOf( + HighFrameRate); + size = mParameters.getSupportedHfrSizes().get(index); + } + if (size != null) { + Log.v(TAG, "supported hfr size : "+ size.width+ " "+size.height); + if (videoWidth <= size.width && videoHeight <= size.height) { + mUnsupportedHFRVideoSize = false; + Log.v(TAG,"Current hfr resolution is supported"); + } + } + } catch (NullPointerException e){ + Log.e(TAG, "supported hfr sizes is null"); + } + + int hfrFps = Integer.parseInt(HighFrameRate); + int inputBitrate = videoWidth*videoHeight*hfrFps; + + //check if codec supports the resolution, otherwise throw toast + List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders(); + for (VideoEncoderCap videoEncoder: videoEncoders) { + if (videoEncoder.mCodec == mVideoEncoder){ + int maxBitrate = (videoEncoder.mMaxHFRFrameWidth * + videoEncoder.mMaxHFRFrameHeight * + videoEncoder.mMaxHFRMode); + if (inputBitrate > maxBitrate ){ + Log.e(TAG,"Selected codec "+mVideoEncoder+ + " does not support HFR " + HighFrameRate + " with "+ videoWidth + + "x" + videoHeight +" resolution"); + Log.e(TAG, "Codec capabilities: " + + "mMaxHFRFrameWidth = " + videoEncoder.mMaxHFRFrameWidth + " , "+ + "mMaxHFRFrameHeight = " + videoEncoder.mMaxHFRFrameHeight + " , "+ + "mMaxHFRMode = " + videoEncoder.mMaxHFRMode); + mUnsupportedHFRVideoSize = true; + } + break; + } + } + + if(mUnsupportedHFRVideoSize) + Log.v(TAG,"Unsupported hfr resolution"); + + if(mVideoEncoder != MediaRecorder.VideoEncoder.H264) + mUnsupportedHFRVideoCodec = true; + } + if (isSupported(HighFrameRate, + mParameters.getSupportedVideoHighFrameRateModes()) && + !mUnsupportedHFRVideoSize && + !("hsr".equals(HighFrameRate))) { + mParameters.setVideoHighFrameRate(HighFrameRate); + mParameters.set("video-hsr", "off"); + } + else { + mParameters.setVideoHighFrameRate("off"); + } + mUnsupportedHSRVideoSize = false; + + if (("hsr".equals(HighFrameRate))) { + mUnsupportedHSRVideoSize = true; + String hsrsize = videoWidth+"x"+videoHeight; + Log.v(TAG, "current set resolution is : "+hsrsize); + try { + Size size = null; + if (isSupported("120",mParameters.getSupportedVideoHighFrameRateModes())) { + int index = mParameters.getSupportedVideoHighFrameRateModes().indexOf( + "120"); + size = mParameters.getSupportedHfrSizes().get(index); + } + if (size != null) { + Log.v(TAG, "supported hsr size : "+ size.width+ " "+size.height); + if (videoWidth <= size.width && videoHeight <= size.height) { + mUnsupportedHSRVideoSize = false; + Log.v(TAG,"Current hsr resolution is supported"); + } + } + } catch (NullPointerException e) { + Log.e(TAG, "supported hfr sizes is null"); + } + + if (mUnsupportedHSRVideoSize) Log.v(TAG,"Unsupported hsr resolution"); + } + + if (("hsr".equals(HighFrameRate)) && !mUnsupportedHSRVideoSize) { + mParameters.set("video-hsr", "on"); + } + else { + mParameters.set("video-hsr", "off"); + } + + // Read Flip mode from adb command + //value: 0(default) - FLIP_MODE_OFF + //value: 1 - FLIP_MODE_H + //value: 2 - FLIP_MODE_V + //value: 3 - FLIP_MODE_VH + int preview_flip_value = SystemProperties.getInt("debug.camera.preview.flip", 0); + int video_flip_value = SystemProperties.getInt("debug.camera.video.flip", 0); + int picture_flip_value = SystemProperties.getInt("debug.camera.picture.flip", 0); + int rotation = CameraUtil.getJpegRotation(mCameraId, mOrientation); + mParameters.setRotation(rotation); + if (rotation == 90 || rotation == 270) { + // in case of 90 or 270 degree, V/H flip should reverse + if (preview_flip_value == 1) { + preview_flip_value = 2; + } else if (preview_flip_value == 2) { + preview_flip_value = 1; + } + if (video_flip_value == 1) { + video_flip_value = 2; + } else if (video_flip_value == 2) { + video_flip_value = 1; + } + if (picture_flip_value == 1) { + picture_flip_value = 2; + } else if (picture_flip_value == 2) { + picture_flip_value = 1; + } + } + String preview_flip = CameraUtil.getFilpModeString(preview_flip_value); + String video_flip = CameraUtil.getFilpModeString(video_flip_value); + String picture_flip = CameraUtil.getFilpModeString(picture_flip_value); + + if(CameraUtil.isSupported(preview_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_PREVIEW_FLIP, preview_flip); + } + if(CameraUtil.isSupported(video_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_VIDEO_FLIP, video_flip); + } + if(CameraUtil.isSupported(picture_flip, CameraSettings.getSupportedFlipMode(mParameters))){ + mParameters.set(CameraSettings.KEY_QC_SNAPSHOT_PICTURE_FLIP, picture_flip); + } + + // Set Video HDR. + String videoHDR = mPreferences.getString( + CameraSettings.KEY_VIDEO_HDR, + mActivity.getString(R.string.pref_camera_video_hdr_default)); + Log.v(TAG, "Video HDR Setting =" + videoHDR); + if (isSupported(videoHDR, mParameters.getSupportedVideoHDRModes())) { + mParameters.setVideoHDRMode(videoHDR); + } else + mParameters.setVideoHDRMode("off"); + + //HFR/HSR recording not supported with DIS,TimeLapse,HDR option + String hfr = mParameters.getVideoHighFrameRate(); + String hsr = mParameters.get("video-hsr"); + String hdr = mParameters.getVideoHDRMode(); + if ( ((hfr != null) && (!hfr.equals("off"))) || + ((hsr != null) && (!hsr.equals("off"))) ) { + // Read time lapse recording interval. + String frameIntervalStr = mPreferences.getString( + CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, + mActivity.getString(R.string.pref_video_time_lapse_frame_interval_default)); + int timeLapseInterval = Integer.parseInt(frameIntervalStr); + if ( (timeLapseInterval != 0) || + (disMode.equals("enable")) || + ((hdr != null) && (!hdr.equals("off"))) ) { + Log.v(TAG,"HDR/DIS/Time Lapse ON for HFR/HSR selection, turning HFR/HSR off"); + Toast.makeText(mActivity, R.string.error_app_unsupported_hfr_selection, + Toast.LENGTH_LONG).show(); + mParameters.setVideoHighFrameRate("off"); + mParameters.set("video-hsr", "off"); + mUI.overrideSettings(CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,"off"); + } + } + + //getSupportedPictureSizes will always send a sorted a list in descending order + Size biggestSize = mParameters.getSupportedPictureSizes().get(0); + + if (biggestSize.width <= videoWidth || biggestSize.height <= videoHeight) { + if (disMode.equals("enable")) { + Log.v(TAG,"DIS is not supported for this video quality"); + Toast.makeText(mActivity, R.string.error_app_unsupported_dis, + Toast.LENGTH_LONG).show(); + mParameters.set(CameraSettings.KEY_QC_DIS_MODE, "disable"); + mUI.overrideSettings(CameraSettings.KEY_DIS,"disable"); + } + } + } @SuppressWarnings("deprecation") private void setCameraParameters() { + Log.d(TAG,"Preview dimension in App->"+mDesiredPreviewWidth+"X"+mDesiredPreviewHeight); mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight); mParameters.set("video-size", mProfile.videoFrameWidth+"x"+mProfile.videoFrameHeight); int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters); @@ -1474,8 +2090,12 @@ public class VideoModule implements CameraModule, mParameters.setPreviewFrameRate(mProfile.videoFrameRate); } - forceFlashOffIfSupported(!mUI.isVisible()); - + forceFlashOffIfSupported(!mPreviewFocused); + videoWidth = mProfile.videoFrameWidth; + videoHeight = mProfile.videoFrameHeight; + String recordSize = videoWidth + "x" + videoHeight; + Log.e(TAG,"Video dimension in App->"+recordSize); + mParameters.set("video-size", recordSize); // Set white balance parameter. String whiteBalance = mPreferences.getString( CameraSettings.KEY_WHITE_BALANCE, @@ -1492,6 +2112,8 @@ public class VideoModule implements CameraModule, // Set zoom. if (mParameters.isZoomSupported()) { + Parameters p = mCameraDevice.getParameters(); + mZoomValue = p.getZoom(); mParameters.setZoom(mZoomValue); } @@ -1528,6 +2150,8 @@ public class VideoModule implements CameraModule, int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, CameraProfile.QUALITY_HIGH); mParameters.setJpegQuality(jpegQuality); + //Call Qcom related Camera Parameters + qcomSetCameraParameters(); boolean flag = false; if (mPreviewing) { @@ -1554,6 +2178,7 @@ public class VideoModule implements CameraModule, public void onConfigurationChanged(Configuration newConfig) { Log.v(TAG, "onConfigurationChanged"); setDisplayOrientation(); + resizeForPreviewAspectRatio(); } @Override @@ -1566,6 +2191,11 @@ public class VideoModule implements CameraModule, } @Override + public void onSharedPreferenceChanged(ListPreference pref) { + onSharedPreferenceChanged(); + } + + @Override public void onSharedPreferenceChanged() { // ignore the events after "onPause()" or preview has not started yet if (mPaused) { @@ -1585,7 +2215,7 @@ public class VideoModule implements CameraModule, // We need to restart the preview if preview size is changed. Size size = mParameters.getPreviewSize(); if (size.width != mDesiredPreviewWidth - || size.height != mDesiredPreviewHeight) { + || size.height != mDesiredPreviewHeight || mRestartPreview) { stopPreview(); resizeForPreviewAspectRatio(); @@ -1593,7 +2223,11 @@ public class VideoModule implements CameraModule, } else { setCameraParameters(); } + mRestartPreview = false; mUI.updateOnScreenIndicators(mParameters, mPreferences); + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + mActivity.updateStorageSpaceAndHint(); } } @@ -1633,6 +2267,9 @@ public class VideoModule implements CameraModule, // onFrameAvailable from the old camera may already exist. mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); mUI.updateOnScreenIndicators(mParameters, mPreferences); + + //Display timelapse msg depending upon selection in front/back camera. + mUI.showTimeLapseUI(mCaptureTimeLapse); } // Preview texture has been copied. Now camera can be released and the @@ -1712,6 +2349,7 @@ public class VideoModule implements CameraModule, public void onPreviewFocusChanged(boolean previewFocused) { mUI.onPreviewFocusChanged(previewFocused); forceFlashOff(!previewFocused); + mPreviewFocused = previewFocused; } @Override @@ -1729,6 +2367,7 @@ public class VideoModule implements CameraModule, @Override public void onPictureTaken(byte [] jpegData, CameraProxy camera) { Log.v(TAG, "onPictureTaken"); + if(!mSnapshotInProgress || mPaused || mCameraDevice == null) return; mSnapshotInProgress = false; showVideoSnapshotUI(false); storeImage(jpegData, mLocation); @@ -1740,10 +2379,11 @@ public class VideoModule implements CameraModule, String title = CameraUtil.createJpegName(dateTaken); ExifInterface exif = Exif.getExif(data); int orientation = Exif.getOrientation(exif); - + Size s = mParameters.getPictureSize(); mActivity.getMediaSaveService().addImage( - data, title, dateTaken, loc, orientation, - exif, mOnPhotoSavedListener, mContentResolver); + data, title, dateTaken, loc, s.width, s.height, orientation, + exif, mOnPhotoSavedListener, mContentResolver, + PhotoModule.PIXEL_FORMAT_JPEG); } private String convertOutputFormatToMimeType(int outputFileFormat) { @@ -1820,4 +2460,15 @@ public class VideoModule implements CameraModule, public void onPreviewUIDestroyed() { stopPreview(); } + + @Override + public void onButtonPause() { + pauseVideoRecording(); + } + + @Override + public void onButtonContinue() { + resumeVideoRecording(); + } + } diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java index a8819e054..9ffd1a113 100644 --- a/src/com/android/camera/VideoUI.java +++ b/src/com/android/camera/VideoUI.java @@ -16,6 +16,7 @@ package com.android.camera; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Matrix; @@ -48,6 +49,7 @@ import com.android.camera.ui.ModuleSwitcher; import com.android.camera.ui.PieRenderer; import com.android.camera.ui.RenderOverlay; import com.android.camera.ui.RotateLayout; +import com.android.camera.PauseButton.OnPauseButtonListener; import com.android.camera.ui.ZoomRenderer; import com.android.camera.util.CameraUtil; import com.android.camera2.R; @@ -57,7 +59,8 @@ import java.util.List; public class VideoUI implements PieRenderer.PieListener, PreviewGestures.SingleTapListener, CameraRootView.MyDisplayListener, - SurfaceTextureListener, SurfaceHolder.Callback { + SurfaceTextureListener, SurfaceHolder.Callback, + PauseButton.OnPauseButtonListener { private static final String TAG = "CAM_VideoUI"; private static final int UPDATE_TRANSFORM_MATRIX = 1; // module fields @@ -71,6 +74,7 @@ public class VideoUI implements PieRenderer.PieListener, private View mReviewDoneButton; private View mReviewPlayButton; private ShutterButton mShutterButton; + private PauseButton mPauseButton; private ModuleSwitcher mSwitcher; private TextView mRecordingTimeView; private LinearLayout mLabelsLinearLayout; @@ -92,6 +96,9 @@ public class VideoUI implements PieRenderer.PieListener, private List<Integer> mZoomRatios; private View mPreviewThumb; private View mFlashOverlay; + private boolean mOrientationResize; + private boolean mPrevOrientationResize; + private boolean mIsTimeLapse = false; private View mPreviewCover; private SurfaceView mSurfaceView = null; @@ -100,6 +107,7 @@ public class VideoUI implements PieRenderer.PieListener, private float mSurfaceTextureUncroppedWidth; private float mSurfaceTextureUncroppedHeight; private float mAspectRatio = 4f / 3f; + private boolean mAspectRatioResize; private Matrix mMatrix = null; private final AnimationManager mAnimationManager; private final Handler mHandler = new Handler() { @@ -127,10 +135,13 @@ public class VideoUI implements PieRenderer.PieListener, w = height; h = width; } - if (mPreviewWidth != width || mPreviewHeight != height) { + if (mPreviewWidth != width || mPreviewHeight != height + || (mOrientationResize != mPrevOrientationResize) + || (mAspectRatioResize)) { mPreviewWidth = width; mPreviewHeight = height; onScreenSizeChanged(width, height, w, h); + mAspectRatioResize = false; } } }; @@ -185,9 +196,16 @@ public class VideoUI implements PieRenderer.PieListener, initializeMiscControls(); initializeControlByIntent(); initializeOverlay(); + initializePauseButton(); mAnimationManager = new AnimationManager(); + mOrientationResize = false; + mPrevOrientationResize = false; } + public void cameraOrientationPreviewResize(boolean orientation){ + mPrevOrientationResize = mOrientationResize; + mOrientationResize = orientation; + } public void initializeSurfaceView() { mSurfaceView = new SurfaceView(mActivity); @@ -247,10 +265,21 @@ public class VideoUI implements PieRenderer.PieListener, Log.w(TAG, "Preview size should not be 0."); return; } + float ratio; if (width > height) { - mAspectRatio = (float) width / height; + ratio = (float) width / height; } else { - mAspectRatio = (float) height / width; + ratio = (float) height / width; + } + if (mOrientationResize && + mActivity.getResources().getConfiguration().orientation + != Configuration.ORIENTATION_PORTRAIT) { + ratio = 1 / ratio; + } + + if (ratio != mAspectRatio){ + mAspectRatioResize = true; + mAspectRatio = ratio; } mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); } @@ -272,16 +301,26 @@ public class VideoUI implements PieRenderer.PieListener, int orientation = CameraUtil.getDisplayRotation(mActivity); float scaleX = 1f, scaleY = 1f; float scaledTextureWidth, scaledTextureHeight; - if (width > height) { - scaledTextureWidth = Math.max(width, - (int) (height * mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int)(width / mAspectRatio)); + if (mOrientationResize){ + if (width/mAspectRatio > height){ + scaledTextureHeight = height; + scaledTextureWidth = (int)(height * mAspectRatio + 0.5f); + } else { + scaledTextureWidth = width; + scaledTextureHeight = (int)(width / mAspectRatio + 0.5f); + } } else { - scaledTextureWidth = Math.max(width, - (int) (height / mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int) (width * mAspectRatio)); + if (width > height) { + scaledTextureWidth = Math.max(width, + (int) (height * mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int)(width / mAspectRatio)); + } else { + scaledTextureWidth = Math.max(width, + (int) (height / mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int) (width * mAspectRatio)); + } } if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || @@ -480,6 +519,11 @@ public class VideoUI implements PieRenderer.PieListener, mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels); } + private void initializePauseButton() { + mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause); + mPauseButton.setOnPauseButtonListener(this); + } + public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) { mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode()); boolean location = RecordLocationPreference.get( @@ -489,13 +533,25 @@ public class VideoUI implements PieRenderer.PieListener, } public void setAspectRatio(double ratio) { - // mPreviewFrameLayout.setAspectRatio(ratio); + if (mOrientationResize && + mActivity.getResources().getConfiguration().orientation + != Configuration.ORIENTATION_PORTRAIT) { + ratio = 1 / ratio; + } + + if (ratio != mAspectRatio){ + mAspectRatioResize = true; + mAspectRatio = (float)ratio; + } + mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); + } public void showTimeLapseUI(boolean enable) { if (mTimeLapseLabel != null) { mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE); } + mIsTimeLapse = enable; } private void openMenu() { @@ -586,12 +642,14 @@ public class VideoUI implements PieRenderer.PieListener, hideSwitcher(); mRecordingTimeView.setText(""); mRecordingTimeView.setVisibility(View.VISIBLE); + mPauseButton.setVisibility(mIsTimeLapse ? View.GONE : View.VISIBLE); } else { mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); if (!mController.isVideoCaptureIntent()) { showSwitcher(); } mRecordingTimeView.setVisibility(View.GONE); + mPauseButton.setVisibility(View.GONE); } } @@ -620,6 +678,8 @@ public class VideoUI implements PieRenderer.PieListener, } private void setShowMenu(boolean show) { + if (mController.isVideoCaptureIntent()) + return; if (mOnScreenIndicators != null) { mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); } @@ -705,10 +765,17 @@ public class VideoUI implements PieRenderer.PieListener, @Override public void onZoomStart() { + if (mPieRenderer != null) { + if (!mRecordingStarted) mPieRenderer.hide(); + mPieRenderer.setBlockFocus(true); + } } @Override public void onZoomEnd() { + if (mPieRenderer != null) { + mPieRenderer.setBlockFocus(false); + } } } @@ -759,4 +826,24 @@ public class VideoUI implements PieRenderer.PieListener, Log.v(TAG, "Surface destroyed"); mController.stopPreview(); } + + @Override + public void onButtonPause() { + mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_pausing_indicator, 0, 0, 0); + mController.onButtonPause(); + } + + @Override + public void onButtonContinue() { + mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_recording_indicator, 0, 0, 0); + mController.onButtonContinue(); + } + + public void resetPauseButton() { + mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_recording_indicator, 0, 0, 0); + mPauseButton.setPaused(false); + } } diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java index 34b3071a4..f6daa6019 100644 --- a/src/com/android/camera/WideAnglePanoramaModule.java +++ b/src/com/android/camera/WideAnglePanoramaModule.java @@ -43,7 +43,7 @@ import android.view.OrientationEventListener; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; - +import com.android.camera.PhotoModule; import com.android.camera.CameraManager.CameraProxy; import com.android.camera.app.OrientationManager; import com.android.camera.data.LocalData; @@ -482,9 +482,24 @@ public class WideAnglePanoramaModule @Override public void onPreviewUILayoutChange(int l, int t, int r, int b) { Log.d(TAG, "layout change: " + (r - l) + "/" + (b - t)); + boolean capturePending = false; + if (mCaptureState == CAPTURE_STATE_MOSAIC){ + capturePending = true; + } mPreviewUIWidth = r - l; mPreviewUIHeight = b - t; configMosaicPreview(); + if (capturePending == true){ + mMainHandler.post(new Runnable() { + @Override + public void run() { + if (!mPaused){ + mMainHandler.removeMessages(MSG_RESET_TO_PREVIEW); + startCapture(); + } + } + }); + } } @Override @@ -509,9 +524,11 @@ public class WideAnglePanoramaModule float progressX, float progressY) { float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle; float accumulatedVerticalAngle = progressY * mVerticalViewAngle; + boolean isRotated = !(mDeviceOrientationAtCapture == mDeviceOrientation); if (isFinished || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE) - || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) { + || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE) + || isRotated) { stopCapture(false); } else { float panningRateXInDegree = panningRateX * mHorizontalViewAngle; @@ -641,7 +658,7 @@ public class WideAnglePanoramaModule if (mUsingFrontCamera) { // mCameraOrientation is negative with respect to the front facing camera. // See document of android.hardware.Camera.Parameters.setRotation. - orientation = (mDeviceOrientationAtCapture - mCameraOrientation + 360) % 360; + orientation = (mDeviceOrientationAtCapture - mCameraOrientation - 360) % 360; } else { orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; } @@ -742,7 +759,8 @@ public class WideAnglePanoramaModule if (jpegData != null) { String filename = PanoUtil.createName( mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken); - String filepath = Storage.generateFilepath(filename); + String filepath = Storage.generateFilepath(filename, + PhotoModule.PIXEL_FORMAT_JPEG); UsageStatistics.onEvent(UsageStatistics.COMPONENT_PANORAMA, UsageStatistics.ACTION_CAPTURE_DONE, null, 0, @@ -854,6 +872,10 @@ public class WideAnglePanoramaModule } @Override + public void resizeForPreviewAspectRatio() { + } + + @Override public void onResumeBeforeSuper() { mPaused = false; } @@ -874,7 +896,7 @@ public class WideAnglePanoramaModule // Check if another panorama instance is using the mosaic frame processor. mUI.dismissAllDialogs(); - if (!mThreadRunning && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { + if (mThreadRunning && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { mUI.showWaitingDialog(mDialogWaitingPreviousString); // If stitching is still going on, make sure switcher and shutter button // are not showing @@ -888,7 +910,12 @@ public class WideAnglePanoramaModule mPreviewUIWidth = size.x; mPreviewUIHeight = size.y; configMosaicPreview(); - mActivity.updateStorageSpaceAndHint(); + mMainHandler.post(new Runnable(){ + @Override + public void run(){ + mActivity.updateStorageSpaceAndHint(); + } + }); } keepScreenOnAwhile(); @@ -976,8 +1003,12 @@ public class WideAnglePanoramaModule // Set the display orientation to 0, so that the underlying mosaic // library can always get undistorted mCameraPreviewWidth x mCameraPreviewHeight // image data from SurfaceTexture. + // as Panoroma will add 90 degree rotation compensation during + // postprocessing, we need to consider both camera mount angle and + // this compensation angle mCameraDevice.setDisplayOrientation(0); + if (mCameraTexture != null) mCameraTexture.setOnFrameAvailableListener(this); mCameraDevice.setPreviewTexture(mCameraTexture); } diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java index 268c82b2b..f41653982 100644 --- a/src/com/android/camera/WideAnglePanoramaUI.java +++ b/src/com/android/camera/WideAnglePanoramaUI.java @@ -290,6 +290,7 @@ public class WideAnglePanoramaUI implements mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mReviewControl.removeAllViews(); + ((ViewGroup) mReviewControl).clearDisappearingChildren(); inflater.inflate(R.layout.pano_review_control, mReviewControl, true); mRootView.bringChildToFront(mCameraControls); @@ -321,6 +322,9 @@ public class WideAnglePanoramaUI implements } @Override + public void onShutterButtonLongClick() {} + + @Override public void onLayoutChange( View v, int l, int t, int r, int b, int oldl, int oldt, int oldr, int oldb) { diff --git a/src/com/android/camera/app/AppManagerFactory.java b/src/com/android/camera/app/AppManagerFactory.java index 43d2a00cd..5cd70a796 100644 --- a/src/com/android/camera/app/AppManagerFactory.java +++ b/src/com/android/camera/app/AppManagerFactory.java @@ -29,7 +29,7 @@ public class AppManagerFactory { public static synchronized AppManagerFactory getInstance(Context ctx) { if (sFactory == null) { - sFactory = new AppManagerFactory(ctx); + sFactory = new AppManagerFactory(ctx.getApplicationContext()); } return sFactory; } diff --git a/src/com/android/camera/crop/ImageLoader.java b/src/com/android/camera/crop/ImageLoader.java index 9eae63e8a..2fa54a19d 100644 --- a/src/com/android/camera/crop/ImageLoader.java +++ b/src/com/android/camera/crop/ImageLoader.java @@ -79,7 +79,9 @@ public final class ImageLoader { } int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); - return cursor.getString(index); + String path = cursor.getString(index); + Utils.closeSilently(cursor); + return path; } /** diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java index 99bde4181..4643d03bf 100644 --- a/src/com/android/camera/data/CameraDataAdapter.java +++ b/src/com/android/camera/data/CameraDataAdapter.java @@ -27,6 +27,7 @@ import android.provider.MediaStore; import android.util.Log; import android.view.View; +import com.android.camera.SDCard; import com.android.camera.Storage; import com.android.camera.app.PlaceholderManager; import com.android.camera.ui.FilmStripView.ImageData; @@ -41,7 +42,7 @@ public class CameraDataAdapter implements LocalDataAdapter { private static final String TAG = "CAM_CameraDataAdapter"; private static final int DEFAULT_DECODE_SIZE = 1600; - private static final String[] CAMERA_PATH = { Storage.DIRECTORY + "%" }; + private static final String[] CAMERA_PATH = { Storage.DIRECTORY + "/%" ,SDCard.instance().getDirectory() + "/%"}; private LocalDataList mImages; @@ -135,20 +136,26 @@ public class CameraDataAdapter implements LocalDataAdapter { public void addNewVideo(ContentResolver cr, Uri uri) { Cursor c = cr.query(uri, LocalMediaData.VideoData.QUERY_PROJECTION, - MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH, + MediaStore.Video.Media.DATA + " like ? or " + + MediaStore.Video.Media.DATA + " like ? ", CAMERA_PATH, LocalMediaData.VideoData.QUERY_ORDER); if (c == null || !c.moveToFirst()) { return; } int pos = findDataByContentUri(uri); LocalMediaData.VideoData newData = LocalMediaData.VideoData.buildFromCursor(c); - if (pos != -1) { - // A duplicate one, just do a substitute. - updateData(pos, newData); + if (newData != null) { + if (pos != -1) { + // A duplicate one, just do a substitute. + updateData(pos, newData); + } else { + // A new data. + insertData(newData); + } } else { - // A new data. - insertData(newData); + Log.e(TAG, "video data not found"); } + c.close(); } // TODO: put the database query on background thread @@ -156,6 +163,7 @@ public class CameraDataAdapter implements LocalDataAdapter { public void addNewPhoto(ContentResolver cr, Uri uri) { Cursor c = cr.query(uri, LocalMediaData.PhotoData.QUERY_PROJECTION, + MediaStore.Images.Media.DATA + " like ? or " + MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH, LocalMediaData.PhotoData.QUERY_ORDER); if (c == null || !c.moveToFirst()) { @@ -171,6 +179,7 @@ public class CameraDataAdapter implements LocalDataAdapter { // a new data. insertData(newData); } + c.close(); } @Override @@ -279,6 +288,7 @@ public class CameraDataAdapter implements LocalDataAdapter { Cursor c = resolver[0].query( LocalMediaData.PhotoData.CONTENT_URI, LocalMediaData.PhotoData.QUERY_PROJECTION, + MediaStore.Images.Media.DATA + " like ? or " + MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH, LocalMediaData.PhotoData.QUERY_ORDER); if (c != null && c.moveToFirst()) { @@ -308,6 +318,7 @@ public class CameraDataAdapter implements LocalDataAdapter { c = resolver[0].query( LocalMediaData.VideoData.CONTENT_URI, LocalMediaData.VideoData.QUERY_PROJECTION, + MediaStore.Video.Media.DATA + " like ? or " + MediaStore.Video.Media.DATA + " like ? ", CAMERA_PATH, LocalMediaData.VideoData.QUERY_ORDER); if (c != null && c.moveToFirst()) { diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java index 1f9c725d0..fe5610863 100644 --- a/src/com/android/camera/data/LocalMediaData.java +++ b/src/com/android/camera/data/LocalMediaData.java @@ -457,6 +457,7 @@ public abstract class LocalMediaData implements LocalData { return null; } PhotoData newData = buildFromCursor(c); + c.close(); return newData; } @@ -636,6 +637,14 @@ public abstract class LocalMediaData implements LocalData { int height = c.getInt(COL_HEIGHT); MediaMetadataRetriever retriever = new MediaMetadataRetriever(); String rotation = null; + + File origFile = new File(path); + if (!origFile.exists() || origFile.length() <= 0) { + Log.e(TAG, "Invalid video file"); + retriever.release(); + return null; + } + try { retriever.setDataSource(path); } catch (RuntimeException ex) { @@ -736,6 +745,7 @@ public abstract class LocalMediaData implements LocalData { return null; } VideoData newData = buildFromCursor(c); + c.close(); return newData; } diff --git a/src/com/android/camera/tinyplanet/TinyPlanetFragment.java b/src/com/android/camera/tinyplanet/TinyPlanetFragment.java index 9cde87b16..d1d5af91c 100644 --- a/src/com/android/camera/tinyplanet/TinyPlanetFragment.java +++ b/src/com/android/camera/tinyplanet/TinyPlanetFragment.java @@ -43,6 +43,7 @@ import com.adobe.xmp.XMPException; import com.adobe.xmp.XMPMeta; import com.android.camera.CameraActivity; import com.android.camera.MediaSaveService; +import com.android.camera.PhotoModule; import com.android.camera.MediaSaveService.OnMediaSavedListener; import com.android.camera.exif.ExifInterface; import com.android.camera.tinyplanet.TinyPlanetPreview.PreviewSizeListener; @@ -321,7 +322,7 @@ public class TinyPlanetFragment extends DialogFragment implements PreviewSizeLis mediaSaveService.addImage(image.mJpegData, tinyPlanetTitle, (new Date()).getTime(), null, image.mSize, image.mSize, 0, null, doneListener, getActivity() - .getContentResolver()); + .getContentResolver(),PhotoModule.PIXEL_FORMAT_JPEG); } }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } diff --git a/src/com/android/camera/ui/FaceView.java b/src/com/android/camera/ui/FaceView.java index 1b3a9c72e..1868e0a38 100644 --- a/src/com/android/camera/ui/FaceView.java +++ b/src/com/android/camera/ui/FaceView.java @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Color; import android.graphics.Paint.Style; import android.graphics.RectF; import android.hardware.Camera.Face; @@ -33,6 +34,7 @@ import android.view.View; import com.android.camera.PhotoUI; import com.android.camera.util.CameraUtil; import com.android.camera2.R; +import org.codeaurora.camera.ExtendedFace; public class FaceView extends View implements FocusIndicator, Rotatable, @@ -63,6 +65,11 @@ public class FaceView extends View private int mUncroppedWidth; private int mUncroppedHeight; + + private final int smile_threashold_no_smile = 30; + private final int smile_threashold_small_smile = 60; + private final int blink_threshold = 60; + private static final int MSG_SWITCH_FACES = 1; private static final int SWITCH_DELAY = 70; private boolean mStateSwitchPending = false; @@ -90,6 +97,9 @@ public class FaceView extends View mPaint.setAntiAlias(true); mPaint.setStyle(Style.STROKE); mPaint.setStrokeWidth(res.getDimension(R.dimen.face_circle_stroke)); + mPaint.setDither(true); + mPaint.setColor(Color.WHITE);//setColor(0xFFFFFF00); + mPaint.setStrokeCap(Paint.Cap.ROUND); } @Override @@ -215,6 +225,161 @@ public class FaceView extends View mPaint.setColor(mColor); mRect.offset(dx, dy); canvas.drawOval(mRect, mPaint); + if (mFaces[i] instanceof ExtendedFace) { + ExtendedFace face = (ExtendedFace)mFaces[i]; + float[] point = new float[4]; + int delta_x = mFaces[i].rect.width() / 12; + int delta_y = mFaces[i].rect.height() / 12; + Log.e(TAG, "blink: (" + face.getLeftEyeBlinkDegree()+ ", " + + face.getRightEyeBlinkDegree() + ")"); + if (face.leftEye != null) { + if ((mDisplayOrientation == 90) || + (mDisplayOrientation == 270)) { + point[0] = face.leftEye.x; + point[1] = face.leftEye.y - delta_y / 2; + point[2] = face.leftEye.x; + point[3] = face.leftEye.y + delta_y / 2; + } else { + point[0] = face.leftEye.x - delta_x / 2; + point[1] = face.leftEye.y; + point[2] = face.leftEye.x + delta_x / 2; + point[3] = face.leftEye.y; + + } + mMatrix.mapPoints (point); + if (face.getLeftEyeBlinkDegree() >= blink_threshold) { + canvas.drawLine(point[0]+ dx, point[1]+ dy, + point[2]+ dx, point[3]+ dy, mPaint); + } + } + if (face.rightEye != null) { + if ((mDisplayOrientation == 90) || + (mDisplayOrientation == 270)) { + point[0] = face.rightEye.x; + point[1] = face.rightEye.y - delta_y / 2; + point[2] = face.rightEye.x; + point[3] = face.rightEye.y + delta_y / 2; + } else { + point[0] = face.rightEye.x - delta_x / 2; + point[1] = face.rightEye.y; + point[2] = face.rightEye.x + delta_x / 2; + point[3] = face.rightEye.y; + } + mMatrix.mapPoints (point); + if (face.getRightEyeBlinkDegree() >= blink_threshold) { + //Add offset to the points if the rect has an offset + canvas.drawLine(point[0] + dx, point[1] + dy, + point[2] +dx, point[3] +dy, mPaint); + } + } + + if (face.getLeftRightGazeDegree() != 0 + || face.getTopBottomGazeDegree() != 0 ) { + + double length = + Math.sqrt((face.leftEye.x - face.rightEye.x) * + (face.leftEye.x - face.rightEye.x) + + (face.leftEye.y - face.rightEye.y) * + (face.leftEye.y - face.rightEye.y)) / 2.0; + double nGazeYaw = -face.getLeftRightGazeDegree(); + double nGazePitch = -face.getTopBottomGazeDegree(); + float gazeRollX = + (float)((-Math.sin(nGazeYaw/180.0*Math.PI) * + Math.cos(-face.getRollDirection()/ + 180.0*Math.PI) + + Math.sin(nGazePitch/180.0*Math.PI) * + Math.cos(nGazeYaw/180.0*Math.PI) * + Math.sin(-face.getRollDirection()/ + 180.0*Math.PI)) * + (-length) + 0.5); + float gazeRollY = + (float)((Math.sin(-nGazeYaw/180.0*Math.PI) * + Math.sin(-face.getRollDirection()/ + 180.0*Math.PI)- + Math.sin(nGazePitch/180.0*Math.PI) * + Math.cos(nGazeYaw/180.0*Math.PI) * + Math.cos(-face.getRollDirection()/ + 180.0*Math.PI)) * + (-length) + 0.5); + + if (face.getLeftEyeBlinkDegree() < blink_threshold) { + if ((mDisplayOrientation == 90) || + (mDisplayOrientation == 270)) { + point[0] = face.leftEye.x; + point[1] = face.leftEye.y; + point[2] = face.leftEye.x + gazeRollX; + point[3] = face.leftEye.y + gazeRollY; + } else { + point[0] = face.leftEye.x; + point[1] = face.leftEye.y; + point[2] = face.leftEye.x + gazeRollY; + point[3] = face.leftEye.y + gazeRollX; + } + mMatrix.mapPoints (point); + canvas.drawLine(point[0] +dx, point[1] + dy, + point[2] + dx, point[3] +dy, mPaint); + } + + if (face.getRightEyeBlinkDegree() < blink_threshold) { + if ((mDisplayOrientation == 90) || + (mDisplayOrientation == 270)) { + point[0] = face.rightEye.x; + point[1] = face.rightEye.y; + point[2] = face.rightEye.x + gazeRollX; + point[3] = face.rightEye.y + gazeRollY; + } else { + point[0] = face.rightEye.x; + point[1] = face.rightEye.y; + point[2] = face.rightEye.x + gazeRollY; + point[3] = face.rightEye.y + gazeRollX; + + } + mMatrix.mapPoints (point); + canvas.drawLine(point[0] + dx, point[1] + dy, + point[2] + dx, point[3] + dy, mPaint); + } + } + + if (face.mouth != null) { + Log.e(TAG, "smile: " + face.getSmileDegree() + "," + + face.getSmileScore()); + if (face.getSmileDegree() < smile_threashold_no_smile) { + + if ((mDisplayOrientation == 90) || + (mDisplayOrientation == 270)) { + point[0] = face.mouth.x; + point[1] = face.mouth.y - delta_y; + point[2] = face.mouth.x; + point[3] = face.mouth.y + delta_y; + } else { + point[0] = face.mouth.x - delta_x; + point[1] = face.mouth.y; + point[2] = face.mouth.x + delta_x ; + point[3] = face.mouth.y; + } + mMatrix.mapPoints (point); + canvas.drawLine(point[0] + dx, point[1] + dy, + point[2] + dx, point[3] + dy, mPaint); + + } else if (face.getSmileDegree() < + smile_threashold_small_smile) { + + mRect.set(face.mouth.x-delta_x, + face.mouth.y-delta_y, face.mouth.x+delta_x, + face.mouth.y+delta_y); + mMatrix.mapRect(mRect); + mRect.offset(dx, dy); + canvas.drawArc(mRect, 0, 180, true, mPaint); + } else { + mRect.set(face.mouth.x-delta_x, + face.mouth.y-delta_y, face.mouth.x+delta_x, + face.mouth.y+delta_y); + mMatrix.mapRect(mRect); + mRect.offset(dx, dy); + canvas.drawOval(mRect, mPaint); + } + } + } } canvas.restore(); } diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index 6b2b7f5e0..d0bcdfcc2 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -409,6 +409,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { public void goToFilmStrip(); public void goToFullScreen(); + } /** @@ -1852,7 +1853,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { // Check the current one. ViewItem curr = mViewItem[mCurrentItem]; int dataId = curr.getId(); - if (reporter.isDataRemoved(dataId)) { + if (reporter.isDataRemoved(dataId) || mDataAdapter.getTotalNumber() == 1) { reload(); return; } diff --git a/src/com/android/camera/ui/MoreSettingPopup.java b/src/com/android/camera/ui/MoreSettingPopup.java index 8da26c946..ad8ed7721 100644 --- a/src/com/android/camera/ui/MoreSettingPopup.java +++ b/src/com/android/camera/ui/MoreSettingPopup.java @@ -82,12 +82,11 @@ public class MoreSettingPopup extends AbstractSettingPopup @Override public View getView(int position, View convertView, ViewGroup parent) { - if (convertView != null) return convertView; - ListPreference pref = mListItem.get(position); - int viewLayoutId = getSettingLayoutId(pref); - InLineSettingItem view = (InLineSettingItem) + InLineSettingItem view = (InLineSettingItem)convertView; + + view = (InLineSettingItem) mInflater.inflate(viewLayoutId, parent, false); view.initialize(pref); // no init for restore one diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java index f1a5a9a4b..0039aa22c 100644 --- a/src/com/android/camera/ui/PieRenderer.java +++ b/src/com/android/camera/ui/PieRenderer.java @@ -118,7 +118,7 @@ public class PieRenderer extends OverlayRenderer private int mPieCenterX; private int mPieCenterY; private int mSliceRadius; - private int mArcRadius; + private int mArcRadius, mMaxArcRadius; private int mArcOffset; private int mDialAngle; @@ -225,6 +225,7 @@ public class PieRenderer extends OverlayRenderer mMenuArcPaint.setStyle(Paint.Style.STROKE); mSliceRadius = res.getDimensionPixelSize(R.dimen.pie_item_radius); mArcRadius = res.getDimensionPixelSize(R.dimen.pie_arc_radius); + mMaxArcRadius = mArcRadius; mArcOffset = res.getDimensionPixelSize(R.dimen.pie_arc_offset); mLabel = new TextDrawable(res); mLabel.setDropShadow(true); @@ -357,6 +358,12 @@ public class PieRenderer extends OverlayRenderer mCenterX = (r - l) / 2; mCenterY = (b - t) / 2; + int layoutWidth = r - l; + if( (layoutWidth > 0) && ((mMaxArcRadius + mCenterX) > layoutWidth) ){ + mArcRadius = layoutWidth - mCenterX; + } else { + mArcRadius = mMaxArcRadius; + } mFocusX = mCenterX; mFocusY = mCenterY; resetPieCenter(); diff --git a/src/com/android/camera/util/ApiHelper.java b/src/com/android/camera/util/ApiHelper.java index dd5208cc8..4a917799e 100644 --- a/src/com/android/camera/util/ApiHelper.java +++ b/src/com/android/camera/util/ApiHelper.java @@ -49,7 +49,8 @@ public class ApiHelper { Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; public static final boolean HAS_ROTATION_ANIMATION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; - + public static final boolean HAS_FINE_RESOLUTION_QUALITY_LEVELS = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; public static final boolean HAS_HIDEYBARS = isKitKatOrHigher(); public static int getIntFieldIfExists(Class<?> klass, String fieldName, diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index 708308b63..68211d648 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -56,6 +56,7 @@ import com.android.camera.CameraActivity; import com.android.camera.CameraDisabledException; import com.android.camera.CameraHolder; import com.android.camera.CameraManager; +import com.android.camera.CameraSettings; import com.android.camera.util.IntentHelper; import com.android.camera2.R; @@ -820,7 +821,20 @@ public class CameraUtil { } } } - + public static String getFilpModeString(int value){ + switch(value){ + case 0: + return CameraSettings.FLIP_MODE_OFF; + case 1: + return CameraSettings.FLIP_MODE_H; + case 2: + return CameraSettings.FLIP_MODE_V; + case 3: + return CameraSettings.FLIP_MODE_VH; + default: + return null; + } + } /** * For still image capture, we need to get the right fps range such that the * camera can slow down the framerate to allow for less-noisy/dark |