diff options
author | Senpo Hu <senpo@google.com> | 2015-01-11 15:04:31 -0800 |
---|---|---|
committer | Senpo Hu <senpo@google.com> | 2015-01-16 12:01:24 -0800 |
commit | fb0496133a0b4b526dc70f6447bd4b97d95de95f (patch) | |
tree | 99f7a50373819633ca21a07009f40b837ad9b5fb /src | |
parent | 3d9639a1b93ee245c53bc7948ec12be4119ff08c (diff) | |
download | android_packages_apps_Camera2-fb0496133a0b4b526dc70f6447bd4b97d95de95f.tar.gz android_packages_apps_Camera2-fb0496133a0b4b526dc70f6447bd4b97d95de95f.tar.bz2 android_packages_apps_Camera2-fb0496133a0b4b526dc70f6447bd4b97d95de95f.zip |
Move FirstRunDialog to app layer.
The first run logic should live in CameraActivity. This refactoring
could clean up CaptureModule and PhotoModule.
* Introduce ResolutionSetting class.
* Introduce OneCameraManagerImpl for camera API 1.
Tested and verified this works on K / L devices.
Change-Id: I11a968a9346b520dee23fc4591a73bb483c43246
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 75 | ||||
-rw-r--r-- | src/com/android/camera/CaptureModule.java | 78 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 159 | ||||
-rw-r--r-- | src/com/android/camera/PhotoUI.java | 120 | ||||
-rw-r--r-- | src/com/android/camera/app/AppController.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/app/FirstRunDialog.java | 191 | ||||
-rw-r--r-- | src/com/android/camera/one/OneCameraManager.java | 46 | ||||
-rw-r--r-- | src/com/android/camera/one/v1/OneCameraCharacteristicsImpl.java | 94 | ||||
-rw-r--r-- | src/com/android/camera/one/v1/OneCameraManagerImpl.java | 108 | ||||
-rw-r--r-- | src/com/android/camera/one/v2/OneCameraManagerImpl.java | 27 | ||||
-rw-r--r-- | src/com/android/camera/settings/Keys.java | 53 | ||||
-rw-r--r-- | src/com/android/camera/settings/ResolutionSetting.java | 108 | ||||
-rw-r--r-- | src/com/android/camera/settings/ResolutionUtil.java | 15 | ||||
-rw-r--r-- | src/com/android/camera/settings/SettingsUtil.java | 20 | ||||
-rw-r--r-- | src/com/android/camera/util/ApiHelper.java | 4 |
15 files changed, 523 insertions, 583 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 70fd52d8d..82ce47401 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -71,6 +71,7 @@ import com.android.camera.app.CameraAppUI; import com.android.camera.app.CameraController; import com.android.camera.app.CameraProvider; import com.android.camera.app.CameraServices; +import com.android.camera.app.FirstRunDialog; import com.android.camera.app.LocationManager; import com.android.camera.app.MemoryManager; import com.android.camera.app.MemoryQuery; @@ -111,6 +112,8 @@ import com.android.camera.session.CaptureSessionManager.SessionListener; import com.android.camera.settings.AppUpgrader; import com.android.camera.settings.CameraSettingsActivity; import com.android.camera.settings.Keys; +import com.android.camera.settings.ResolutionSetting; +import com.android.camera.settings.ResolutionUtil; import com.android.camera.settings.SettingsManager; import com.android.camera.settings.SettingsUtil; import com.android.camera.tinyplanet.TinyPlanetFragment; @@ -205,6 +208,7 @@ public class CameraActivity extends QuickActivity private OneCameraManager mCameraManager; private SettingsManager mSettingsManager; + private ResolutionSetting mResolutionSetting; private ModeListView mModeListView; private boolean mModeListVisible = false; private int mCurrentModeIndex; @@ -269,6 +273,9 @@ public class CameraActivity extends QuickActivity private MemoryManager mMemoryManager; private MotionManager mMotionManager; + /** First run dialog */ + private FirstRunDialog mFirstRunDialog; + @Override public CameraAppUI getCameraAppUI() { return mCameraAppUI; @@ -1414,11 +1421,12 @@ public class CameraActivity extends QuickActivity mSoundPlayer = new SoundPlayer(mAppContext); try { - mCameraManager = OneCameraManager.get(this); + mCameraManager = OneCameraManager.get(this, ResolutionUtil.getDisplayMetrics(this)); } catch (OneCameraException e) { // Log error and continue. Modules requiring OneCamera should check // and handle if null by showing error dialog or other treatment. - Log.w(TAG, "Creating camera manager failed.", e); + Log.e(TAG, "Creating camera manager failed.", e); + CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera); } // TODO: Try to move all the resources allocation to happen as soon as @@ -1431,6 +1439,7 @@ public class CameraActivity extends QuickActivity AppUpgrader appUpgrader = new AppUpgrader(this); appUpgrader.upgrade(mSettingsManager); Keys.setDefaults(mSettingsManager, mAppContext); + mResolutionSetting = new ResolutionSetting(mSettingsManager, mCameraManager); getWindow().requestFeature(Window.FEATURE_ACTION_BAR); // We suppress this flag via theme when drawing the system preview @@ -1609,6 +1618,19 @@ public class CameraActivity extends QuickActivity } }); mMotionManager = getServices().getMotionManager(); + + mFirstRunDialog = new FirstRunDialog(this, new FirstRunDialog.FirstRunDialogListener() { + @Override + public void onFirstRunStateReady() { + // Run normal resume tasks. + resume(); + } + + @Override + public void onCameraAccessException() { + CameraUtil.showErrorAndFinish(CameraActivity.this, R.string.cannot_connect_camera); + } + }); } /** @@ -1737,10 +1759,13 @@ public class CameraActivity extends QuickActivity } mPaused = true; - mPeekAnimationHandler = null; - mPeekAnimationThread.quitSafely(); - mPeekAnimationThread = null; + if (mPeekAnimationHandler != null) { + mPeekAnimationHandler = null; + mPeekAnimationThread.quitSafely(); + mPeekAnimationThread = null; + } mCameraAppUI.hideCaptureIndicator(); + mFirstRunDialog.dismiss(); // Delete photos that are pending deletion performDeletion(); @@ -1776,10 +1801,17 @@ public class CameraActivity extends QuickActivity @Override public void onResumeTasks() { + mPaused = false; + + // Show the dialog if necessary. The rest resume logic will be invoked + // at the onFirstRunStateReady() callback. + mFirstRunDialog.showIfNecessary(); + } + + private void resume() { CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME); Log.v(TAG, "Build info: " + Build.DISPLAY); - mPaused = false; updateStorageSpaceAndHint(null); mLastLayoutOrientation = getResources().getConfiguration().orientation; @@ -1912,8 +1944,11 @@ public class CameraActivity extends QuickActivity mPanoramaViewHelper.onResume(); ReleaseHelper.showReleaseInfoDialogOnStart(this, mSettingsManager); - // Record location if the setting is active - Keys.syncLocationManager(mSettingsManager, mLocationManager); + + // Enable location recording if the setting is on. + final boolean locationRecordingEnabled = + mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION); + mLocationManager.recordLocation(locationRecordingEnabled); final int previewVisibility = getPreviewVisibility(); updatePreviewRendering(previewVisibility); @@ -2303,6 +2338,11 @@ public class CameraActivity extends QuickActivity } @Override + public ResolutionSetting getResolutionSetting() { + return mResolutionSetting; + } + + @Override public CameraServices getServices() { return (CameraServices) getApplication(); } @@ -2334,25 +2374,6 @@ public class CameraActivity extends QuickActivity } /** - * Creates an AlertDialog appropriate for choosing whether to enable - * location on the first run of the app. - */ - public AlertDialog getFirstTimeLocationAlert() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder = SettingsUtil.getFirstTimeLocationAlertBuilder(builder, new Callback<Boolean>() { - @Override - public void onCallback(Boolean locationOn) { - Keys.setLocation(mSettingsManager, locationOn, mLocationManager); - } - }); - if (builder != null) { - return builder.create(); - } else { - return null; - } - } - - /** * Launches an ACTION_EDIT intent for the given local data item. If * 'withTinyPlanet' is set, this will show a disambig dialog first to let * the user start either the tiny planet editor or another photo editor. diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 0226b636a..a3b97929f 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -39,7 +39,6 @@ import android.view.View; import com.android.camera.app.AppController; import com.android.camera.app.CameraAppUI; import com.android.camera.app.CameraAppUI.BottomBarUISpec; -import com.android.camera.app.FirstRunDialog; import com.android.camera.app.LocationManager; import com.android.camera.async.MainThreadExecutor; import com.android.camera.burst.BurstFacade; @@ -48,7 +47,6 @@ import com.android.camera.burst.BurstReadyStateChangeListener; import com.android.camera.debug.DebugPropertyHelper; import com.android.camera.debug.Log; import com.android.camera.debug.Log.Tag; -import com.android.camera.exif.Rational; import com.android.camera.hardware.HardwareSpec; import com.android.camera.hardware.HeadingSensor; import com.android.camera.module.ModuleController; @@ -73,7 +71,6 @@ import com.android.camera.remote.RemoteCameraModule; import com.android.camera.session.CaptureSession; import com.android.camera.settings.Keys; import com.android.camera.settings.SettingsManager; -import com.android.camera.settings.SettingsUtil; import com.android.camera.ui.CountDownView; import com.android.camera.ui.PreviewStatusListener; import com.android.camera.ui.TouchCoordinate; @@ -135,16 +132,16 @@ public class CaptureModule extends CameraModule implements private final Context mContext; /** Module UI. */ private CaptureModuleUI mUI; - /** First run dialog */ - private FirstRunDialog mFirstRunDialog; /** The camera manager used to open cameras. */ private OneCameraManager mCameraManager; /** The currently opened camera device, or null if the camera is closed. */ private OneCamera mCamera; + /** The selected picture size. */ + private Size mPictureSize; /** Held when opening or closing the camera. */ private final Semaphore mCameraOpenCloseLock = new Semaphore(1); /** The direction the currently opened camera is facing to. */ - private Facing mCameraFacing = Facing.BACK; + private Facing mCameraFacing; /** Whether HDR is currently enabled. */ private boolean mHdrEnabled = false; @@ -335,6 +332,7 @@ public class CaptureModule extends CameraModule implements /** Constructs a new capture module. */ public CaptureModule(AppController appController, boolean stickyHdr) { super(appController); + mPaused = true; mAppController = appController; mContext = mAppController.getAndroidContext(); mSettingsManager = mAppController.getSettingsManager(); @@ -362,9 +360,8 @@ public class CaptureModule extends CameraModule implements mCameraHandler = new Handler(thread.getLooper()); mCameraManager = mAppController.getCameraManager(); mDisplayRotation = CameraUtil.getDisplayRotation(mContext); - mCameraFacing = getFacingFromCameraId(mSettingsManager.getInteger( - mAppController.getModuleScope(), - Keys.KEY_CAMERA_ID)); + mCameraFacing = getFacingFromCameraId( + mSettingsManager.getInteger(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID)); mUI = new CaptureModuleUI(activity, mAppController.getModuleLayoutRoot(), mUIListener); mAppController.setPreviewStatusListener(mPreviewStatusListener); @@ -389,7 +386,6 @@ public class CaptureModule extends CameraModule implements } }); - mFirstRunDialog = new FirstRunDialog(mAppController, mCameraManager); mMediaActionSound.load(MediaActionSound.SHUTTER_CLICK); } @@ -528,12 +524,11 @@ public class CaptureModule extends CameraModule implements } private void reopenCamera() { - // Don't open camera until the aspect ratio preference is set on devices - // that require us to show it. - if (!mFirstRunDialog.shouldShow()) { - closeCamera(); - openCameraAndStartPreview(); + if (mPaused) { + return; } + closeCamera(); + openCameraAndStartPreview(); } private SurfaceTexture getPreviewSurfaceTexture() { @@ -584,28 +579,6 @@ public class CaptureModule extends CameraModule implements mSoundPlayer.loadSound(R.raw.timer_increment); mHeadingSensor.activate(); - - if (mFirstRunDialog.shouldShow()) { - mFirstRunDialog.setListener(new FirstRunDialog.FirstRunDialogListener() { - @Override - public void onLocationPreferenceConfirmed(boolean locationRecordingEnabled) { - // If this device doesn't need to show the aspect ratio - // dialog, start the preview right away since - // onAspectRatioPreferenceConfirmed will never be called. - if (!mFirstRunDialog.shouldShow()) { - openCameraAndStartPreview(); - } - } - - @Override - public void onAspectRatioPreferenceConfirmed(Rational chosenAspectRatio) { - // Open the camera. This dialog will be dismissed in - // onPreviewStarted() after preview is started. - openCameraAndStartPreview(); - } - }); - mFirstRunDialog.show(); - } } @Override @@ -1036,9 +1009,6 @@ public class CaptureModule extends CameraModule implements mState = ModuleState.UPDATE_TRANSFORM_ON_NEXT_SURFACE_TEXTURE_UPDATE; } - // Dismiss the aspect ratio preference dialog. - mFirstRunDialog.dismiss(); - mAppController.onPreviewStarted(); onReadyStateChanged(true); } @@ -1160,8 +1130,7 @@ public class CaptureModule extends CameraModule implements return; } - Size pictureSize = getPictureSizeFromSettings(); - Size previewBufferSize = mCamera.pickPreviewSize(pictureSize, mContext); + Size previewBufferSize = mCamera.pickPreviewSize(mPictureSize, mContext); mPreviewBufferWidth = previewBufferSize.getWidth(); mPreviewBufferHeight = previewBufferSize.getHeight(); updateFrameDistributorBufferSize(); @@ -1185,9 +1154,9 @@ public class CaptureModule extends CameraModule implements } catch (InterruptedException e) { throw new RuntimeException("Interrupted while waiting to acquire camera-open lock.", e); } - OneCameraCharacteristics oneCameraCharacteristics; + OneCameraCharacteristics cameraCharacteristics; try { - oneCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraFacing); + cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraFacing); } catch (OneCameraAccessException ocae) { mAppController.showErrorAndFinish(R.string.cannot_connect_camera); return; @@ -1210,15 +1179,23 @@ public class CaptureModule extends CameraModule implements // for taking the image. MainThreadExecutor mainThreadExecutor = MainThreadExecutor.create(); ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl - .from(oneCameraCharacteristics); + .from(cameraCharacteristics); ImageBackend imageBackend = ProcessingServiceManager.getImageBackendInstance(); ImageSaver.Builder imageSaverBuilder = new YuvImageBackendImageSaver( mainThreadExecutor, imageRotationCalculator, imageBackend); // Only enable HDR on the back camera boolean useHdr = mHdrEnabled && mCameraFacing == Facing.BACK; - Size pictureSize = getPictureSizeFromSettings(); - mCameraManager.open(mCameraFacing, useHdr, pictureSize, imageSaverBuilder, + + // Read the preferred picture size from the setting. + try { + mPictureSize = mAppController.getResolutionSetting().getPictureSize(mCameraFacing); + } catch (OneCameraAccessException ex) { + mAppController.showErrorAndFinish(R.string.cannot_connect_camera); + return; + } + + mCameraManager.open(mCameraFacing, useHdr, mPictureSize, imageSaverBuilder, new OpenCallback() { @Override public void onFailure() { @@ -1339,13 +1316,6 @@ public class CaptureModule extends CameraModule implements initSurfaceTextureConsumer(); } - private Size getPictureSizeFromSettings() { - String pictureSizeKey = mCameraFacing == Facing.FRONT ? Keys.KEY_PICTURE_SIZE_FRONT - : Keys.KEY_PICTURE_SIZE_BACK; - return SettingsUtil.sizeFromSettingString( - mSettingsManager.getString(SettingsManager.SCOPE_GLOBAL, pictureSizeKey)); - } - private int getPreviewOrientation(int deviceOrientationDegrees) { // Important: Camera2 buffers are already rotated to the natural // orientation of the device (at least for the back-camera). diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index e4a8a1ca9..ea85a0247 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -24,9 +24,6 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.SurfaceTexture; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; import android.media.CameraProfile; @@ -59,12 +56,13 @@ import com.android.camera.hardware.HardwareSpec; import com.android.camera.hardware.HardwareSpecImpl; import com.android.camera.hardware.HeadingSensor; import com.android.camera.module.ModuleController; +import com.android.camera.one.OneCamera; +import com.android.camera.one.OneCameraAccessException; import com.android.camera.remote.RemoteCameraModule; import com.android.camera.settings.CameraPictureSizesCacher; import com.android.camera.settings.Keys; import com.android.camera.settings.ResolutionUtil; import com.android.camera.settings.SettingsManager; -import com.android.camera.settings.SettingsUtil; import com.android.camera.ui.CountDownView; import com.android.camera.ui.TouchCoordinate; import com.android.camera.util.ApiHelper; @@ -269,43 +267,6 @@ public class PhotoModule */ private String mFlashModeBeforeSceneMode; - /** - * This callback gets called when user select whether or not to - * turn on geo-tagging. - */ - public interface LocationDialogCallback { - /** - * Gets called after user selected/unselected geo-tagging feature. - * - * @param selected whether or not geo-tagging feature is selected - */ - public void onLocationTaggingSelected(boolean selected); - } - - /** - * This callback defines the text that is shown in the aspect ratio selection - * dialog, provides the current aspect ratio, and gets notified when user changes - * aspect ratio selection in the dialog. - */ - public interface AspectRatioDialogCallback { - /** - * Returns current aspect ratio that is being used to set as default. - */ - public Rational getCurrentAspectRatio(); - - /** - * Gets notified when user has made the aspect ratio selection. - * - * @param chosenAspectRatio The aspect ratio that user has selected - * @param dialogHandlingFinishedRunnable runnable to run when the operations - * needed to handle changes from dialog - * are finished. - */ - public void onAspectRatioSelected( - Rational chosenAspectRatio, - Runnable dialogHandlingFinishedRunnable); - } - private void checkDisplayRotation() { // Need to just be a no-op for the quick resume-pause scenario. if (mPaused) { @@ -475,95 +436,6 @@ public class PhotoModule mAppController.setShutterEnabled(true); setCameraState(IDLE); startFaceDetection(); - settingsFirstRun(); - } - - /** - * Prompt the user to pick to record location and choose aspect ratio for the - * very first run of camera only. - */ - private void settingsFirstRun() { - final SettingsManager settingsManager = mActivity.getSettingsManager(); - - if (mActivity.isSecureCamera() || isImageCaptureIntent()) { - return; - } - - boolean locationPrompt = !settingsManager.isSet(SettingsManager.SCOPE_GLOBAL, - Keys.KEY_RECORD_LOCATION); - boolean aspectRatioPrompt = !settingsManager.getBoolean( - SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO); - if (!locationPrompt && !aspectRatioPrompt) { - return; - } - - // Check if the back camera exists - int backCameraId = mAppController.getCameraProvider().getFirstBackCameraId(); - if (backCameraId == -1) { - // If there is no back camera, do not show the prompt. - return; - } - - if (locationPrompt) { - // Show both location and aspect ratio selection dialog. - mUI.showLocationAndAspectRatioDialog(new LocationDialogCallback(){ - @Override - public void onLocationTaggingSelected(boolean selected) { - Keys.setLocation(mActivity.getSettingsManager(), selected, - mActivity.getLocationManager()); - } - }, createAspectRatioDialogCallback()); - } else { - // App upgrade. Only show aspect ratio selection. - boolean wasShown = mUI.showAspectRatioDialog(createAspectRatioDialogCallback()); - if (!wasShown) { - // If the dialog was not shown, set this flag to true so that we - // never have to check for it again. It means that we don't need - // to show the dialog on this device. - mActivity.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL, - Keys.KEY_USER_SELECTED_ASPECT_RATIO, true); - } - } - } - - private AspectRatioDialogCallback createAspectRatioDialogCallback() { - Size currentSize = new Size(mCameraSettings.getCurrentPhotoSize()); - final Rational currentAspectRatio = ResolutionUtil.getAspectRatio(currentSize); - AspectRatioDialogCallback callback = new AspectRatioDialogCallback() { - @Override - public Rational getCurrentAspectRatio() { - return currentAspectRatio; - } - - @Override - public void onAspectRatioSelected( - Rational chosenAspectRatio, Runnable dialogHandlingFinishedRunnable) { - List<Size> supportedPhotoSizes = Size.convert(mCameraCapabilities.getSupportedPhotoSizes()); - Size largestPictureSize = ResolutionUtil.getLargestPictureSize( - chosenAspectRatio, supportedPhotoSizes); - mActivity.getSettingsManager().set( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_PICTURE_SIZE_BACK, - SettingsUtil.sizeToSettingString(largestPictureSize)); - mActivity.getSettingsManager().set( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_USER_SELECTED_ASPECT_RATIO, - true); - String aspectRatio = mActivity.getSettingsManager().getString( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_USER_SELECTED_ASPECT_RATIO); - Log.e(TAG, "aspect ratio after setting it to true=" + aspectRatio); - if (chosenAspectRatio != currentAspectRatio) { - Log.i(TAG, "changing aspect ratio from dialog"); - stopPreview(); - startPreview(); - mUI.setRunnableForNextFrame(dialogHandlingFinishedRunnable); - } else { - mHandler.post(dialogHandlingFinishedRunnable); - } - } - }; - return callback; } @Override @@ -2053,21 +1925,22 @@ public class PhotoModule return; } - SettingsManager settingsManager = mActivity.getSettingsManager(); - String pictureSizeKey = isCameraFrontFacing() ? Keys.KEY_PICTURE_SIZE_FRONT - : Keys.KEY_PICTURE_SIZE_BACK; - String pictureSize = settingsManager.getString(SettingsManager.SCOPE_GLOBAL, - pictureSizeKey); - - List<com.android.camera.util.Size> supported = - com.android.camera.util.Size.convert(mCameraCapabilities.getSupportedPhotoSizes()); + List<Size> supported = Size.convert(mCameraCapabilities.getSupportedPhotoSizes()); CameraPictureSizesCacher.updateSizesForCamera(mAppController.getAndroidContext(), mCameraDevice.getCameraId(), supported); - SettingsUtil.setCameraPictureSize(pictureSize, supported, mCameraSettings, - mCameraDevice.getCameraId()); - Size size = SettingsUtil.getPhotoSize(pictureSize, supported, - mCameraDevice.getCameraId()); + OneCamera.Facing cameraFacing = + isCameraFrontFacing() ? OneCamera.Facing.FRONT : OneCamera.Facing.BACK; + Size pictureSize; + try { + pictureSize = mAppController.getResolutionSetting().getPictureSize(cameraFacing); + } catch (OneCameraAccessException ex) { + mAppController.showErrorAndFinish(R.string.cannot_connect_camera); + return; + } + + mCameraSettings.setPhotoSize(pictureSize.toPortabilitySize()); + if (ApiHelper.IS_NEXUS_5) { if (ResolutionUtil.NEXUS_5_LARGE_16_BY_9.equals(pictureSize)) { mShouldResizeTo16x9 = true; @@ -2080,7 +1953,7 @@ public class PhotoModule // the right aspect ratio. List<Size> sizes = Size.convert(mCameraCapabilities.getSupportedPreviewSizes()); Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes, - (double) size.width() / size.height()); + (double) pictureSize.width() / pictureSize.height()); Size original = new Size(mCameraSettings.getCurrentPreviewSize()); if (!optimalSize.equals(original)) { Log.v(TAG, "setting preview size. optimal: " + optimalSize + "original: " + original); diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index 02f98d848..d2e5c093f 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -33,17 +33,12 @@ import android.widget.ImageView; import com.android.camera.debug.DebugPropertyHelper; import com.android.camera.debug.Log; -import com.android.camera.exif.Rational; import com.android.camera.ui.CountDownView; import com.android.camera.ui.FaceView; import com.android.camera.ui.PreviewOverlay; import com.android.camera.ui.PreviewStatusListener; import com.android.camera.ui.focus.FocusRing; -import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; -import com.android.camera.util.GservicesHelper; -import com.android.camera.widget.AspectRatioDialogLayout; -import com.android.camera.widget.LocationDialogLayout; import com.android.camera2.R; import com.android.ex.camera2.portability.CameraAgent; import com.android.ex.camera2.portability.CameraCapabilities; @@ -91,7 +86,6 @@ public class PhotoUI implements PreviewStatusListener, mDialog = null; } }; - private Runnable mRunnableForNextFrame = null; private final CountDownView mCountdownView; @Override @@ -126,13 +120,6 @@ public class PhotoUI implements PreviewStatusListener, } /** - * Sets the runnable to run when the next frame comes in. - */ - public void setRunnableForNextFrame(Runnable runnable) { - mRunnableForNextFrame = runnable; - } - - /** * Starts the countdown timer. * * @param sec seconds to countdown @@ -314,14 +301,6 @@ public class PhotoUI implements PreviewStatusListener, @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { - if (mRunnableForNextFrame != null) { - mRootView.post(mRunnableForNextFrame); - mRunnableForNextFrame = null; - } - } - - public View getRootView() { - return mRootView; } private void initIndicators() { @@ -351,105 +330,6 @@ public class PhotoUI implements PreviewStatusListener, } } - public void showLocationAndAspectRatioDialog( - final PhotoModule.LocationDialogCallback locationCallback, - final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) { - setDialog(new Dialog(mActivity, - android.R.style.Theme_Black_NoTitleBar_Fullscreen)); - final LocationDialogLayout locationDialogLayout = new LocationDialogLayout( - mActivity, true); - locationDialogLayout.setListener(new LocationDialogLayout.LocationDialogListener() { - @Override - public void onConfirm(boolean selected) { - // Update setting. - locationCallback.onLocationTaggingSelected(selected); - - if (showAspectRatioDialogOnThisDevice()) { - // Go to next page. - showAspectRatioDialog(aspectRatioDialogCallback, mDialog); - } else { - // If we don't want to show the aspect ratio dialog, - // dismiss the dialog right after the user chose the - // location setting. - if (mDialog != null) { - mDialog.dismiss(); - } - } - } - }); - mDialog.setContentView(locationDialogLayout, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - mDialog.show(); - } - - /** - * Dismisses previous dialog if any, sets current dialog to the given dialog, - * and set the on dismiss listener for the given dialog. - * @param dialog dialog to show - */ - private void setDialog(Dialog dialog) { - if (mDialog != null) { - mDialog.setOnDismissListener(null); - mDialog.dismiss(); - } - mDialog = dialog; - if (mDialog != null) { - mDialog.setOnDismissListener(mOnDismissListener); - } - } - - /** - * @return Whether the dialog was shown. - */ - public boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) { - if (showAspectRatioDialogOnThisDevice()) { - setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen)); - showAspectRatioDialog(callback, mDialog); - return true; - } else { - return false; - } - } - - private boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback, - final Dialog aspectRatioDialog) { - if (aspectRatioDialog == null) { - Log.e(TAG, "Dialog for aspect ratio is null."); - return false; - } - final AspectRatioDialogLayout aspectRatioDialogLayout = new AspectRatioDialogLayout( - mActivity, callback.getCurrentAspectRatio()); - aspectRatioDialogLayout.setListener( - new AspectRatioDialogLayout.AspectRatioDialogListener() { - @Override - public void onConfirm(Rational chosenAspectRatio) { - callback.onAspectRatioSelected(chosenAspectRatio, new Runnable() { - @Override - public void run() { - if (mDialog != null) { - mDialog.dismiss(); - } - } - }); - } - }); - aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - aspectRatioDialog.show(); - return true; - } - - /** - * @return Whether this is a device that we should show the aspect ratio - * intro dialog on. - */ - private boolean showAspectRatioDialogOnThisDevice() { - // We only want to show that dialog on N4/N5/N6 - // Don't show if using API2 portability, b/17462976 - return !GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity) && - (ApiHelper.IS_NEXUS_4 || ApiHelper.IS_NEXUS_5 || ApiHelper.IS_NEXUS_6); - } - public void initializeZoom(CameraCapabilities capabilities, CameraSettings settings) { if ((capabilities == null) || settings == null || !capabilities.supports(CameraCapabilities.Feature.ZOOM)) { diff --git a/src/com/android/camera/app/AppController.java b/src/com/android/camera/app/AppController.java index 1ec233236..3ebfcac40 100644 --- a/src/com/android/camera/app/AppController.java +++ b/src/com/android/camera/app/AppController.java @@ -32,6 +32,7 @@ import com.android.camera.ButtonManager; import com.android.camera.SoundPlayer; import com.android.camera.module.ModuleController; import com.android.camera.one.OneCameraManager; +import com.android.camera.settings.ResolutionSetting; import com.android.camera.settings.SettingsManager; import com.android.camera.ui.AbstractTutorialOverlay; import com.android.camera.ui.PreviewStatusListener; @@ -365,6 +366,13 @@ public interface AppController { public SettingsManager getSettingsManager(); /** + * Returns the {@link com.android.camera.settings.ResolutionSetting}. + * + * @return the current resolution setting. + */ + public ResolutionSetting getResolutionSetting(); + + /** * @return Common services and functionality to be shared. */ public CameraServices getServices(); diff --git a/src/com/android/camera/app/FirstRunDialog.java b/src/com/android/camera/app/FirstRunDialog.java index 8011e6f21..08c22e77f 100644 --- a/src/com/android/camera/app/FirstRunDialog.java +++ b/src/com/android/camera/app/FirstRunDialog.java @@ -17,52 +17,51 @@ package com.android.camera.app; import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; -import android.graphics.ImageFormat; import android.view.ViewGroup; -import com.android.camera.debug.Log; import com.android.camera.exif.Rational; import com.android.camera.one.OneCamera; import com.android.camera.one.OneCameraAccessException; -import com.android.camera.one.OneCameraCharacteristics; -import com.android.camera.one.OneCameraManager; import com.android.camera.settings.Keys; +import com.android.camera.settings.ResolutionSetting; import com.android.camera.settings.ResolutionUtil; import com.android.camera.settings.SettingsManager; -import com.android.camera.settings.SettingsUtil; import com.android.camera.util.ApiHelper; -import com.android.camera.util.Size; import com.android.camera.widget.AspectRatioDialogLayout; import com.android.camera.widget.LocationDialogLayout; -import java.util.List; - /** * The dialog to show when users open the app for the first time. */ public class FirstRunDialog { public interface FirstRunDialogListener { - - public void onLocationPreferenceConfirmed(boolean locationRecordingEnabled); - - public void onAspectRatioPreferenceConfirmed(Rational chosenAspectRatio); + public void onFirstRunStateReady(); + public void onCameraAccessException(); } - private static final Log.Tag TAG = new Log.Tag("FirstRunDialog"); - /** The default preference of aspect ratio. */ private static final Rational DEFAULT_ASPECT_RATIO = ResolutionUtil.ASPECT_RATIO_4x3; /** The default preference of whether enabling location recording. */ private static final boolean DEFAULT_LOCATION_RECORDING_ENABLED = true; + /** Listener to receive events. */ + private final FirstRunDialogListener mListener; + /** The app controller. */ private final AppController mAppController; - /** The camera manager used to query camera characteristics. */ - private final OneCameraManager mCameraManager; + /** The app context. */ + private final Context mContext; + + /** The resolution settings. */ + private final ResolutionSetting mResolutionSetting; + + /** The settings manager. */ + private final SettingsManager mSettingsManager; /** Aspect ratio preference dialog */ private Dialog mAspectRatioPreferenceDialog; @@ -70,55 +69,30 @@ public class FirstRunDialog { /** Location preference dialog */ private Dialog mLocationPreferenceDialog; - /** Listener to receive events. */ - private FirstRunDialogListener mListener; - /** * Constructs a first run dialog. * * @param appController The app controller. - * @param cameraManager The camera manager used to query supported aspect - * ratio by camera devices. */ - public FirstRunDialog(AppController appController, OneCameraManager cameraManager) { - mAppController = appController; - mCameraManager = cameraManager; - } - - /** - * Set a dialog listener. - * - * @param listener The dialog listener to be set. - */ - public void setListener(FirstRunDialogListener listener) { + public FirstRunDialog(AppController appController, FirstRunDialogListener listener) { mListener = listener; - } - - /** - * Whether first run dialogs should be presented to the user. - * - * @return Whether first run dialogs should be presented to the user. - */ - public boolean shouldShow() { - return shouldShowAspectRatioPreferenceDialog() || shouldShowLocationPreferenceDialog(); + mAppController = appController; + mContext = mAppController.getAndroidContext(); + mResolutionSetting = mAppController.getResolutionSetting(); + mSettingsManager = mAppController.getSettingsManager(); } /** * Shows first run dialogs if necessary. - * - * @return Whether first run dialogs are shown. */ - public boolean show() { - // When people open the app for the first time, prompt two dialogs to - // ask preferences about - // location and aspect ratio. - if (promptLocationPreferenceDialog()) { - return true; + public void showIfNecessary() { + if (shouldShow()) { + // When people open the app for the first time, prompt two dialogs to + // ask preferences about location and aspect ratio. The first dialog is + // location reference. + promptLocationPreferenceDialog(); } else { - // This should be a rare case because location and aspect ratio - // preferences usually got - // set at the same time when people open the app for the first time. - return promptAspectRatioPreferenceDialog(); + mListener.onFirstRunStateReady(); } } @@ -135,76 +109,54 @@ public class FirstRunDialog { } /** - * Whether a aspect ratio dialog should be presented to the user. + * Whether first run dialogs should be presented to the user. * - * @return Whether a aspect ratio dialog should be presented to the user. + * @return Whether first run dialogs should be presented to the user. */ - private boolean shouldShowAspectRatioPreferenceDialog() { - final SettingsManager settingsManager = mAppController.getSettingsManager(); - final boolean isAspectRatioPreferenceSet = settingsManager.getBoolean( + private boolean shouldShow() { + final boolean isAspectRatioPreferenceSet = mSettingsManager.getBoolean( SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO); - return ApiHelper.shouldShowAspectRatioDialog() && !isAspectRatioPreferenceSet; + final boolean isAspectRatioDevice = + ApiHelper.IS_NEXUS_4 || ApiHelper.IS_NEXUS_5 || ApiHelper.IS_NEXUS_6; + final boolean shouldShowAspectRatioDialog = + isAspectRatioDevice && !isAspectRatioPreferenceSet; + final boolean shouldShowLocationDialog = + !mSettingsManager.isSet(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION); + return shouldShowAspectRatioDialog || shouldShowLocationDialog; } /** * Prompts a dialog to allow people to choose aspect ratio preference when * people open the app for the first time. If the preference has been set, * this will return false. - * - * @return Whether the dialog will be prompted or not. */ - private boolean promptAspectRatioPreferenceDialog() { - // Do nothing if the preference is already set. - if (!shouldShowAspectRatioPreferenceDialog()) { - return false; - } - + private void promptAspectRatioPreferenceDialog() { // Create a content view for the dialog. final AspectRatioDialogLayout dialogLayout = new AspectRatioDialogLayout( - mAppController.getAndroidContext(), DEFAULT_ASPECT_RATIO); + mContext, DEFAULT_ASPECT_RATIO); dialogLayout.setListener(new AspectRatioDialogLayout.AspectRatioDialogListener() { @Override public void onConfirm(Rational aspectRatio) { + // Change resolution setting based on the chosen aspect ratio. try { - final SettingsManager settingsManager = - mAppController.getSettingsManager(); - - // Save the picture size setting for back camera. - OneCameraCharacteristics backCameraChars = - mCameraManager.getCameraCharacteristics(OneCamera.Facing.BACK); - List<Size> backCameraPictureSizes = - backCameraChars.getSupportedPictureSizes(ImageFormat.JPEG); - Size backCameraChosenPictureSize = - ResolutionUtil.getLargestPictureSize( - aspectRatio, backCameraPictureSizes); - settingsManager.set( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_PICTURE_SIZE_BACK, - SettingsUtil.sizeToSettingString(backCameraChosenPictureSize)); - - // Save the picture size setting for front camera. - OneCameraCharacteristics frontCameraChars = - mCameraManager.getCameraCharacteristics(OneCamera.Facing.FRONT); - List<Size> frontCameraPictureSizes = - frontCameraChars.getSupportedPictureSizes(ImageFormat.JPEG); - Size frontCameraChosenPictureSize = - ResolutionUtil.getLargestPictureSize( - aspectRatio, frontCameraPictureSizes); - settingsManager.set( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_PICTURE_SIZE_FRONT, - SettingsUtil.sizeToSettingString(frontCameraChosenPictureSize)); - - // Indicate the aspect ratio is selected. - settingsManager.set( - SettingsManager.SCOPE_GLOBAL, - Keys.KEY_USER_SELECTED_ASPECT_RATIO, - true); + mResolutionSetting.setPictureAspectRatio(OneCamera.Facing.BACK, aspectRatio); + mResolutionSetting.setPictureAspectRatio(OneCamera.Facing.FRONT, aspectRatio); } catch (OneCameraAccessException ex) { - throw new RuntimeException(ex); + mListener.onCameraAccessException(); + return; } - mListener.onAspectRatioPreferenceConfirmed(aspectRatio); + // Mark that user has made the choice. + mSettingsManager.set( + SettingsManager.SCOPE_GLOBAL, + Keys.KEY_USER_SELECTED_ASPECT_RATIO, + true); + + // Dismiss all dialogs. + dismiss(); + + // Notify that the app is ready to go. + mListener.onFirstRunStateReady(); } }); @@ -221,47 +173,27 @@ public class FirstRunDialog { // Show the dialog. mAspectRatioPreferenceDialog.show(); - return true; - } - - /** - * Whether a location dialog should be presented to the user. - * - * @return Whether a location dialog should be presented to the user. - */ - private boolean shouldShowLocationPreferenceDialog() { - final SettingsManager settingsManager = mAppController.getSettingsManager(); - return !settingsManager.isSet(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION); } /** * Prompts a dialog to allow people to choose location preference when * people open the app for the first time. If the preference has been set, * this will return false. - * - * @return Whether the dialog will be prompted or not. */ - private boolean promptLocationPreferenceDialog() { - // Do nothing if the preference is already set. - if (!shouldShowLocationPreferenceDialog()) { - return false; - } - + private void promptLocationPreferenceDialog() { // Create a content view for the dialog. final LocationDialogLayout dialogLayout = new LocationDialogLayout( - mAppController.getAndroidContext(), DEFAULT_LOCATION_RECORDING_ENABLED); + mContext, DEFAULT_LOCATION_RECORDING_ENABLED); dialogLayout.setListener(new LocationDialogLayout.LocationDialogListener() { @Override public void onConfirm(boolean locationRecordingEnabled) { - mAppController.getSettingsManager().set( + // Change the location preference setting. + mSettingsManager.set( SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION, locationRecordingEnabled); - mAppController.getLocationManager().recordLocation( - locationRecordingEnabled); - - mListener.onLocationPreferenceConfirmed(locationRecordingEnabled); + // Prompt the second dialog about aspect ratio preference. promptAspectRatioPreferenceDialog(); } }); @@ -279,6 +211,5 @@ public class FirstRunDialog { // Show the dialog. mLocationPreferenceDialog.show(); - return true; } } diff --git a/src/com/android/camera/one/OneCameraManager.java b/src/com/android/camera/one/OneCameraManager.java index 686e74bde..9a4fe0c65 100644 --- a/src/com/android/camera/one/OneCameraManager.java +++ b/src/com/android/camera/one/OneCameraManager.java @@ -16,19 +16,16 @@ package com.android.camera.one; -import android.content.Context; -import android.hardware.camera2.CameraManager; +import com.google.common.base.Optional; + import android.os.Handler; import android.util.DisplayMetrics; -import android.view.WindowManager; import com.android.camera.CameraActivity; -import com.android.camera.debug.Log; import com.android.camera.debug.Log.Tag; import com.android.camera.one.OneCamera.Facing; import com.android.camera.one.OneCamera.OpenCallback; import com.android.camera.one.v2.imagesaver.ImageSaver; -import com.android.camera.util.ApiHelper; import com.android.camera.util.Size; /** @@ -83,8 +80,9 @@ public abstract class OneCameraManager { * @throws OneCameraException Thrown if an error occurred while trying to * access the camera. */ - public static OneCameraManager get(CameraActivity activity) throws OneCameraException { - return create(activity); + public static OneCameraManager get(CameraActivity activity, DisplayMetrics displayMetrics) + throws OneCameraException { + return create(activity, displayMetrics); } /** @@ -93,32 +91,16 @@ public abstract class OneCameraManager { * @throws OneCameraException Thrown if an error occurred while trying to * access the camera. */ - private static OneCameraManager create(CameraActivity activity) throws OneCameraException { - DisplayMetrics displayMetrics = getDisplayMetrics(activity); - CameraManager cameraManager = null; - - try { - cameraManager = ApiHelper.HAS_CAMERA_2_API ? (CameraManager) activity - .getSystemService(Context.CAMERA_SERVICE) : null; - } catch (IllegalStateException ex) { - cameraManager = null; - Log.e(TAG, "Could not get camera service v2", ex); + private static OneCameraManager create(CameraActivity activity, DisplayMetrics displayMetrics) + throws OneCameraException { + Optional<OneCameraManager> manager = + com.android.camera.one.v2.OneCameraManagerImpl.create(activity, displayMetrics); + if (!manager.isPresent()) { + manager = com.android.camera.one.v1.OneCameraManagerImpl.create(activity); } - int maxMemoryMB = activity.getServices().getMemoryManager() - .getMaxAllowedNativeMemoryAllocation(); - return new com.android.camera.one.v2.OneCameraManagerImpl( - activity, cameraManager, maxMemoryMB, - displayMetrics, activity.getSoundPlayer()); - } - - private static DisplayMetrics getDisplayMetrics(Context context) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - WindowManager wm = (WindowManager) - context.getSystemService(Context.WINDOW_SERVICE); - if (wm != null) { - displayMetrics = new DisplayMetrics(); - wm.getDefaultDisplay().getMetrics(displayMetrics); + if (!manager.isPresent()) { + throw new OneCameraException("No camera manager is available."); } - return displayMetrics; + return manager.get(); } } diff --git a/src/com/android/camera/one/v1/OneCameraCharacteristicsImpl.java b/src/com/android/camera/one/v1/OneCameraCharacteristicsImpl.java new file mode 100644 index 000000000..fc4bc95fc --- /dev/null +++ b/src/com/android/camera/one/v1/OneCameraCharacteristicsImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.one.v1; + +import android.graphics.Rect; +import android.hardware.Camera; + +import com.android.camera.one.OneCamera; +import com.android.camera.one.OneCameraCharacteristics; +import com.android.camera.util.Size; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describes a OneCamera device which is on top of camera1 API. + */ +public class OneCameraCharacteristicsImpl implements OneCameraCharacteristics { + private final Camera.CameraInfo mCameraInfo; + + /** The supported picture sizes. */ + private final ArrayList<Size> mSupportedPictureSizes = new ArrayList<>(); + + /** The supported preview sizes. */ + private final ArrayList<Size> mSupportedPreviewSizes = new ArrayList<>(); + + public OneCameraCharacteristicsImpl( + Camera.CameraInfo cameraInfo, Camera.Parameters cameraParameters) { + mCameraInfo = cameraInfo; + + List<Camera.Size> supportedPictureSizes = cameraParameters.getSupportedPictureSizes(); + if (supportedPictureSizes != null) { + for (Camera.Size pictureSize : supportedPictureSizes) { + mSupportedPictureSizes.add(new Size(pictureSize)); + } + } + + List<Camera.Size> supportedPreviewSizes = cameraParameters.getSupportedPreviewSizes(); + if (supportedPreviewSizes != null) { + for (Camera.Size previewSize : supportedPreviewSizes) { + mSupportedPreviewSizes.add(new Size(previewSize)); + } + } + } + + @Override + public List<Size> getSupportedPictureSizes(int imageFormat) { + return mSupportedPictureSizes; + } + + @Override + public List<Size> getSupportedPreviewSizes() { + return mSupportedPreviewSizes; + } + + @Override + public int getSensorOrientation() { + return mCameraInfo.orientation; + } + + @Override + public OneCamera.Facing getCameraDirection() { + int direction = mCameraInfo.facing; + if (direction == Camera.CameraInfo.CAMERA_FACING_BACK) { + return OneCamera.Facing.BACK; + } else { + return OneCamera.Facing.FRONT; + } + } + + @Override + public Rect getSensorInfoActiveArraySize() { + throw new RuntimeException("Not implemented yet."); + } + + @Override + public float getAvailableMaxDigitalZoom() { + throw new RuntimeException("Not implemented yet."); + } +} diff --git a/src/com/android/camera/one/v1/OneCameraManagerImpl.java b/src/com/android/camera/one/v1/OneCameraManagerImpl.java index 54076dcb4..87b541905 100644 --- a/src/com/android/camera/one/v1/OneCameraManagerImpl.java +++ b/src/com/android/camera/one/v1/OneCameraManagerImpl.java @@ -16,20 +16,80 @@ package com.android.camera.one.v1; +import com.google.common.base.Optional; + +import android.hardware.Camera; import android.os.Handler; +import com.android.camera.CameraActivity; +import com.android.camera.debug.Log; import com.android.camera.one.OneCamera.Facing; import com.android.camera.one.OneCamera.OpenCallback; +import com.android.camera.one.OneCameraAccessException; import com.android.camera.one.OneCameraCharacteristics; import com.android.camera.one.OneCameraManager; import com.android.camera.one.v2.imagesaver.ImageSaver; import com.android.camera.util.Size; /** - * The {@link OneCameraManager} implementation on top of the Camera 1 API - * portability layer. + * The {@link OneCameraManager} implementation on top of the Camera API 1. */ public class OneCameraManagerImpl extends OneCameraManager { + private static final Log.Tag TAG = new Log.Tag("OneCameraMgrImpl1"); + + private static final int NO_DEVICE = -1; + + private final int mFirstBackCameraId; + private final int mFirstFrontCameraId; + private final Camera.CameraInfo[] mCameraInfos; + + OneCameraCharacteristics mBackCameraCharacteristics; + OneCameraCharacteristics mFrontCameraCharacteristics; + + public static Optional<OneCameraManager> create(CameraActivity activity) { + int numberOfCameras; + Camera.CameraInfo[] cameraInfos; + try { + numberOfCameras = Camera.getNumberOfCameras(); + cameraInfos = new Camera.CameraInfo[numberOfCameras]; + for (int i = 0; i < numberOfCameras; i++) { + cameraInfos[i] = new Camera.CameraInfo(); + Camera.getCameraInfo(i, cameraInfos[i]); + } + } catch (RuntimeException ex) { + Log.e(TAG, "Exception while creating CameraDeviceInfo", ex); + return Optional.absent(); + } + + int firstFront = NO_DEVICE; + int firstBack = NO_DEVICE; + // Get the first (smallest) back and first front camera id. + for (int i = numberOfCameras - 1; i >= 0; i--) { + if (cameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_BACK) { + firstBack = i; + } else { + if (cameraInfos[i].facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + firstFront = i; + } + } + } + + OneCameraManager cameraManager = + new OneCameraManagerImpl(firstBack, firstFront, cameraInfos); + return Optional.of(cameraManager); + } + + /** + * Instantiates a new {@link OneCameraManager} for Camera1 API. + */ + public OneCameraManagerImpl( + int firstBackCameraId, + int firstFrontCameraId, + Camera.CameraInfo[] info) { + mFirstBackCameraId = firstBackCameraId; + mFirstFrontCameraId = firstFrontCameraId; + mCameraInfos = info; + } @Override public void open(Facing facing, boolean enableHdr, Size pictureSize, @@ -39,11 +99,49 @@ public class OneCameraManagerImpl extends OneCameraManager { @Override public boolean hasCameraFacing(Facing facing) { - throw new RuntimeException("Not implemented yet."); + if (facing == Facing.BACK) { + return mFirstBackCameraId != NO_DEVICE; + } else if (facing == Facing.FRONT) { + return mFirstFrontCameraId != NO_DEVICE; + } + return false; } @Override - public OneCameraCharacteristics getCameraCharacteristics(Facing facing) { - throw new RuntimeException("Not implemented yet."); + public OneCameraCharacteristics getCameraCharacteristics(Facing facing) + throws OneCameraAccessException { + // Returns the cached object if there exists one. + if (facing == Facing.BACK && mBackCameraCharacteristics != null) { + return mBackCameraCharacteristics; + } else if (facing == Facing.FRONT && mFrontCameraCharacteristics != null) { + return mFrontCameraCharacteristics; + } + + int cameraId = NO_DEVICE; + if (facing == Facing.BACK) { + cameraId = mFirstBackCameraId; + } else if (facing == Facing.FRONT) { + cameraId = mFirstFrontCameraId; + } + if (cameraId == NO_DEVICE) { + throw new OneCameraAccessException( + "Unable to get camera characteristics (no camera id.)"); + } + + OneCameraCharacteristics characteristics; + Camera camera = null; + try { + camera = Camera.open(cameraId); + Camera.Parameters cameraParameters = camera.getParameters(); + if (cameraParameters == null) { + Log.e(TAG, "Camera object returned null parameters!"); + throw new OneCameraAccessException("API1 Camera.getParameters() returned null"); + } + characteristics = new OneCameraCharacteristicsImpl( + mCameraInfos[cameraId], cameraParameters); + } finally { + camera.release(); + } + return characteristics; } }
\ No newline at end of file diff --git a/src/com/android/camera/one/v2/OneCameraManagerImpl.java b/src/com/android/camera/one/v2/OneCameraManagerImpl.java index 3cc2e4bbb..100e3bea5 100644 --- a/src/com/android/camera/one/v2/OneCameraManagerImpl.java +++ b/src/com/android/camera/one/v2/OneCameraManagerImpl.java @@ -16,13 +16,17 @@ package com.android.camera.one.v2; +import android.annotation.TargetApi; +import android.content.Context; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; +import android.os.Build; import android.os.Handler; import android.util.DisplayMetrics; +import com.android.camera.CameraActivity; import com.android.camera.SoundPlayer; import com.android.camera.app.AppController; import com.android.camera.debug.Log; @@ -34,11 +38,15 @@ import com.android.camera.one.OneCameraAccessException; import com.android.camera.one.OneCameraCharacteristics; import com.android.camera.one.OneCameraManager; import com.android.camera.one.v2.imagesaver.ImageSaver; +import com.android.camera.util.ApiHelper; import com.android.camera.util.Size; +import com.google.common.base.Optional; + /** * The {@link OneCameraManager} implementation on top of Camera2 API. */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class OneCameraManagerImpl extends OneCameraManager { private static final Tag TAG = new Tag("OneCameraMgrImpl2"); @@ -48,6 +56,25 @@ public class OneCameraManagerImpl extends OneCameraManager { private final DisplayMetrics mDisplayMetrics; private final SoundPlayer mSoundPlayer; + public static Optional<OneCameraManager> create(CameraActivity activity, DisplayMetrics displayMetrics) { + if (!ApiHelper.HAS_CAMERA_2_API) { + return Optional.absent(); + } + CameraManager cameraManager; + try { + cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); + } catch (IllegalStateException ex) { + Log.e(TAG, "camera2.CameraManager is not available."); + return Optional.absent(); + } + final int maxMemoryMB = activity.getServices().getMemoryManager() + .getMaxAllowedNativeMemoryAllocation(); + final SoundPlayer soundPlayer = activity.getSoundPlayer(); + OneCameraManager oneCameraManager = new OneCameraManagerImpl( + activity, cameraManager, maxMemoryMB, displayMetrics, soundPlayer); + return Optional.of(oneCameraManager); + } + /** * Instantiates a new {@link OneCameraManager} for Camera2 API. * diff --git a/src/com/android/camera/settings/Keys.java b/src/com/android/camera/settings/Keys.java index 35d0aca81..6b3ce5b20 100644 --- a/src/com/android/camera/settings/Keys.java +++ b/src/com/android/camera/settings/Keys.java @@ -68,7 +68,12 @@ public class Keys { "pref_should_show_refocus_viewer_cling"; public static final String KEY_EXPOSURE_COMPENSATION_ENABLED = "pref_camera_exposure_compensation_key"; + + /** + * Whether the user has chosen an aspect ratio on the first run dialog. + */ public static final String KEY_USER_SELECTED_ASPECT_RATIO = "pref_user_selected_aspect_ratio"; + public static final String KEY_COUNTDOWN_DURATION = "pref_camera_countdown_duration_key"; public static final String KEY_HDR_PLUS_FLASH_MODE = "pref_hdr_plus_flash_mode"; public static final String KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING = @@ -211,53 +216,5 @@ public class Keys { return settingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, KEY_CAMERA_GRID_LINES); } - - /** - * Returns whether pano orientation is horizontal. - */ - public static boolean isPanoOrientationHorizontal(SettingsManager settingsManager) { - return settingsManager.isDefault(SettingsManager.SCOPE_GLOBAL, - KEY_CAMERA_PANO_ORIENTATION); - } - - /** - * Sets the settings for whether location recording should be enabled or - * not. Also makes sure to pass on the change to the location manager. - */ - public static void setLocation(SettingsManager settingsManager, boolean on, - LocationManager locationManager) { - settingsManager.set(SettingsManager.SCOPE_GLOBAL, KEY_RECORD_LOCATION, on); - locationManager.recordLocation(on); - } - - /** - * Sets the user selected aspect ratio setting to selected. - */ - public static void setAspectRatioSelected(SettingsManager settingsManager) { - settingsManager.set(SettingsManager.SCOPE_GLOBAL, - KEY_USER_SELECTED_ASPECT_RATIO, true); - } - - /** - * Sets the manual exposure compensation enabled setting - * to on/off based on the given argument. - */ - public static void setManualExposureCompensation(SettingsManager settingsManager, - boolean on) { - settingsManager.set(SettingsManager.SCOPE_GLOBAL, - KEY_EXPOSURE_COMPENSATION_ENABLED, on); - } - - /** - * Reads the current location recording settings and passes it on to the - * given location manager. - */ - public static void syncLocationManager(SettingsManager settingsManager, - LocationManager locationManager) { - boolean value = settingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, - KEY_RECORD_LOCATION); - locationManager.recordLocation(value); - } - } diff --git a/src/com/android/camera/settings/ResolutionSetting.java b/src/com/android/camera/settings/ResolutionSetting.java new file mode 100644 index 000000000..d5d91f57f --- /dev/null +++ b/src/com/android/camera/settings/ResolutionSetting.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.settings; + +import com.android.camera.debug.Log; +import com.android.camera.exif.Rational; +import com.android.camera.one.OneCamera; +import com.android.camera.one.OneCameraAccessException; +import com.android.camera.one.OneCameraCharacteristics; +import com.android.camera.one.OneCameraManager; +import com.android.camera.util.Size; + +import android.graphics.ImageFormat; + +import java.util.List; + +/** + * Handles the picture resolution setting stored in SharedPreferences keyed by + * Keys.KEY_PICTURE_SIZE_BACK and Keys.KEY_PICTURE_SIZE_FRONT. + */ +public class ResolutionSetting { + private static final Log.Tag TAG = new Log.Tag("ResolutionSettings"); + + private final SettingsManager mSettingsManager; + + private final OneCameraManager mOneCameraManager; + + public ResolutionSetting(SettingsManager settingsManager, OneCameraManager oneCameraManager) { + mSettingsManager = settingsManager; + mOneCameraManager = oneCameraManager; + } + + /** + * Changes the picture size settings for the cameras with specified facing. + * Pick the largest picture size with the specified aspect ratio. + * + * @param cameraFacing The specified direction that the camera is facing. + * @param aspectRatio The chosen aspect ratio. + */ + public void setPictureAspectRatio(OneCamera.Facing cameraFacing, Rational aspectRatio) + throws OneCameraAccessException { + OneCameraCharacteristics cameraCharacteristics = + mOneCameraManager.getCameraCharacteristics(cameraFacing); + + // Pick the largest picture size with the selected aspect ratio and save the choice for front camera. + final String pictureSizeSettingKey = cameraFacing == OneCamera.Facing.FRONT ? + Keys.KEY_PICTURE_SIZE_FRONT : Keys.KEY_PICTURE_SIZE_BACK; + final List<Size> supportedPictureSizes = + cameraCharacteristics.getSupportedPictureSizes(ImageFormat.JPEG); + final Size chosenPictureSize = + ResolutionUtil.getLargestPictureSize(aspectRatio, supportedPictureSizes); + mSettingsManager.set( + SettingsManager.SCOPE_GLOBAL, + pictureSizeSettingKey, + SettingsUtil.sizeToSettingString(chosenPictureSize)); + } + + /** + * Reads the picture size setting for the cameras with specified facing. + * + * @param cameraFacing The specified direction that the camera is facing. + * @return The preferred picture size. + */ + public Size getPictureSize(OneCamera.Facing cameraFacing) throws OneCameraAccessException { + final String pictureSizeSettingKey = cameraFacing == OneCamera.Facing.FRONT ? + Keys.KEY_PICTURE_SIZE_FRONT : Keys.KEY_PICTURE_SIZE_BACK; + + /** + * If there is no saved reference, pick a largest size with 4:3 aspect + * ratio as a fallback. + */ + final boolean isPictureSizeSettingSet = + mSettingsManager.isSet(SettingsManager.SCOPE_GLOBAL, pictureSizeSettingKey); + if (!isPictureSizeSettingSet) { + final Rational aspectRatio = ResolutionUtil.ASPECT_RATIO_4x3; + + final OneCameraCharacteristics cameraCharacteristics = + mOneCameraManager.getCameraCharacteristics(cameraFacing); + final List<Size> supportedPictureSizes = + cameraCharacteristics.getSupportedPictureSizes(ImageFormat.JPEG); + final Size fallbackPictureSize = + ResolutionUtil.getLargestPictureSize(aspectRatio, supportedPictureSizes); + mSettingsManager.set( + SettingsManager.SCOPE_GLOBAL, + pictureSizeSettingKey, + SettingsUtil.sizeToSettingString(fallbackPictureSize)); + Log.e(TAG, "Picture size setting is not set. Choose " + fallbackPictureSize); + } + + /** Reads picture size setting from SettingsManager. */ + return SettingsUtil.sizeFromSettingString( + mSettingsManager.getString(SettingsManager.SCOPE_GLOBAL, pictureSizeSettingKey)); + } +}
\ No newline at end of file diff --git a/src/com/android/camera/settings/ResolutionUtil.java b/src/com/android/camera/settings/ResolutionUtil.java index 40ee4ee5a..913a0f640 100644 --- a/src/com/android/camera/settings/ResolutionUtil.java +++ b/src/com/android/camera/settings/ResolutionUtil.java @@ -20,6 +20,10 @@ import com.android.camera.exif.Rational; import com.android.camera.util.ApiHelper; import com.android.camera.util.Size; +import android.content.Context; +import android.util.DisplayMetrics; +import android.view.WindowManager; + import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -370,4 +374,15 @@ public class ResolutionUtil { } return maxSize; } + + public static DisplayMetrics getDisplayMetrics(Context context) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) + context.getSystemService(Context.WINDOW_SERVICE); + if (wm != null) { + wm.getDefaultDisplay().getMetrics(displayMetrics); + } + return displayMetrics; + } + } diff --git a/src/com/android/camera/settings/SettingsUtil.java b/src/com/android/camera/settings/SettingsUtil.java index 732a834a0..728e7a920 100644 --- a/src/com/android/camera/settings/SettingsUtil.java +++ b/src/com/android/camera/settings/SettingsUtil.java @@ -148,26 +148,6 @@ public class SettingsUtil { new SparseArray<SelectedVideoQualities>(2); /** - * Based on the selected size, this method selects the matching concrete - * resolution and sets it as the picture size. - * - * @param sizeSetting The setting selected by the user. One of "large", - * "medium, "small" or two integers separated by "x". - * @param supported The list of supported resolutions. - * @param settings The Camera settings to set the selected picture - * resolution on. - * @param cameraId This is used for caching the results for finding the - * different sizes. - */ - public static void setCameraPictureSize(String sizeSetting, List<Size> supported, - CameraSettings settings, int cameraId) { - Size selectedSize = getCameraPictureSize(sizeSetting, supported, cameraId); - Log.d(TAG, "Selected " + sizeSetting + " resolution: " + selectedSize.getWidth() + "x" + - selectedSize.getHeight()); - settings.setPhotoSize(selectedSize.toPortabilitySize()); - } - - /** * Based on the selected size, this method returns the matching concrete * resolution. * diff --git a/src/com/android/camera/util/ApiHelper.java b/src/com/android/camera/util/ApiHelper.java index 046a9f9b4..67a67a8c7 100644 --- a/src/com/android/camera/util/ApiHelper.java +++ b/src/com/android/camera/util/ApiHelper.java @@ -99,8 +99,4 @@ public class ApiHelper { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP || "L".equals(Build.VERSION.CODENAME); } - - public static boolean shouldShowAspectRatioDialog() { - return IS_NEXUS_4 || IS_NEXUS_5 || IS_NEXUS_6; - } } |