diff options
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 43 | ||||
-rw-r--r-- | src/com/android/camera/CameraSettings.java | 14 | ||||
-rw-r--r-- | src/com/android/camera/MosaicPreviewRenderer.java | 9 | ||||
-rw-r--r-- | src/com/android/camera/MosaicRenderer.java | 10 | ||||
-rw-r--r-- | src/com/android/camera/PhotoMenu.java | 42 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 109 | ||||
-rw-r--r-- | src/com/android/camera/PhotoUI.java | 16 | ||||
-rw-r--r-- | src/com/android/camera/RefocusActivity.java | 249 | ||||
-rw-r--r-- | src/com/android/camera/VideoMenu.java | 17 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 9 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaModule.java | 34 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaUI.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/ui/CameraControls.java | 106 | ||||
-rw-r--r-- | src/com/android/camera/util/CameraUtil.java | 14 |
14 files changed, 565 insertions, 115 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 8fd8f9daa..e9786431b 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -49,6 +49,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.provider.Settings; @@ -101,6 +102,8 @@ import java.io.File; import static com.android.camera.CameraManager.CameraOpenErrorCallback; +import android.media.AudioManager; + public class CameraActivity extends Activity implements ModuleSwitcher.ModuleSwitchListener, ActionBar.OnMenuVisibilityListener, @@ -122,6 +125,9 @@ public class CameraActivity extends Activity // panorama. If the extra is not set, it is in the normal camera mode. public static final String SECURE_CAMERA_EXTRA = "secure_camera"; + // This string is used for judge start activity from screenoff or not + public static final String GESTURE_CAMERA_NAME = "com.android.camera.CameraGestureActivity"; + /** * Request code from an activity we started that indicated that we do not * want to reset the view to the preview in onResume. @@ -187,7 +193,6 @@ public class CameraActivity extends Activity private ViewGroup mUndoDeletionBar; private boolean mIsUndoingDeletion = false; private boolean mIsEditActivityInProgress = false; - protected boolean mIsModuleSwitchInProgress = false; private View mPreviewCover; private FrameLayout mPreviewContentLayout; @@ -210,6 +215,10 @@ public class CameraActivity extends Activity public static int SETTING_LIST_WIDTH_2 = 250; private Bitmap mPreviewThumbnailBitmap; + private AudioManager mAudioManager; + private int mShutterVol; + private int mOriginalMasterVol; + private class MyOrientationEventListener extends OrientationEventListener { public MyOrientationEventListener(Context context) { @@ -524,6 +533,15 @@ public class CameraActivity extends Activity if (img == null) return; Uri uri = img.getContentUri(); + if (mCurrentModule instanceof PhotoModule) { + if (((PhotoModule) mCurrentModule).isRefocus()) { + Intent intent = new Intent(); + intent.setClass(this, RefocusActivity.class); + intent.setData(uri); + startActivity(intent); + return; + } + } Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); } @@ -1156,11 +1174,14 @@ public class CameraActivity extends Activity super.onCreate(state); GcamHelper.init(getContentResolver()); + mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + mOriginalMasterVol = mAudioManager.getMasterVolume(); + mShutterVol = SystemProperties.getInt("persist.camera.snapshot.volume", -1); + if (mShutterVol >= 0 && mShutterVol <= 100 ) + mAudioManager.setMasterVolume(mShutterVol,0); + getWindow().requestFeature(Window.FEATURE_ACTION_BAR); setContentView(R.layout.camera_filmstrip); - int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - getWindow().addFlags(flags); mActionBar = getActionBar(); mActionBar.addOnMenuVisibilityListener(this); @@ -1174,7 +1195,8 @@ public class CameraActivity extends Activity Intent intent = getIntent(); String action = intent.getAction(); if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action) - || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { + || ACTION_IMAGE_CAPTURE_SECURE.equals(action) + || intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) { mSecureCamera = true; } else { mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); @@ -1185,6 +1207,9 @@ public class CameraActivity extends Activity Window win = getWindow(); WindowManager.LayoutParams params = win.getAttributes(); params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; + if (intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) { + params.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; + } win.setAttributes(params); // Filter for screen off so that we can finish secure camera activity @@ -1365,6 +1390,8 @@ public class CameraActivity extends Activity @Override public void onPause() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mOriginalMasterVol,0); // Delete photos that are pending deletion performDeletion(); mOrientationListener.disable(); @@ -1388,6 +1415,8 @@ public class CameraActivity extends Activity @Override public void onResume() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mShutterVol,0); // TODO: Handle this in OrientationManager. // Auto-rotate off if (Settings.System.getInt(getContentResolver(), @@ -1455,6 +1484,8 @@ public class CameraActivity extends Activity @Override public void onDestroy() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mOriginalMasterVol,0); if (mSecureCamera) { unregisterReceiver(mScreenOffReceiver); } @@ -1583,7 +1614,6 @@ public class CameraActivity extends Activity return; } - mIsModuleSwitchInProgress = true; CameraHolder.instance().keep(); closeModule(mCurrentModule); setModuleFromIndex(moduleIndex); @@ -1598,7 +1628,6 @@ public class CameraActivity extends Activity // starts up. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, moduleIndex).apply(); - mIsModuleSwitchInProgress = false; } /** diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java index 37fc39718..63581b8ba 100644 --- a/src/com/android/camera/CameraSettings.java +++ b/src/com/android/camera/CameraSettings.java @@ -769,9 +769,19 @@ public class CameraSettings { filterUnsupportedOptions(group, whiteBalance, mParameters.getSupportedWhiteBalance()); } + if (sceneMode != null) { - filterUnsupportedOptions(group, - sceneMode, mParameters.getSupportedSceneModes()); + List<String> supportedSceneModes = mParameters.getSupportedSceneModes(); + List<String> supportedAdvancedFeatures = + getSupportedAdvancedFeatures(mParameters); + if (CameraUtil.isSupported( + mContext.getString(R.string + .pref_camera_advanced_feature_value_refocus_on), + supportedAdvancedFeatures)) { + supportedSceneModes.add(mContext.getString(R.string + .pref_camera_advanced_feature_value_refocus_on)); + } + filterUnsupportedOptions(group, sceneMode, supportedSceneModes); } if (flashMode != null) { filterUnsupportedOptions(group, diff --git a/src/com/android/camera/MosaicPreviewRenderer.java b/src/com/android/camera/MosaicPreviewRenderer.java index 77c260eb5..42da4d9e7 100644 --- a/src/com/android/camera/MosaicPreviewRenderer.java +++ b/src/com/android/camera/MosaicPreviewRenderer.java @@ -83,13 +83,10 @@ public class MosaicPreviewRenderer { mInputSurfaceTexture.updateTexImage(); mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); - // Call setPreviewBackground to render high-res RGB textures to full screen. - MosaicRenderer.setPreviewBackground(true); - MosaicRenderer.preprocess(mTransformMatrix); - MosaicRenderer.step(); - MosaicRenderer.setPreviewBackground(false); - MosaicRenderer.setWarping(true); + // Call preprocess to render it to low-res and high-res RGB textures. + MosaicRenderer.preprocess(mTransformMatrix); + // Now, transfer the textures from GPU to CPU memory for processing MosaicRenderer.transferGPUtoCPU(); MosaicRenderer.updateMatrix(); MosaicRenderer.step(); diff --git a/src/com/android/camera/MosaicRenderer.java b/src/com/android/camera/MosaicRenderer.java index daf94abe6..92d9cb7b6 100644 --- a/src/com/android/camera/MosaicRenderer.java +++ b/src/com/android/camera/MosaicRenderer.java @@ -86,14 +86,4 @@ public class MosaicRenderer * @param flag boolean flag to set the warping to true or false. */ public static native void setWarping(boolean flag); - /** - * This function allows toggling between drawing the background full - * screen preview image data to screen and drawing the warped smaller - * preview on top of it. To render the full screen background preview, - * we set the falsg to true and to render the warped image on top of this - * we set the flag to false and flag in setWarping to true. - * - * @param flag boolean flag to set the warping to true or false. - */ - public static native void setPreviewBackground(boolean flag); } diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java index 1568c32c0..d10a679b3 100644 --- a/src/com/android/camera/PhotoMenu.java +++ b/src/com/android/camera/PhotoMenu.java @@ -69,7 +69,8 @@ public class PhotoMenu extends MenuController private static final int POPUP_NONE = 0; private static final int POPUP_FIRST_LEVEL = 1; private static final int POPUP_SECOND_LEVEL = 2; - private static final int POPUP_IN_ANIMATION = 3; + private static final int POPUP_IN_ANIMATION_SLIDE = 3; + private static final int POPUP_IN_ANIMATION_FADE = 4; private static final int PREVIEW_MENU_NONE = 0; private static final int PREVIEW_MENU_IN_ANIMATION = 1; private static final int PREVIEW_MENU_ON = 2; @@ -225,9 +226,9 @@ public class PhotoMenu extends MenuController } private void animateFadeOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_FADE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_FADE; ViewPropertyAnimator vp = v.animate(); vp.alpha(0f).setDuration(ANIMATION_DURATION); @@ -274,9 +275,9 @@ public class PhotoMenu extends MenuController } private void animateSlideOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_SLIDE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_SLIDE; ViewPropertyAnimator vp = v.animate(); vp.translationX(v.getX() - v.getWidth()).setDuration(ANIMATION_DURATION); @@ -413,7 +414,9 @@ public class PhotoMenu extends MenuController } public boolean isOverMenu(MotionEvent ev) { - if (mPopupStatus == POPUP_NONE || mPopupStatus == POPUP_IN_ANIMATION) + if (mPopupStatus == POPUP_NONE + || mPopupStatus == POPUP_IN_ANIMATION_SLIDE + || mPopupStatus == POPUP_IN_ANIMATION_FADE) return false; if (mUI.getMenuLayout() == null) return false; @@ -439,7 +442,7 @@ public class PhotoMenu extends MenuController } public boolean isMenuBeingAnimated() { - return mPopupStatus == POPUP_IN_ANIMATION; + return mPopupStatus == POPUP_IN_ANIMATION_SLIDE || mPopupStatus == POPUP_IN_ANIMATION_FADE; } public boolean isPreviewMenuBeingShown() { @@ -681,8 +684,11 @@ public class PhotoMenu extends MenuController @Override public void onClick(View v) { addSceneMode(); - View view = mUI.getPreviewMenuLayout().getChildAt(0); - animateSlideIn(view, previewMenuSize, false); + ViewGroup menuLayout = mUI.getPreviewMenuLayout(); + if (menuLayout != null) { + View view = menuLayout.getChildAt(0); + animateSlideIn(view, previewMenuSize, false); + } } }); } @@ -830,8 +836,11 @@ public class PhotoMenu extends MenuController @Override public void onClick(View v) { addFilterMode(); - View view = mUI.getPreviewMenuLayout().getChildAt(0); - animateSlideIn(view, previewMenuSize, false); + ViewGroup menuLayout = mUI.getPreviewMenuLayout(); + if (menuLayout != null) { + View view = mUI.getPreviewMenuLayout().getChildAt(0); + animateSlideIn(view, previewMenuSize, false); + } } }); } @@ -1094,6 +1103,17 @@ public class PhotoMenu extends MenuController } } + String refocusOn = mActivity.getString(R.string + .pref_camera_advanced_feature_value_refocus_on); + if (notSame(pref, CameraSettings.KEY_SCENE_MODE, refocusOn)) { + ListPreference lp = mPreferenceGroup + .findPreference(CameraSettings.KEY_ADVANCED_FEATURES); + if (lp != null && refocusOn.equals(lp.getValue())) { + setPreference(CameraSettings.KEY_ADVANCED_FEATURES, + mActivity.getString(R.string.pref_camera_advanced_feature_default)); + } + } + if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) { buttonSetEnabled(mFilterModeSwitcher, false); } else { diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 1e238be80..843d860f7 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -35,7 +35,9 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; +import android.media.AudioManager; import android.media.CameraProfile; +import android.media.SoundPool; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -192,6 +194,7 @@ public class PhotoModule private boolean mTouchAfAecFlag; private boolean mLongshotSave = false; private boolean mRefocus = false; + private boolean mLastPhotoTakenWithRefocus = false; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -253,6 +256,9 @@ public class PhotoModule // when the image is ready to be saved. private NamedImages mNamedImages; + private SoundPool mSoundPool; + private int mRefocusSound; + private Runnable mDoSnapRunnable = new Runnable() { @Override public void run() { @@ -358,6 +364,7 @@ public class PhotoModule private boolean mAnimateCapture = true; private int mJpegFileSizeEstimation = 0; + private int mRemainingPhotos = -1; private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @@ -524,7 +531,7 @@ public class PhotoModule mPreferences.setLocalId(mActivity, mCameraId); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - if (mOpenCameraThread == null && !mActivity.mIsModuleSwitchInProgress) { + if (mOpenCameraThread == null) { mOpenCameraThread = new OpenCameraThread(); mOpenCameraThread.start(); } @@ -558,6 +565,8 @@ public class PhotoModule mAm.getMemoryInfo(memInfo); SECONDARY_SERVER_MEM = memInfo.secondaryServerThreshold; + mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0); + mRefocusSound = mSoundPool.load(mActivity, R.raw.camera_click_x5, 1); } private void initializeControlByIntent() { @@ -1028,6 +1037,9 @@ public class PhotoModule } }); } + if (mRefocus) { + mSoundPool.play(mRefocusSound, 1.0f, 1.0f, 0, 0, 1.0f); + } } } private final class StatsCallback @@ -1243,7 +1255,20 @@ public class PhotoModule } startFaceDetection(); } - if ((mRefocus) && (mReceivedSnapNum == 6)) { + + mLastPhotoTakenWithRefocus = mRefocus; + if (mRefocus) { + final String[] NAMES = { "00.jpg", "01.jpg", "02.jpg", "03.jpg", + "04.jpg", "DepthMapImage.y", "AllFocusImage.jpg" }; + try { + FileOutputStream out = mActivity.openFileOutput(NAMES[mReceivedSnapNum - 1], + Context.MODE_PRIVATE); + out.write(jpegData, 0, jpegData.length); + out.close(); + } catch (Exception e) { + } + } + if (mRefocus && (mReceivedSnapNum == 7)) { Size s = mParameters.getPictureSize(); mNamedImages.nameNewImage(mCaptureStartTime, mRefocus); NamedEntity name = mNamedImages.getNextNameEntity(); @@ -1259,9 +1284,9 @@ public class PhotoModule } mActivity.getMediaSaveService().addImage( jpegData, title, date, mLocation, s.width, s.height, - 0, null, mOnMediaSavedListener, mContentResolver, ".jpeg"); - - } else { + 0, null, mOnMediaSavedListener, mContentResolver, PIXEL_FORMAT_JPEG); + mUI.showRefocusToast(mRefocus); + } else if (!mRefocus) { ExifInterface exif = Exif.getExif(jpegData); int orientation = Exif.getOrientation(exif); if (!mIsImageCaptureIntent) { @@ -1351,7 +1376,7 @@ public class PhotoModule // the mean time and fill it, but that could have happened between the // shutter press and saving the JPEG too. mActivity.updateStorageSpaceAndHint(); - updateRemainingPhotos(); + mUI.updateRemainingPhotos(--mRemainingPhotos); long now = System.currentTimeMillis(); mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; Log.v(TAG, "mJpegCallbackFinishTime = " @@ -1604,6 +1629,7 @@ public class PhotoModule new JpegPictureCallback(loc)); } } else { + mCameraDevice.enableShutterSound(!mRefocus); mCameraDevice.takePicture(mHandler, new ShutterCallback(!animateBefore), mRawPictureCallback, mPostViewPictureCallback, @@ -1763,9 +1789,7 @@ public class PhotoModule } else { mUI.overrideSettings(CameraSettings.KEY_PICTURE_FORMAT, null); } - if ((ubiFocus != null && ubiFocus.equals(ubiFocusOn)) || - (multiTouchFocus != null && multiTouchFocus.equals(multiTouchFocusOn)) || - (reFocus != null && reFocus.equals(reFocusOn)) || + if ((multiTouchFocus != null && multiTouchFocus.equals(multiTouchFocusOn)) || (chromaFlash != null && chromaFlash.equals(chromaFlashOn)) || (optiZoom != null && optiZoom.equals(optiZoomOn)) || (fssr != null && fssr.equals(fssrOn)) || @@ -2097,10 +2121,12 @@ public class PhotoModule } //Need to disable focus for ZSL mode - if(mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { - mFocusManager.setZslEnable(true); - } else { - mFocusManager.setZslEnable(false); + if (mFocusManager != null) { + 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 @@ -2108,7 +2134,8 @@ public class PhotoModule // one and re-start the preview. Snapshot in progress also includes the // state that autofocus is focusing and a picture will be taken when // focus callback arrives. - if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS) + if ((((mFocusManager != null) && mFocusManager.isFocusingSnapOnFinish()) + || mCameraState == SNAPSHOT_IN_PROGRESS) && !mIsImageCaptureIntent) { mSnapshotOnIdle = true; return; @@ -2240,11 +2267,12 @@ public class PhotoModule private void updateRemainingPhotos() { if (mJpegFileSizeEstimation != 0) { - mUI.updateRemainingPhotos((int) (mActivity.getStorageSpaceBytes() - / mJpegFileSizeEstimation)); + mRemainingPhotos = (int) (mActivity.getStorageSpaceBytes() + / mJpegFileSizeEstimation); } else { - mUI.updateRemainingPhotos(-1); + mRemainingPhotos = -1; } + mUI.updateRemainingPhotos(mRemainingPhotos); } private void onResumeTasks() { @@ -2844,7 +2872,16 @@ public class PhotoModule //mUnsupportedJpegQuality = true; }else { mParameters.setJpegQuality(JpegEncodingQualityMappings.getQualityNumber(jpegQuality)); - setJpegFileSizeEstimation(pic_size, jpegQuality); + int jpegFileSize = estimateJpegFileSize(pic_size, jpegQuality); + if (jpegFileSize != mJpegFileSizeEstimation) { + mJpegFileSizeEstimation = jpegFileSize; + mHandler.post(new Runnable() { + @Override + public void run() { + updateRemainingPhotos(); + } + }); + } } } @@ -3242,7 +3279,7 @@ public class PhotoModule } } - private void setJpegFileSizeEstimation(final Size size, final String quality) { + private int estimateJpegFileSize(final Size size, final String quality) { int[] ratios = mActivity.getResources().getIntArray(R.array.jpegquality_compression_ratio); String[] qualities = mActivity.getResources().getStringArray( R.array.pref_camera_jpegquality_entryvalues); @@ -3255,9 +3292,9 @@ public class PhotoModule } if (ratio == 0) { - mJpegFileSizeEstimation = 0; + return 0; } else { - mJpegFileSizeEstimation = size.width * size.height * 3 / ratio; + return size.width * size.height * 3 / ratio; } } @@ -3472,6 +3509,10 @@ public class PhotoModule mActivity.getString(R.string.pref_camera_scenemode_default)); } } + + String refocusOn = mActivity.getString(R.string + .pref_camera_advanced_feature_value_refocus_on); + if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) { if (!mParameters.getSceneMode().equals(mSceneMode)) { mParameters.setSceneMode(mSceneMode); @@ -3483,9 +3524,16 @@ public class PhotoModule mParameters = mCameraDevice.getParameters(); } } else { - mSceneMode = mParameters.getSceneMode(); - if (mSceneMode == null) { - mSceneMode = Parameters.SCENE_MODE_AUTO; + if (refocusOn.equals(mSceneMode)) { + try { + mUI.setPreference(CameraSettings.KEY_ADVANCED_FEATURES, refocusOn); + } catch (NullPointerException e) { + } + } else { + mSceneMode = mParameters.getSceneMode(); + if (mSceneMode == null) { + mSceneMode = Parameters.SCENE_MODE_AUTO; + } } } @@ -4124,6 +4172,12 @@ public class PhotoModule return; } + if (CameraSettings.KEY_CAMERA_SAVEPATH.equals(pref.getKey())) { + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + mActivity.updateStorageSpaceAndHint(); + } + //call generic onSharedPreferenceChanged onSharedPreferenceChanged(); } @@ -4171,8 +4225,6 @@ public class PhotoModule disableSkinToneSeekBar(); } } - Storage.setSaveSDCard( - mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); } @Override @@ -4423,6 +4475,10 @@ public class PhotoModule } } } + + public boolean isRefocus() { + return mLastPhotoTakenWithRefocus; + } } /* Below is no longer needed, except to get rid of compile error @@ -4600,5 +4656,4 @@ class DrawAutoHDR extends View{ public void setPhotoModuleObject (PhotoModule photoModule) { mPhotoModule = photoModule; } - } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index b4e08c398..d4cec7bc0 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -529,6 +529,10 @@ public class PhotoUI implements PieListener, task.execute(); } + public void showRefocusToast(boolean show) { + mCameraControls.showRefocusToast(show); + } + private void openMenu() { if (mPieRenderer != null) { // If autofocus is not finished, cancel autofocus so that the @@ -553,7 +557,9 @@ public class PhotoUI implements PieListener, mMenuButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - mMenu.openFirstLevel(); + if(mMenu != null){ + mMenu.openFirstLevel(); + } } }); if (mController.isImageCaptureIntent()) { @@ -917,8 +923,11 @@ public class PhotoUI implements PieListener, } public boolean sendTouchToMenu(MotionEvent ev) { - View v = mMenuLayout.getChildAt(0); - return v.dispatchTouchEvent(ev); + if (mMenuLayout != null) { + View v = mMenuLayout.getChildAt(0); + return v.dispatchTouchEvent(ev); + } + return false; } public void dismissSceneModeMenu() { @@ -962,6 +971,7 @@ public class PhotoUI implements PieListener, ret = true; } onShowSwitcherPopup(); + mCameraControls.showRefocusToast(false); return ret; } diff --git a/src/com/android/camera/RefocusActivity.java b/src/com/android/camera/RefocusActivity.java new file mode 100644 index 000000000..2102d1a78 --- /dev/null +++ b/src/com/android/camera/RefocusActivity.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2015, 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 java.io.File; +import java.io.FileInputStream; +import java.io.OutputStream; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Build; +import android.view.Display; +import android.view.MotionEvent; +import android.view.View; +import android.widget.ImageView; + +import org.codeaurora.snapcam.R; + +public class RefocusActivity extends Activity { + private static final String TAG = "RefocusActivity"; + private static final String[] NAMES = { + "00", "01", "02", "03", "04", "AllFocusImage" + }; + + private Uri mUri; + + private ImageView mImageView; + private int mWidth; + private int mHeight; + + private DepthMap mDepthMap; + private int mCurrentImage = -1; + private int mRequestedImage = -1; + private LoadImageTask mLoadImageTask; + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + + new Thread(new Runnable() { + public void run() { + mDepthMap = new DepthMap(getFilesDir() + "/DepthMapImage.y"); + } + }).start(); + + mUri = getIntent().getData(); + setResult(RESULT_CANCELED, new Intent()); + + setContentView(R.layout.refocus_editor); + mImageView = (ImageView) findViewById(R.id.refocus_image); + mImageView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + float x = event.getX(); + float y = event.getY(); + int w = v.getWidth(); + int h = v.getHeight(); + if (mDepthMap != null) { + int depth = mDepthMap.getDepth(x / (float) w, y / (float) h); + setCurrentImage(depth); + } + break; + } + return true; + } + }); + + findViewById(R.id.refocus_all).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + allInFocus(); + } + }); + + findViewById(R.id.refocus_cancel).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + finish(); + } + }); + + findViewById(R.id.refocus_done).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + if (mRequestedImage != NAMES.length - 1) { + new SaveImageTask().execute(getFilesDir() + "/" + NAMES[mRequestedImage] + + ".jpg"); + } else { + finish(); + } + } + }); + + Display display = getWindowManager().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + mWidth = size.x; + mHeight = size.y; + + allInFocus(); + } + + private void setCurrentImage(int depth) { + if (depth >= 0 && depth < NAMES.length && depth != mRequestedImage) { + mRequestedImage = depth; + if (mLoadImageTask != null) { + mLoadImageTask.cancel(true); + } + if (depth != mCurrentImage) { + mCurrentImage = depth; + mLoadImageTask = new LoadImageTask(); + mLoadImageTask.execute(getFilesDir() + "/" + NAMES[depth] + ".jpg"); + } + } + } + + private void allInFocus() { + setCurrentImage(NAMES.length - 1); + } + + private class SaveImageTask extends AsyncTask<String, Void, Void> { + protected Void doInBackground(String... path) { + try { + OutputStream out = getContentResolver().openOutputStream(mUri); + FileInputStream in = new FileInputStream(path[0]); + byte[] buf = new byte[4096]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (Exception e) { + } + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mUri); + sendBroadcast(intent); + return null; + } + + protected void onPostExecute(Void v) { + finish(); + } + } + + private class LoadImageTask extends AsyncTask<String, Void, Bitmap> { + protected Bitmap doInBackground(String... path) { + final BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path[0], o); + + int h = o.outHeight; + int w = o.outWidth; + int sample = 1; + + if (h > mHeight || w > mWidth) { + while (h / sample / 2 > mHeight && w / sample / 2 > mWidth) { + sample *= 2; + } + } + + o.inJustDecodeBounds = false; + o.inSampleSize = sample; + return BitmapFactory.decodeFile(path[0], o); + } + + protected void onPostExecute(Bitmap result) { + mImageView.setImageBitmap(result); + } + } + + private class DepthMap { + private byte[] mData; + private int mWidth; + private int mHeight; + private boolean mFail = true; + + public DepthMap(final String path) { + File file = new File(path); + try { + FileInputStream stream = new FileInputStream(file); + mData = new byte[(int) file.length()]; + stream.read(mData); + stream.close(); + } catch (Exception e) { + } + + int length = (int) mData.length; + if (length > 25) { + mFail = (mData[length - 25] != 0); + mWidth = readInteger(length - 24); + mHeight = readInteger(length - 20); + } + if (mWidth * mHeight + 25 > length) { + mFail = true; + } + } + + public int getDepth(float x, float y) { + if (mFail || x > 1.0f || y > 1.0f) { + return NAMES.length - 1; + } else { + return mData[(int) ((y * mHeight + x) * mWidth)]; + } + } + + private int readInteger(int offset) { + int result = mData[offset] & 0xff; + for (int i = 1; i < 4; ++i) { + result <<= 8; + result += mData[offset + i] & 0xff; + } + return result; + } + } +} diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java index 3f9cde7f0..1f9c6d1a0 100644 --- a/src/com/android/camera/VideoMenu.java +++ b/src/com/android/camera/VideoMenu.java @@ -66,7 +66,8 @@ public class VideoMenu extends MenuController private static final int POPUP_NONE = 0; private static final int POPUP_FIRST_LEVEL = 1; private static final int POPUP_SECOND_LEVEL = 2; - private static final int POPUP_IN_ANIMATION = 3; + private static final int POPUP_IN_ANIMATION_SLIDE = 3; + private static final int POPUP_IN_ANIMATION_FADE = 4; private static final int PREVIEW_MENU_NONE = 0; private static final int PREVIEW_MENU_IN_ANIMATION = 1; private static final int PREVIEW_MENU_ON = 2; @@ -164,9 +165,9 @@ public class VideoMenu extends MenuController } private void animateFadeOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_FADE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_FADE; ViewPropertyAnimator vp = v.animate(); vp.alpha(0f).setDuration(ANIMATION_DURATION); @@ -213,9 +214,9 @@ public class VideoMenu extends MenuController } private void animateSlideOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_SLIDE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_SLIDE; ViewPropertyAnimator vp = v.animate(); vp.translationX(v.getX() - v.getWidth()).setDuration(ANIMATION_DURATION); @@ -340,7 +341,9 @@ public class VideoMenu extends MenuController } public boolean isOverMenu(MotionEvent ev) { - if (mPopupStatus == POPUP_NONE || mPopupStatus == POPUP_IN_ANIMATION) + if (mPopupStatus == POPUP_NONE + || mPopupStatus == POPUP_IN_ANIMATION_SLIDE + || mPopupStatus == POPUP_IN_ANIMATION_FADE) return false; if (mUI.getMenuLayout() == null) return false; @@ -366,7 +369,7 @@ public class VideoMenu extends MenuController } public boolean isMenuBeingAnimated() { - return mPopupStatus == POPUP_IN_ANIMATION; + return mPopupStatus == POPUP_IN_ANIMATION_SLIDE || mPopupStatus == POPUP_IN_ANIMATION_FADE; } public boolean isPreviewMenuBeingShown() { diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 1bd395188..59874dd81 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -646,6 +646,7 @@ public class VideoModule implements CameraModule, mUI.animateCapture(); } } + mUI.showUIafterRecording(); } public void onVideoSaved() { @@ -687,10 +688,8 @@ public class VideoModule implements CameraModule, if (stop) { onStopVideoRecording(); - mUI.showUIafterRecording(); } else { startVideoRecording(); - mUI.hideUIwhileRecording(); } mUI.enableShutter(false); @@ -1597,6 +1596,7 @@ public class VideoModule implements CameraModule, mStartRecPending = true; mUI.cancelAnimations(); mUI.setSwipingEnabled(false); + mUI.hideUIwhileRecording(); mActivity.updateStorageSpaceAndHint(); if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) { @@ -2276,6 +2276,11 @@ public class VideoModule implements CameraModule, mParameters.setVideoRotation(videoRotation); } + //set low-power mode if supported + String lpmSupported = mParameters.get("low-power-mode-supported"); + if ("true".equals(lpmSupported)) { + mParameters.set("low-power-mode", 1); + } } @SuppressWarnings("deprecation") private void setCameraParameters() { diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java index bc9fd8602..40878581e 100644 --- a/src/com/android/camera/WideAnglePanoramaModule.java +++ b/src/com/android/camera/WideAnglePanoramaModule.java @@ -44,7 +44,6 @@ import android.view.OrientationEventListener; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.Display; import android.widget.Toast; import com.android.camera.PhotoModule; import com.android.camera.CameraManager.CameraProxy; @@ -110,8 +109,6 @@ public class WideAnglePanoramaModule private boolean mUsingFrontCamera; private int mCameraPreviewWidth; private int mCameraPreviewHeight; - private int mScreenWidth; - private int mScreenHeight; private int mCameraState; private int mCaptureState; private PowerManager.WakeLock mPartialWakeLock; @@ -372,13 +369,14 @@ public class WideAnglePanoramaModule return true; } - private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, boolean need16To9, + private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, boolean needSmaller) { int pixelsDiff = DEFAULT_CAPTURE_PIXELS; boolean hasFound = false; for (Size size : supportedSizes) { int h = size.height; int w = size.width; + // we only want 4:3 format. int d = DEFAULT_CAPTURE_PIXELS - h * w; if (needSmaller && d < 0) { // no bigger preview than 960x720. continue; @@ -386,9 +384,6 @@ public class WideAnglePanoramaModule if (need4To3 && (h * 4 != w * 3)) { continue; } - if (need16To9 && (h * 16 != w * 9)) { - continue; - } d = Math.abs(d); if (d < pixelsDiff) { mCameraPreviewWidth = w; @@ -401,26 +396,12 @@ public class WideAnglePanoramaModule } private void setupCaptureParams(Parameters parameters) { - boolean need4To3 = false; - boolean need16To9 = false; List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); - Display mDisplay = mActivity.getWindowManager().getDefaultDisplay(); - mScreenWidth = mDisplay.getWidth(); - mScreenHeight = mDisplay.getHeight(); - - if(mScreenHeight * 4 == mScreenWidth * 3) { - need4To3 = true; - } - - if(mScreenHeight * 16 == mScreenWidth * 9) { - need16To9 = true; - } - - if (!findBestPreviewSize(supportedSizes, need4To3, need16To9, true)) { - Log.w(TAG, "No preview size supported matching the screen aspect ratio"); - if (!findBestPreviewSize(supportedSizes, false, false, true)) { + if (!findBestPreviewSize(supportedSizes, true, true)) { + Log.w(TAG, "No 4:3 ratio preview size supported."); + if (!findBestPreviewSize(supportedSizes, false, true)) { Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); - findBestPreviewSize(supportedSizes, false, false, false); + findBestPreviewSize(supportedSizes, false, false); } } Log.d(TAG, "camera preview h = " @@ -511,9 +492,6 @@ public class WideAnglePanoramaModule } mPreviewUIWidth = r - l; mPreviewUIHeight = b - t; - Parameters parameters = mCameraDevice.getParameters(); - setupCaptureParams(parameters); - configureCamera(parameters); configMosaicPreview(); if (capturePending == true){ mMainHandler.post(new Runnable() { diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java index 4b403f2d9..9594ac0e6 100644 --- a/src/com/android/camera/WideAnglePanoramaUI.java +++ b/src/com/android/camera/WideAnglePanoramaUI.java @@ -441,6 +441,14 @@ public class WideAnglePanoramaUI implements private void setViews(Resources appRes) { int weight = appRes.getInteger(R.integer.SRI_pano_layout_weight); + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mPreviewLayout.getLayoutParams(); + lp.weight = weight; + mPreviewLayout.setLayoutParams(lp); + + lp = (LinearLayout.LayoutParams) mReview.getLayoutParams(); + lp.weight = weight; + mPreviewLayout.setLayoutParams(lp); + mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar); mSavingProgressBar.setIndicatorWidth(0); mSavingProgressBar.setMaxProgress(100); diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java index 14f27a36d..0938ffc19 100644 --- a/src/com/android/camera/ui/CameraControls.java +++ b/src/com/android/camera/ui/CameraControls.java @@ -19,13 +19,18 @@ package com.android.camera.ui; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.content.Context; -import android.util.Log; +import android.graphics.Canvas; import android.graphics.drawable.AnimationDrawable; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.Paint; +import android.graphics.Path; import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; import android.view.View; +import android.view.ViewGroup; import android.view.ViewPropertyAnimator; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -51,6 +56,8 @@ public class CameraControls extends RotatableLayout { private View mPreview; private View mSceneModeSwitcher; private View mFilterModeSwitcher; + private ArrowTextView mRefocusToast; + private int mSize; private static final int WIDTH_GRID = 5; private static final int HEIGHT_GRID = 7; @@ -154,8 +161,15 @@ public class CameraControls extends RotatableLayout { public CameraControls(Context context, AttributeSet attrs) { super(context, attrs); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); setWillNotDraw(false); + + mRefocusToast = new ArrowTextView(context); + addView(mRefocusToast); + setClipChildren(false); + + setMeasureAllChildren(true); } public CameraControls(Context context) { @@ -294,6 +308,46 @@ public class CameraControls extends RotatableLayout { toIndex(mHdrSwitcher, w, h, rotation, 3, 0, HDR_INDEX); toIndex(mFilterModeSwitcher, w, h, rotation, 1, 0, FILTER_MODE_INDEX); toIndex(mSceneModeSwitcher, w, h, rotation, 0, 0, SCENE_MODE_INDEX); + layoutToast(mRefocusToast, w, h, rotation); + } + + private void layoutToast(final View v, int w, int h, int rotation) { + int tw = v.getMeasuredWidth(); + int th = v.getMeasuredHeight(); + int l, t, r, b, c; + switch (rotation) { + case 90: + c = (int) (h / WIDTH_GRID * (WIDTH_GRID - 0.5)); + t = c - th / 2; + b = c + th / 2; + r = (int) (w / HEIGHT_GRID * (HEIGHT_GRID - 1.25)); + l = r - tw; + mRefocusToast.setArrow(tw, th / 2, tw + th / 2, th, tw, th); + break; + case 180: + t = (int) (h / HEIGHT_GRID * 1.25); + b = t + th; + r = (int) (w / WIDTH_GRID * (WIDTH_GRID - 0.25)); + l = r - tw; + mRefocusToast.setArrow(tw - th / 2, 0, tw, 0, tw, - th / 2); + break; + case 270: + c = (int) (h / WIDTH_GRID * 0.5); + t = c - th / 2; + b = c + th / 2; + l = (int) (w / HEIGHT_GRID * 1.25); + r = l + tw; + mRefocusToast.setArrow(0, 0, 0, th / 2, - th / 2, 0); + break; + default: + l = w / WIDTH_GRID / 4; + b = (int) (h / HEIGHT_GRID * (HEIGHT_GRID - 1.25)); + r = l + tw; + t = b - th; + mRefocusToast.setArrow(0, th, th / 2, th, 0, th * 3 / 2); + break; + } + mRefocusToast.layout(l, t, r, b); } private void center(View v, int l, int t, int r, int b, int orientation, int rotation, @@ -433,6 +487,7 @@ public class CameraControls extends RotatableLayout { break; } mRemainingPhotos.setVisibility(View.INVISIBLE); + mRefocusToast.setVisibility(View.GONE); } public void showUI() { @@ -523,6 +578,7 @@ public class CameraControls extends RotatableLayout { if (mRemainingPhotos.getVisibility() == View.INVISIBLE) { mRemainingPhotos.setVisibility(View.VISIBLE); } + mRefocusToast.setVisibility(View.GONE); } private void center(View v, Rect other, int rotation) { @@ -767,4 +823,52 @@ public class CameraControls extends RotatableLayout { } invalidate(); } + + public void showRefocusToast(boolean show) { + mRefocusToast.setVisibility(show ? View.VISIBLE : View.GONE); + mRemainingPhotos.setVisibility(show ? View.GONE : View.VISIBLE); + } + + private class ArrowTextView extends TextView { + private static final int TEXT_SIZE = 14; + private static final int PADDING_SIZE = 18; + private static final int BACKGROUND = 0x80000000; + + private Paint mPaint; + private Path mPath; + + public ArrowTextView(Context context) { + super(context); + + setText(context.getString(R.string.refocus_toast)); + setBackgroundColor(BACKGROUND); + setVisibility(View.GONE); + setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + setTextSize(TEXT_SIZE); + setPadding(PADDING_SIZE, PADDING_SIZE, PADDING_SIZE, PADDING_SIZE); + + mPaint = new Paint(); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setColor(BACKGROUND); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mPath != null) { + canvas.drawPath(mPath, mPaint); + } + } + + public void setArrow(float x1, float y1, float x2, float y2, float x3, float y3) { + mPath = new Path(); + mPath.reset(); + mPath.moveTo(x1, y1); + mPath.lineTo(x2, y2); + mPath.lineTo(x3, y3); + mPath.lineTo(x1, y1); + } + } } diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index 08ce84d87..dbd2cc36d 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -1073,18 +1073,10 @@ public class CameraUtil { } public static int determineRatio(int width, int height) { - int s = width, l = height; - if (width > height) { - l = width; - s = height; - } - if (l * 3 == s * 4) { - return RATIO_4_3; - } else if (l * 9 == s * 16) { - return RATIO_16_9; - } else { - return RATIO_UNKNOWN; + if (height != 0) { + return determineRatio(((float) width) / height); } + return RATIO_UNKNOWN; } public static int determineRatio(float ratio) { |