CaptureModule first run dialog.

* Introduce FirstRunDialog.
* Add OneCameraCharacteristics so we can query camera properties without
  opening the camera.
* Refactor AspectRatioDialogLayout and LocationDialogLayout to clean up.
* Refactor to move away from portability/Size class in Camera2.

Bug: 18623223
Change-Id: I05f4eefe3ee2feeaa47b6296f8926f6be8e83051
diff --git a/res/layout-land/aspect_ratio_selector.xml b/res/layout-land/aspect_ratio_selector.xml
index 5b8ea7c..6d32f58 100644
--- a/res/layout-land/aspect_ratio_selector.xml
+++ b/res/layout-land/aspect_ratio_selector.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<com.android.camera.widget.AspectRatioSelector
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/aspect_ratio_selector"
     android:orientation="vertical"
@@ -67,4 +67,4 @@
             android:gravity="center"
             android:layout_weight="1"/>
     </LinearLayout>
-</com.android.camera.widget.AspectRatioSelector>
+</LinearLayout>
diff --git a/res/layout-port/aspect_ratio_selector.xml b/res/layout-port/aspect_ratio_selector.xml
index 69f0d80..96e8aa6 100644
--- a/res/layout-port/aspect_ratio_selector.xml
+++ b/res/layout-port/aspect_ratio_selector.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<com.android.camera.widget.AspectRatioSelector
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/aspect_ratio_selector"
     android:orientation="vertical" >
@@ -38,4 +38,4 @@
             android:src="@drawable/aspect_ratio_16x9"
             android:layout_marginLeft="28dp"/>
     </LinearLayout>
-</com.android.camera.widget.AspectRatioSelector>
+</LinearLayout>
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 66525af..91b07b3 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -19,6 +19,7 @@
 
 import android.animation.Animator;
 import android.app.ActionBar;
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.ActivityNotFoundException;
@@ -982,6 +983,11 @@
     }
 
     @Override
+    public Dialog createDialog() {
+        return new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
+    }
+
+    @Override
     public void launchActivityByIntent(Intent intent) {
         // Starting from L, we prefer not to start edit activity within camera's task.
         mResetToPreviewOnResume = false;
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 7c00015..1ca4874 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -43,6 +43,7 @@
 import com.android.camera.app.CameraAppUI.BottomBarUISpec;
 import com.android.camera.app.LocationManager;
 import com.android.camera.app.MediaSaver;
+import com.android.camera.app.FirstRunDialog;
 import com.android.camera.burst.BurstFacade;
 import com.android.camera.burst.BurstFacadeFactory;
 import com.android.camera.burst.BurstReadyStateChangeListener;
@@ -51,6 +52,7 @@
 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.gl.FrameDistributor.FrameConsumer;
 import com.android.camera.gl.FrameDistributorWrapper;
 import com.android.camera.gl.SurfaceTextureConsumer;
@@ -69,6 +71,7 @@
 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;
@@ -149,7 +152,10 @@
     private final SettingsManager mSettingsManager;
     /** Application context. */
     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. */
@@ -320,6 +326,8 @@
                 cancelCountDown();
             }
         });
+
+        mFirstRunDialog = new FirstRunDialog(mAppController, mCameraManager);
     }
 
     @Override
@@ -503,8 +511,14 @@
                 || mPreviewConsumer.getHeight() != height) {
             mPreviewConsumer.setSize(width, height);
         }
-        closeCamera();
-        openCameraAndStartPreview();
+
+        // Don't open camera until the aspect ratio preference is set.
+        final boolean isAspectRatioPreferenceSet = mAppController.getSettingsManager().getBoolean(
+                SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO);
+        if (isAspectRatioPreferenceSet) {
+            closeCamera();
+            openCameraAndStartPreview();
+        }
     }
 
     @Override
@@ -585,6 +599,20 @@
 
         mSoundPlayer.loadSound(R.raw.timer_final_second);
         mSoundPlayer.loadSound(R.raw.timer_increment);
+
+        if (mFirstRunDialog.shouldShow()) {
+            mFirstRunDialog.setListener(new FirstRunDialog.FirstRunDialogListener() {
+                public void onLocationPreferenceConfirmed(boolean locationRecordingEnabled) {
+                }
+
+                public void onAspectRatioPreferenceConfirmed(Rational chosenAspectRatio) {
+                    // Open the camera. This dialog will be dismissed in onPreviewStarted() after
+                    // preview is started.
+                    openCameraAndStartPreview();
+                }
+            });
+            mFirstRunDialog.show();
+        }
     }
 
     @Override
@@ -1047,6 +1075,10 @@
         if (mState == ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED) {
             mState = ModuleState.UPDATE_TRANSFORM_ON_NEXT_SURFACE_TEXTURE_UPDATE;
         }
+
+        // Dismiss the aspect ratio preference dialog.
+        mFirstRunDialog.dismiss();
+
         mAppController.onPreviewStarted();
         onReadyStateChanged(true);
     }
@@ -1194,9 +1226,6 @@
      * Open camera and start the preview.
      */
     private void openCameraAndStartPreview() {
-        // Only enable HDR on the back camera
-        boolean useHdr = mHdrEnabled && mCameraFacing == Facing.BACK;
-
         try {
             // TODO Given the current design, we cannot guarantee that one of
             // CaptureReadyCallback.onSetupFailed or onReadyForCapture will
@@ -1216,7 +1245,10 @@
             mCameraOpenCloseLock.release();
             return;
         }
-        mCameraManager.open(mCameraFacing, useHdr, getPictureSizeFromSettings(),
+        // Only enable HDR on the back camera
+        boolean useHdr = mHdrEnabled && mCameraFacing == Facing.BACK;
+        Size pictureSize = getPictureSizeFromSettings();
+        mCameraManager.open(mCameraFacing, useHdr, pictureSize,
                 new OpenCallback() {
                     @Override
                     public void onFailure() {
@@ -1354,7 +1386,8 @@
     private Size getPictureSizeFromSettings() {
         String pictureSizeKey = mCameraFacing == Facing.FRONT ? Keys.KEY_PICTURE_SIZE_FRONT
                 : Keys.KEY_PICTURE_SIZE_BACK;
-        return mSettingsManager.getSize(SettingsManager.SCOPE_GLOBAL, pictureSizeKey);
+        return SettingsUtil.sizeFromSettingString(
+                mSettingsManager.getString(SettingsManager.SCOPE_GLOBAL, pictureSizeKey));
     }
 
     private int getPreviewOrientation(int deviceOrientationDegrees) {
@@ -1399,4 +1432,4 @@
             return Flash.AUTO;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/camera/CaptureModuleUI.java b/src/com/android/camera/CaptureModuleUI.java
index 6d71660..3075435 100644
--- a/src/com/android/camera/CaptureModuleUI.java
+++ b/src/com/android/camera/CaptureModuleUI.java
@@ -132,8 +132,7 @@
         mLayoutListener = layoutListener;
 
         ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
-        mActivity.getLayoutInflater().inflate(R.layout.capture_module,
-                moduleRoot, true);
+        mActivity.getLayoutInflater().inflate(R.layout.capture_module, moduleRoot, true);
 
         mPreviewView = (TextureView) mRootView.findViewById(R.id.preview_content);
 
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 4e0ebff..8ae9339 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -71,8 +71,8 @@
 import com.android.camera.util.GcamHelper;
 import com.android.camera.util.GservicesHelper;
 import com.android.camera.util.SessionStatsCollector;
+import com.android.camera.util.Size;
 import com.android.camera.util.UsageStatistics;
-import com.android.camera.widget.AspectRatioSelector;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgent;
 import com.android.ex.camera2.portability.CameraAgent.CameraAFCallback;
@@ -83,7 +83,6 @@
 import com.android.ex.camera2.portability.CameraCapabilities;
 import com.android.ex.camera2.portability.CameraDeviceInfo.Characteristics;
 import com.android.ex.camera2.portability.CameraSettings;
-import com.android.ex.camera2.portability.Size;
 import com.google.common.logging.eventprotos;
 
 import java.io.ByteArrayOutputStream;
@@ -295,17 +294,18 @@
         /**
          * Returns current aspect ratio that is being used to set as default.
          */
-        public AspectRatioSelector.AspectRatio getCurrentAspectRatio();
+        public Rational getCurrentAspectRatio();
 
         /**
          * Gets notified when user has made the aspect ratio selection.
          *
-         * @param newAspectRatio aspect ratio that user has selected
+         * @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(AspectRatioSelector.AspectRatio newAspectRatio,
+        public void onAspectRatioSelected(
+                Rational chosenAspectRatio,
                 Runnable dialogHandlingFinishedRunnable);
     }
 
@@ -529,81 +529,33 @@
     }
 
     private AspectRatioDialogCallback createAspectRatioDialogCallback() {
-        Size currentSize = mCameraSettings.getCurrentPhotoSize();
-        float aspectRatio = (float) currentSize.width() / (float) currentSize.height();
-        if (aspectRatio < 1f) {
-            aspectRatio = 1 / aspectRatio;
-        }
-        final AspectRatioSelector.AspectRatio currentAspectRatio;
-        if (Math.abs(aspectRatio - 4f / 3f) <= 0.1f) {
-            currentAspectRatio = AspectRatioSelector.AspectRatio.ASPECT_RATIO_4x3;
-        } else if (Math.abs(aspectRatio - 16f / 9f) <= 0.1f) {
-            currentAspectRatio = AspectRatioSelector.AspectRatio.ASPECT_RATIO_16x9;
-        } else {
-            // TODO: Log error and not show dialog.
-            return null;
-        }
-
-        List<Size> sizes = mCameraCapabilities.getSupportedPhotoSizes();
-        List<Size> pictureSizes = ResolutionUtil
-                .getDisplayableSizesFromSupported(sizes, true);
-
-        // This logic below finds the largest resolution for each aspect ratio.
-        // TODO: Move this somewhere that can be shared with SettingsActivity
-        int aspectRatio4x3Resolution = 0;
-        int aspectRatio16x9Resolution = 0;
-        Size largestSize4x3 = new Size(0, 0);
-        Size largestSize16x9 = new Size(0, 0);
-        for (Size size : pictureSizes) {
-            float pictureAspectRatio = (float) size.width() / (float) size.height();
-            pictureAspectRatio = pictureAspectRatio < 1 ?
-                    1f / pictureAspectRatio : pictureAspectRatio;
-            int resolution = size.width() * size.height();
-            if (Math.abs(pictureAspectRatio - 4f / 3f) < 0.1f) {
-                if (resolution > aspectRatio4x3Resolution) {
-                    aspectRatio4x3Resolution = resolution;
-                    largestSize4x3 = size;
-                }
-            } else if (Math.abs(pictureAspectRatio - 16f / 9f) < 0.1f) {
-                if (resolution > aspectRatio16x9Resolution) {
-                    aspectRatio16x9Resolution = resolution;
-                    largestSize16x9 = size;
-                }
-            }
-        }
-
-        // Use the largest 4x3 and 16x9 sizes as candidates for picture size selection.
-        final Size size4x3ToSelect = largestSize4x3;
-        final Size size16x9ToSelect = largestSize16x9;
-
+        Size currentSize = new Size(mCameraSettings.getCurrentPhotoSize());
+        final Rational currentAspectRatio = ResolutionUtil.getAspectRatio(currentSize);
         AspectRatioDialogCallback callback = new AspectRatioDialogCallback() {
-
             @Override
-            public AspectRatioSelector.AspectRatio getCurrentAspectRatio() {
+            public Rational getCurrentAspectRatio() {
                 return currentAspectRatio;
             }
 
             @Override
-            public void onAspectRatioSelected(AspectRatioSelector.AspectRatio newAspectRatio,
-                    Runnable dialogHandlingFinishedRunnable) {
-                if (newAspectRatio == AspectRatioSelector.AspectRatio.ASPECT_RATIO_4x3) {
-                    String largestSize4x3Text = SettingsUtil.sizeToSetting(size4x3ToSelect);
-                    mActivity.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
-                                                       Keys.KEY_PICTURE_SIZE_BACK,
-                                                       largestSize4x3Text);
-                } else if (newAspectRatio == AspectRatioSelector.AspectRatio.ASPECT_RATIO_16x9) {
-                    String largestSize16x9Text = SettingsUtil.sizeToSetting(size16x9ToSelect);
-                    mActivity.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
-                                                       Keys.KEY_PICTURE_SIZE_BACK,
-                                                       largestSize16x9Text);
-                }
-                mActivity.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
-                                                   Keys.KEY_USER_SELECTED_ASPECT_RATIO, true);
+            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 (newAspectRatio != currentAspectRatio) {
+                if (chosenAspectRatio != currentAspectRatio) {
                     Log.i(TAG, "changing aspect ratio from dialog");
                     stopPreview();
                     startPreview();
@@ -1113,8 +1065,7 @@
                     width = exifWidth;
                     height = exifHeight;
                 } else {
-                    Size s;
-                    s = mCameraSettings.getCurrentPhotoSize();
+                    Size s = new Size(mCameraSettings.getCurrentPhotoSize());
                     if ((mJpegRotation + orientation) % 180 == 0) {
                         width = s.width();
                         height = s.height();
@@ -2125,7 +2076,8 @@
         String pictureSize = settingsManager.getString(SettingsManager.SCOPE_GLOBAL,
                                                        pictureSizeKey);
 
-        List<Size> supported = mCameraCapabilities.getSupportedPhotoSizes();
+        List<com.android.camera.util.Size> supported =
+                com.android.camera.util.Size.convert(mCameraCapabilities.getSupportedPhotoSizes());
         CameraPictureSizesCacher.updateSizesForCamera(mAppController.getAndroidContext(),
                 mCameraDevice.getCameraId(), supported);
         SettingsUtil.setCameraPictureSize(pictureSize, supported, mCameraSettings,
@@ -2143,13 +2095,13 @@
 
         // Set a preview size that is closest to the viewfinder height and has
         // the right aspect ratio.
-        List<Size> sizes = mCameraCapabilities.getSupportedPreviewSizes();
+        List<Size> sizes = Size.convert(mCameraCapabilities.getSupportedPreviewSizes());
         Size optimalSize = CameraUtil.getOptimalPreviewSize(mActivity, sizes,
                 (double) size.width() / size.height());
-        Size original = mCameraSettings.getCurrentPreviewSize();
+        Size original = new Size(mCameraSettings.getCurrentPreviewSize());
         if (!optimalSize.equals(original)) {
             Log.v(TAG, "setting preview size. optimal: " + optimalSize + "original: " + original);
-            mCameraSettings.setPreviewSize(optimalSize);
+            mCameraSettings.setPreviewSize(optimalSize.toPortabilitySize());
 
             mCameraDevice.applySettings(mCameraSettings);
             mCameraSettings = mCameraDevice.getSettings();
@@ -2186,7 +2138,6 @@
             // If exposure compensation is not enabled, reset the exposure compensation value.
             setExposureCompensation(0);
         }
-
     }
 
     private void updateParametersSceneMode() {
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index 6e59bf9..72ab4a3 100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
@@ -33,6 +33,7 @@
 
 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;
@@ -42,7 +43,6 @@
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.GservicesHelper;
 import com.android.camera.widget.AspectRatioDialogLayout;
-import com.android.camera.widget.AspectRatioSelector;
 import com.android.camera.widget.LocationDialogLayout;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgent;
@@ -361,12 +361,11 @@
             final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) {
         setDialog(new Dialog(mActivity,
                 android.R.style.Theme_Black_NoTitleBar_Fullscreen));
-        final LocationDialogLayout locationDialogLayout = (LocationDialogLayout) mActivity
-                .getLayoutInflater().inflate(R.layout.location_dialog_layout, null);
-        locationDialogLayout.setLocationTaggingSelectionListener(
-                new LocationDialogLayout.LocationTaggingSelectionListener() {
+        final LocationDialogLayout locationDialogLayout = new LocationDialogLayout(
+                mActivity, true);
+        locationDialogLayout.setListener(new LocationDialogLayout.LocationDialogListener() {
             @Override
-            public void onLocationTaggingSelected(boolean selected) {
+            public void onConfirm(boolean selected) {
                 // Update setting.
                 locationCallback.onLocationTaggingSelected(selected);
 
@@ -423,15 +422,13 @@
             Log.e(TAG, "Dialog for aspect ratio is null.");
             return false;
         }
-        final AspectRatioDialogLayout aspectRatioDialogLayout =
-                (AspectRatioDialogLayout) mActivity
-                .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
-        aspectRatioDialogLayout.initialize(
-                new AspectRatioDialogLayout.AspectRatioChangedListener() {
+        final AspectRatioDialogLayout aspectRatioDialogLayout = new AspectRatioDialogLayout(
+                mActivity, callback.getCurrentAspectRatio());
+        aspectRatioDialogLayout.setListener(
+                new AspectRatioDialogLayout.AspectRatioDialogListener() {
                     @Override
-                    public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
-                        // callback to set picture size.
-                        callback.onAspectRatioSelected(aspectRatio, new Runnable() {
+                    public void onConfirm(Rational chosenAspectRatio) {
+                        callback.onAspectRatioSelected(chosenAspectRatio, new Runnable() {
                             @Override
                             public void run() {
                                 if (mDialog != null) {
@@ -440,7 +437,7 @@
                             }
                         });
                     }
-                }, callback.getCurrentAspectRatio());
+                });
         aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
         aspectRatioDialog.show();
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 5c30a8c..f0a15d8 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -67,6 +67,7 @@
 import com.android.camera.util.ApiHelper;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.UsageStatistics;
+import com.android.camera.util.Size;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgent;
 import com.android.ex.camera2.portability.CameraAgent.CameraPictureCallback;
@@ -74,7 +75,6 @@
 import com.android.ex.camera2.portability.CameraCapabilities;
 import com.android.ex.camera2.portability.CameraDeviceInfo.Characteristics;
 import com.android.ex.camera2.portability.CameraSettings;
-import com.android.ex.camera2.portability.Size;
 import com.google.common.logging.eventprotos;
 
 import java.io.File;
@@ -801,8 +801,8 @@
 
         final int previewScreenShortSide = (previewScreenSize.x < previewScreenSize.y ?
                 previewScreenSize.x : previewScreenSize.y);
-        List<Size> sizes = capabilities.getSupportedPreviewSizes();
-        Size preferred = capabilities.getPreferredPreviewSizeForVideo();
+        List<Size> sizes = Size.convert(capabilities.getSupportedPreviewSizes());
+        Size preferred = new Size(capabilities.getPreferredPreviewSizeForVideo());
         final int preferredPreviewSizeShortSide = (preferred.width() < preferred.height() ?
                 preferred.width() : preferred.height());
         if (preferredPreviewSizeShortSide * 2 < previewScreenShortSide) {
@@ -1612,7 +1612,8 @@
         // Update Desired Preview size in case video camera resolution has changed.
         updateDesiredPreviewSize();
 
-        mCameraSettings.setPreviewSize(new Size(mDesiredPreviewWidth, mDesiredPreviewHeight));
+        Size previewSize = new Size(mDesiredPreviewWidth, mDesiredPreviewHeight);
+        mCameraSettings.setPreviewSize(previewSize.toPortabilitySize());
         // This is required for Samsung SGH-I337 and probably other Samsung S4 versions
         if (Build.BRAND.toLowerCase().contains("samsung")) {
             mCameraSettings.setSetting("video-size",
@@ -1644,12 +1645,12 @@
         // The logic here is different from the logic in still-mode camera.
         // There we determine the preview size based on the picture size, but
         // here we determine the picture size based on the preview size.
-        List<Size> supported = mCameraCapabilities.getSupportedPhotoSizes();
+        List<Size> supported = Size.convert(mCameraCapabilities.getSupportedPhotoSizes());
         Size optimalSize = CameraUtil.getOptimalVideoSnapshotPictureSize(supported,
                 mDesiredPreviewWidth, mDesiredPreviewHeight);
         Size original = new Size(mCameraSettings.getCurrentPhotoSize());
         if (!original.equals(optimalSize)) {
-            mCameraSettings.setPhotoSize(optimalSize);
+            mCameraSettings.setPhotoSize(optimalSize.toPortabilitySize());
         }
         Log.d(TAG, "Video snapshot size is " + optimalSize);
 
diff --git a/src/com/android/camera/app/AppController.java b/src/com/android/camera/app/AppController.java
index f749806..1ec2332 100644
--- a/src/com/android/camera/app/AppController.java
+++ b/src/com/android/camera/app/AppController.java
@@ -17,6 +17,7 @@
 package com.android.camera.app;
 
 import android.app.Activity;
+import android.app.Dialog;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -71,6 +72,13 @@
     public Context getAndroidContext();
 
     /**
+     * Creates a new dialog which can be shown in the app.
+     *
+     * @return  {@link android.app.Dialog} of the app.
+     */
+    public Dialog createDialog();
+
+    /**
      * @return the current camera id.
      */
     public int getCurrentCameraId();
diff --git a/src/com/android/camera/app/FirstRunDialog.java b/src/com/android/camera/app/FirstRunDialog.java
new file mode 100644
index 0000000..8011e6f
--- /dev/null
+++ b/src/com/android/camera/app/FirstRunDialog.java
@@ -0,0 +1,284 @@
+/*
+ * 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.app;
+
+import android.app.Dialog;
+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.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);
+    }
+
+    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;
+
+    /** The app controller. */
+    private final AppController mAppController;
+
+    /** The camera manager used to query camera characteristics. */
+    private final OneCameraManager mCameraManager;
+
+    /** Aspect ratio preference dialog */
+    private Dialog mAspectRatioPreferenceDialog;
+
+    /** 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) {
+        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();
+    }
+
+    /**
+     * 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;
+        } 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();
+        }
+    }
+
+    /**
+     * Dismiss all shown dialogs.
+     */
+    public void dismiss() {
+        if (mAspectRatioPreferenceDialog != null) {
+            mAspectRatioPreferenceDialog.dismiss();
+        }
+        if (mLocationPreferenceDialog != null) {
+            mLocationPreferenceDialog.dismiss();
+        }
+    }
+
+    /**
+     * Whether a aspect ratio dialog should be presented to the user.
+     *
+     * @return Whether a aspect ratio dialog should be presented to the user.
+     */
+    private boolean shouldShowAspectRatioPreferenceDialog() {
+        final SettingsManager settingsManager = mAppController.getSettingsManager();
+        final boolean isAspectRatioPreferenceSet = settingsManager.getBoolean(
+                SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO);
+        return ApiHelper.shouldShowAspectRatioDialog() && !isAspectRatioPreferenceSet;
+    }
+
+    /**
+     * 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;
+        }
+
+        // Create a content view for the dialog.
+        final AspectRatioDialogLayout dialogLayout = new AspectRatioDialogLayout(
+                mAppController.getAndroidContext(), DEFAULT_ASPECT_RATIO);
+        dialogLayout.setListener(new AspectRatioDialogLayout.AspectRatioDialogListener() {
+            @Override
+            public void onConfirm(Rational aspectRatio) {
+                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);
+                } catch (OneCameraAccessException ex) {
+                    throw new RuntimeException(ex);
+                }
+
+                mListener.onAspectRatioPreferenceConfirmed(aspectRatio);
+            }
+        });
+
+        // Create the dialog.
+        mAspectRatioPreferenceDialog = mAppController.createDialog();
+        mAspectRatioPreferenceDialog.setContentView(dialogLayout, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        mAspectRatioPreferenceDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                mAspectRatioPreferenceDialog = null;
+            }
+        });
+
+        // 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;
+        }
+
+        // Create a content view for the dialog.
+        final LocationDialogLayout dialogLayout = new LocationDialogLayout(
+                mAppController.getAndroidContext(), DEFAULT_LOCATION_RECORDING_ENABLED);
+        dialogLayout.setListener(new LocationDialogLayout.LocationDialogListener() {
+            @Override
+            public void onConfirm(boolean locationRecordingEnabled) {
+                mAppController.getSettingsManager().set(
+                        SettingsManager.SCOPE_GLOBAL,
+                        Keys.KEY_RECORD_LOCATION,
+                        locationRecordingEnabled);
+                mAppController.getLocationManager().recordLocation(
+                        locationRecordingEnabled);
+
+                mListener.onLocationPreferenceConfirmed(locationRecordingEnabled);
+
+                promptAspectRatioPreferenceDialog();
+            }
+        });
+
+        // Create the dialog.
+        mLocationPreferenceDialog = mAppController.createDialog();
+        mLocationPreferenceDialog.setContentView(dialogLayout, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        mLocationPreferenceDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                mLocationPreferenceDialog = null;
+            }
+        });
+
+        // Show the dialog.
+        mLocationPreferenceDialog.show();
+        return true;
+    }
+}
diff --git a/src/com/android/camera/exif/Rational.java b/src/com/android/camera/exif/Rational.java
index 96b5312..cf73e2b 100644
--- a/src/com/android/camera/exif/Rational.java
+++ b/src/com/android/camera/exif/Rational.java
@@ -16,6 +16,7 @@
 
 package com.android.camera.exif;
 
+// TODO: Move this class to under util package.
 /**
  * The rational data type of EXIF tag. Contains a pair of longs representing the
  * numerator and denominator of a Rational number.
@@ -28,11 +29,11 @@
     /**
      * Create a Rational with a given numerator and denominator.
      *
-     * @param nominator
+     * @param numerator
      * @param denominator
      */
-    public Rational(long nominator, long denominator) {
-        mNumerator = nominator;
+    public Rational(long numerator, long denominator) {
+        mNumerator = numerator;
         mDenominator = denominator;
     }
 
diff --git a/src/com/android/camera/one/OneCameraAccessException.java b/src/com/android/camera/one/OneCameraAccessException.java
new file mode 100644
index 0000000..d0181c5
--- /dev/null
+++ b/src/com/android/camera/one/OneCameraAccessException.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+public class OneCameraAccessException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public OneCameraAccessException(String message) {
+        super(message);
+    }
+
+    public OneCameraAccessException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/com/android/camera/one/OneCameraCharacteristics.java b/src/com/android/camera/one/OneCameraCharacteristics.java
new file mode 100644
index 0000000..9e806b8
--- /dev/null
+++ b/src/com/android/camera/one/OneCameraCharacteristics.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import com.android.camera.util.Size;
+
+import java.util.List;
+
+/**
+ * The properties describing a OneCamera device. These properties are fixed for
+ * a given OneCamera device.
+ *
+ * TODO: Complete this interface to expose all camera
+ * properties.
+ */
+public interface OneCameraCharacteristics {
+    /**
+     * Gets the supported picture sizes for the given image format.
+     *
+     * @param imageFormat The specific image format listed on
+     *                    {@link ImageFormat}.
+     */
+    public List<Size> getSupportedPictureSizes(int imageFormat);
+}
diff --git a/src/com/android/camera/one/OneCameraManager.java b/src/com/android/camera/one/OneCameraManager.java
index cb6d142..dde1ca2 100644
--- a/src/com/android/camera/one/OneCameraManager.java
+++ b/src/com/android/camera/one/OneCameraManager.java
@@ -58,12 +58,25 @@
     public abstract void open(Facing facing, boolean enableHdr, Size captureSize,
             OpenCallback callback, Handler handler);
 
+    // TODO: Move this to OneCameraCharacteristics class.
     /**
      * Returns whether the device has a camera facing the given direction.
      */
     public abstract boolean hasCameraFacing(Facing facing);
 
     /**
+     * Retrieve the characteristics for the camera facing at the given direction. The first camera
+     * found in the given direction will be chosen.
+     *
+     * @param facing The facing direction of the camera.
+     * @return A #{link com.android.camera.one.OneCameraCharacteristics} object to provide camera
+     *         characteristics information. Returns null if there is no camera facing the given
+     *         direction.
+     */
+    public abstract OneCameraCharacteristics getCameraCharacteristics(Facing facing)
+            throws OneCameraAccessException;
+
+    /**
      * Creates a camera manager that is based on Camera2 API, if available, or
      * otherwise uses the portability layer API.
      *
diff --git a/src/com/android/camera/one/v1/OneCameraManagerImpl.java b/src/com/android/camera/one/v1/OneCameraManagerImpl.java
index 839ca5a..3967739 100644
--- a/src/com/android/camera/one/v1/OneCameraManagerImpl.java
+++ b/src/com/android/camera/one/v1/OneCameraManagerImpl.java
@@ -20,6 +20,7 @@
 
 import com.android.camera.one.OneCamera.Facing;
 import com.android.camera.one.OneCamera.OpenCallback;
+import com.android.camera.one.OneCameraCharacteristics;
 import com.android.camera.one.OneCameraManager;
 import com.android.camera.util.Size;
 
@@ -38,4 +39,9 @@
     public boolean hasCameraFacing(Facing facing) {
         throw new RuntimeException("Not implemented yet.");
     }
-}
+
+    @Override
+    public OneCameraCharacteristics getCameraCharacteristics(Facing facing) {
+        throw new RuntimeException("Not implemented yet.");
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/camera/one/v2/OneCameraCharacteristicsImpl.java b/src/com/android/camera/one/v2/OneCameraCharacteristicsImpl.java
new file mode 100644
index 0000000..77278e5
--- /dev/null
+++ b/src/com/android/camera/one/v2/OneCameraCharacteristicsImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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.v2;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.params.StreamConfigurationMap;
+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 camera2 API. This is essential a wrapper
+ * for #{link android.hardware.camera2.CameraCharacteristics}.
+ */
+public class OneCameraCharacteristicsImpl implements OneCameraCharacteristics {
+    private final CameraCharacteristics mCameraCharacteristics;
+
+    public OneCameraCharacteristicsImpl(CameraCharacteristics cameraCharacteristics) {
+        mCameraCharacteristics = cameraCharacteristics;
+    }
+
+    @Override
+    public List<Size> getSupportedPictureSizes(int imageFormat) {
+        StreamConfigurationMap configMap =
+                mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+        ArrayList<Size> supportedPictureSizes = new ArrayList<>();
+        for (android.util.Size androidSize : configMap.getOutputSizes(imageFormat)) {
+            supportedPictureSizes.add(new Size(androidSize));
+        }
+        return supportedPictureSizes;
+    }
+}
diff --git a/src/com/android/camera/one/v2/OneCameraManagerImpl.java b/src/com/android/camera/one/v2/OneCameraManagerImpl.java
index 249e4ec..584cb4e 100644
--- a/src/com/android/camera/one/v2/OneCameraManagerImpl.java
+++ b/src/com/android/camera/one/v2/OneCameraManagerImpl.java
@@ -30,6 +30,8 @@
 import com.android.camera.one.OneCamera;
 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.util.Size;
 
@@ -147,6 +149,18 @@
                 : CameraCharacteristics.LENS_FACING_BACK) != null;
     }
 
+    @Override
+    public OneCameraCharacteristics getCameraCharacteristics(Facing facing)
+            throws OneCameraAccessException {
+        String cameraId = getCameraId(facing);
+        try {
+            CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
+            return new OneCameraCharacteristicsImpl(characteristics);
+        } catch (CameraAccessException ex) {
+            throw new OneCameraAccessException("Unable to get camera characteristics", ex);
+        }
+    }
+
     /** Returns the ID of the first camera facing the given direction. */
     private String getCameraId(Facing facing) {
         if (facing == Facing.FRONT) {
diff --git a/src/com/android/camera/settings/AppUpgrader.java b/src/com/android/camera/settings/AppUpgrader.java
index 9ff3dfa..b1c6336 100644
--- a/src/com/android/camera/settings/AppUpgrader.java
+++ b/src/com/android/camera/settings/AppUpgrader.java
@@ -24,10 +24,10 @@
 import com.android.camera.app.ModuleManagerImpl;
 import com.android.camera.debug.Log;
 import com.android.camera.module.ModuleController;
+import com.android.camera.util.Size;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgentFactory;
 import com.android.ex.camera2.portability.CameraDeviceInfo;
-import com.android.ex.camera2.portability.Size;
 
 import java.util.List;
 import java.util.Map;
@@ -326,7 +326,7 @@
             if (supported != null) {
                 Size size = SettingsUtil.getPhotoSize(pictureSize, supported, camera);
                 settingsManager.set(SettingsManager.SCOPE_GLOBAL, key,
-                        SettingsUtil.sizeToSetting(size));
+                        SettingsUtil.sizeToSettingString(size));
             }
         }
     }
diff --git a/src/com/android/camera/settings/CameraPictureSizesCacher.java b/src/com/android/camera/settings/CameraPictureSizesCacher.java
index 6f0c86e..689cd9c 100644
--- a/src/com/android/camera/settings/CameraPictureSizesCacher.java
+++ b/src/com/android/camera/settings/CameraPictureSizesCacher.java
@@ -22,7 +22,7 @@
 import android.os.Build;
 import android.preference.PreferenceManager;
 
-import com.android.ex.camera2.portability.Size;
+import com.android.camera.util.Size;
 
 import java.util.List;
 
diff --git a/src/com/android/camera/settings/CameraSettingsActivity.java b/src/com/android/camera/settings/CameraSettingsActivity.java
index 82b54cd..1791051 100644
--- a/src/com/android/camera/settings/CameraSettingsActivity.java
+++ b/src/com/android/camera/settings/CameraSettingsActivity.java
@@ -37,10 +37,10 @@
 import com.android.camera.settings.SettingsUtil.SelectedVideoQualities;
 import com.android.camera.util.CameraSettingsActivityHelper;
 import com.android.camera.util.GoogleHelpHelper;
+import com.android.camera.util.Size;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraAgentFactory;
 import com.android.ex.camera2.portability.CameraDeviceInfo;
-import com.android.ex.camera2.portability.Size;
 
 import java.text.DecimalFormat;
 import java.util.ArrayList;
@@ -352,7 +352,7 @@
             for (int i = 0; i < selectedSizes.size(); i++) {
                 Size size = selectedSizes.get(i);
                 entries[i] = getSizeSummaryString(size);
-                entryValues[i] = SettingsUtil.sizeToSetting(size);
+                entryValues[i] = SettingsUtil.sizeToSettingString(size);
             }
             preference.setEntries(entries);
             preference.setEntryValues(entryValues);
diff --git a/src/com/android/camera/settings/ResolutionUtil.java b/src/com/android/camera/settings/ResolutionUtil.java
index 8f6c929..40ee4ee 100644
--- a/src/com/android/camera/settings/ResolutionUtil.java
+++ b/src/com/android/camera/settings/ResolutionUtil.java
@@ -16,8 +16,9 @@
 
 package com.android.camera.settings;
 
+import com.android.camera.exif.Rational;
 import com.android.camera.util.ApiHelper;
-import com.android.ex.camera2.portability.Size;
+import com.android.camera.util.Size;
 
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -36,6 +37,12 @@
  * user with so many options.
  */
 public class ResolutionUtil {
+    /**
+     * Different aspect ratio constants.
+     */
+    public static final Rational ASPECT_RATIO_16x9 = new Rational(16, 9);
+    public static final Rational ASPECT_RATIO_4x3 = new Rational(4, 3);
+    private static final double ASPECT_RATIO_TOLERANCE = 0.05;
 
     public static final String NEXUS_5_LARGE_16_BY_9 = "1836x3264";
     public static final float NEXUS_5_LARGE_16_BY_9_ASPECT_RATIO = 16f / 9f;
@@ -43,7 +50,7 @@
 
     /**
      * These are the preferred aspect ratios for the settings. We will take HAL
-     * supported aspect ratios that are within RATIO_TOLERANCE of these values.
+     * supported aspect ratios that are within ASPECT_RATIO_TOLERANCE of these values.
      * We will also take the maximum supported resolution for full sensor image.
      */
     private static Float[] sDesiredAspectRatios = {
@@ -54,8 +61,6 @@
             new Size(16, 9), new Size(4, 3)
     };
 
-    private static final float RATIO_TOLERANCE = .05f;
-
     /**
      * A resolution bucket holds a list of sizes that are of a given aspect
      * ratio.
@@ -131,7 +136,7 @@
         for (Float targetRatio : sortedDesiredAspectRatios) {
             for (ResolutionBucket bucket : buckets) {
                 Number aspectRatio = bucket.aspectRatio;
-                if (Math.abs(aspectRatio.floatValue() - targetRatio) <= RATIO_TOLERANCE) {
+                if (Math.abs(aspectRatio.floatValue() - targetRatio) <= ASPECT_RATIO_TOLERANCE) {
                     result.addAll(pickUpToThree(bucket.sizes));
                 }
             }
@@ -197,12 +202,12 @@
      * possible.
      *
      * @param aspectRatio the aspect ratio to fuzz
-     * @return the closest desiredAspectRatio within RATIO_TOLERANCE, or the
+     * @return the closest desiredAspectRatio within ASPECT_RATIO_TOLERANCE, or the
      *         original ratio
      */
     private static float fuzzAspectRatio(float aspectRatio) {
         for (float desiredAspectRatio : sDesiredAspectRatios) {
-            if ((Math.abs(aspectRatio - desiredAspectRatio)) < RATIO_TOLERANCE) {
+            if ((Math.abs(aspectRatio - desiredAspectRatio)) < ASPECT_RATIO_TOLERANCE) {
                 return desiredAspectRatio;
             }
         }
@@ -223,7 +228,7 @@
         HashMap<Float, ResolutionBucket> aspectRatioToBuckets = new HashMap<Float, ResolutionBucket>();
 
         for (Size size : sizes) {
-            Float aspectRatio = size.width() / (float) size.height();
+            Float aspectRatio = (float) size.getWidth() / (float) size.getHeight();
             // If this aspect ratio is close to a desired Aspect Ratio,
             // fuzz it so that they are bucketed together
             aspectRatio = fuzzAspectRatio(aspectRatio);
@@ -300,23 +305,12 @@
         float fuzzy = fuzzAspectRatio(size.width() / (float) size.height());
         int index = Arrays.asList(sDesiredAspectRatios).indexOf(fuzzy);
         if (index != -1) {
-            aspectRatio = new Size(sDesiredAspectRatioSizes[index]);
+            aspectRatio = sDesiredAspectRatioSizes[index];
         }
         return aspectRatio;
     }
 
     /**
-     * See {@link #getApproximateSize(Size)}.
-     * <p>
-     * TODO: Move this whole util to {@link android.util.Size}
-     */
-    public static com.android.camera.util.Size getApproximateSize(
-            com.android.camera.util.Size size) {
-        Size result = getApproximateSize(new Size(size.getWidth(), size.getHeight()));
-        return new com.android.camera.util.Size(result.width(), result.height());
-    }
-
-    /**
      * Given a size return the numerator of its aspect ratio
      *
      * @param size
@@ -330,4 +324,50 @@
         return denominator;
     }
 
+    /**
+     * Returns the aspect ratio for the given size.
+     *
+     * @param size The given size.
+     * @return A {@link Rational} which represents the aspect ratio.
+     */
+    public static Rational getAspectRatio(Size size) {
+        int width = size.getWidth();
+        int height = size.getHeight();
+        int numerator = width;
+        int denominator = height;
+        if (height > width) {
+            numerator = height;
+            denominator = width;
+        }
+        return new Rational(numerator, denominator);
+    }
+
+    public static boolean hasSameAspectRatio(Rational ar1, Rational ar2) {
+        return Math.abs(ar1.toDouble() - ar2.toDouble()) < ASPECT_RATIO_TOLERANCE;
+    }
+
+    /**
+     * Selects the maximal resolution for the given aspect ratio from all available resolutions.
+     *
+     * @param desiredAspectRatio The desired aspect ratio.
+     * @param sizes All available resolutions.
+     * @return The maximal resolution for 4x3 aspect ratio
+     */
+    public static Size getLargestPictureSize(Rational desiredAspectRatio, List<Size> sizes) {
+        int maxPixelNum = 0;
+        Size maxSize = new Size(0, 0);
+        for (Size size : sizes) {
+            Rational aspectRatio = getAspectRatio(size);
+            // Skip if the aspect ratio is not desired.
+            if (!hasSameAspectRatio(aspectRatio, desiredAspectRatio)) {
+                continue;
+            }
+            int pixelNum = size.getWidth() * size.getHeight();
+            if (pixelNum > maxPixelNum) {
+                maxPixelNum = pixelNum;
+                maxSize = size;
+            }
+        }
+        return maxSize;
+    }
 }
diff --git a/src/com/android/camera/settings/SettingsManager.java b/src/com/android/camera/settings/SettingsManager.java
index 6d90832..86b06ea 100644
--- a/src/com/android/camera/settings/SettingsManager.java
+++ b/src/com/android/camera/settings/SettingsManager.java
@@ -374,30 +374,6 @@
     }
 
     /**
-     * Retrieve a setting's value as a {@link Size}. Returns <code>null</code>
-     * if value could not be parsed as a size.
-     */
-    public Size getSize(String scope, String key) {
-        String strValue = getString(scope, key);
-        if (strValue == null) {
-            return null;
-        }
-
-        String[] widthHeight = strValue.split("x");
-        if (widthHeight.length != 2) {
-            return null;
-        }
-
-        try {
-            int width = Integer.parseInt(widthHeight[0]);
-            int height = Integer.parseInt(widthHeight[1]);
-            return new Size(width, height);
-        } catch (NumberFormatException ex) {
-            return null;
-        }
-    }
-
-    /**
      * If possible values are stored for this key, return the
      * index into that list of the currently set value.
      *
diff --git a/src/com/android/camera/settings/SettingsUtil.java b/src/com/android/camera/settings/SettingsUtil.java
index acf8921..732a834 100644
--- a/src/com/android/camera/settings/SettingsUtil.java
+++ b/src/com/android/camera/settings/SettingsUtil.java
@@ -26,10 +26,10 @@
 import com.android.camera.debug.Log;
 import com.android.camera.util.ApiHelper;
 import com.android.camera.util.Callback;
+import com.android.camera.util.Size;
 import com.android.camera2.R;
 import com.android.ex.camera2.portability.CameraDeviceInfo;
 import com.android.ex.camera2.portability.CameraSettings;
-import com.android.ex.camera2.portability.Size;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -79,7 +79,7 @@
             } else if (SIZE_SMALL.equals(sizeSetting)) {
                 return small;
             } else if (sizeSetting != null && sizeSetting.split("x").length == 2) {
-                Size desiredSize = sizeFromString(sizeSetting);
+                Size desiredSize = sizeFromSettingString(sizeSetting);
                 if (supportedSizes.contains(desiredSize)) {
                     return desiredSize;
                 }
@@ -162,9 +162,9 @@
     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.width() + "x" +
-                selectedSize.height());
-        settings.setPhotoSize(selectedSize);
+        Log.d(TAG, "Selected " + sizeSetting + " resolution: " + selectedSize.getWidth() + "x" +
+                selectedSize.getHeight());
+        settings.setPhotoSize(selectedSize.toPortabilitySize());
     }
 
     /**
@@ -404,27 +404,38 @@
         return closestMatchIndex;
     }
 
+    private static final String SIZE_SETTING_STRING_DIMENSION_DELIMITER = "x";
+
     /**
      * This is used to serialize a size to a string for storage in settings
      *
      * @param size The size to serialize.
      * @return the string to be saved in preferences
      */
-    public static String sizeToSetting(Size size) {
-        return ((Integer) size.width()).toString() + "x" + ((Integer) size.height()).toString();
+    public static String sizeToSettingString(Size size) {
+        return size.width() + SIZE_SETTING_STRING_DIMENSION_DELIMITER + size.height();
     }
 
     /**
      * This parses a setting string and returns the representative size.
      *
-     * @param sizeSetting The string to parse.
+     * @param sizeSettingString The string that stored in settings to represent a size.
      * @return the represented Size.
      */
-    static public Size sizeFromString(String sizeSetting) {
-        String[] parts = sizeSetting.split("x");
-        if (parts.length == 2) {
-            return new Size(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]));
-        } else {
+    static public Size sizeFromSettingString(String sizeSettingString) {
+        if (sizeSettingString == null) {
+            return null;
+        }
+        String[] parts = sizeSettingString.split(SIZE_SETTING_STRING_DIMENSION_DELIMITER);
+        if (parts.length != 2) {
+            return null;
+        }
+
+        try {
+            int width = Integer.parseInt(parts[0]);
+            int height = Integer.parseInt(parts[1]);
+            return new Size(width, height);
+        } catch (NumberFormatException ex) {
             return null;
         }
     }
diff --git a/src/com/android/camera/util/ApiHelper.java b/src/com/android/camera/util/ApiHelper.java
index 7e8a748..624cbf2 100644
--- a/src/com/android/camera/util/ApiHelper.java
+++ b/src/com/android/camera/util/ApiHelper.java
@@ -100,4 +100,8 @@
         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;
+    }
 }
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index aa8c525..71e15cb 100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
@@ -458,10 +458,9 @@
         return new Size(res);
     }
 
-    public static com.android.ex.camera2.portability.Size getOptimalPreviewSize(Context context,
-            List<com.android.ex.camera2.portability.Size> sizes, double targetRatio) {
-        int optimalPickIndex = getOptimalPreviewSizeIndex(context, Size.convert(sizes),
-                targetRatio);
+    public static Size getOptimalPreviewSize(
+            Context context, List<Size> sizes, double targetRatio) {
+        int optimalPickIndex = getOptimalPreviewSizeIndex(context, sizes, targetRatio);
         if (optimalPickIndex == -1) {
             return null;
         } else {
@@ -585,8 +584,8 @@
      * @param targetHeight the ideal height of the video snapshot
      * @return the Optimal Video Snapshot Picture Size
      */
-    public static com.android.ex.camera2.portability.Size getOptimalVideoSnapshotPictureSize(
-            List<com.android.ex.camera2.portability.Size> sizes, int targetWidth,
+    public static Size getOptimalVideoSnapshotPictureSize(
+            List<Size> sizes, int targetWidth,
             int targetHeight) {
 
         // Use a very small tolerance because we want an exact match.
@@ -595,12 +594,12 @@
             return null;
         }
 
-        com.android.ex.camera2.portability.Size optimalSize = null;
+        Size optimalSize = null;
 
         // WYSIWYG Override
         // We assume that physical display constraints have already been
         // imposed on the variables sizes
-        for (com.android.ex.camera2.portability.Size size : sizes) {
+        for (Size size : sizes) {
             if (size.height() == targetHeight && size.width() == targetWidth) {
                 return size;
             }
@@ -608,7 +607,7 @@
 
         // Try to find a size matches aspect ratio and has the largest width
         final double targetRatio = (double) targetWidth / targetHeight;
-        for (com.android.ex.camera2.portability.Size size : sizes) {
+        for (Size size : sizes) {
             double ratio = (double) size.width() / size.height();
             if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
                 continue;
@@ -622,7 +621,7 @@
         // happen. Ignore the requirement.
         if (optimalSize == null) {
             Log.w(TAG, "No picture size match the aspect ratio");
-            for (com.android.ex.camera2.portability.Size size : sizes) {
+            for (Size size : sizes) {
                 if (optimalSize == null || size.width() > optimalSize.width()) {
                     optimalSize = size;
                 }
diff --git a/src/com/android/camera/util/Size.java b/src/com/android/camera/util/Size.java
index 20ad187..61905a0 100644
--- a/src/com/android/camera/util/Size.java
+++ b/src/com/android/camera/util/Size.java
@@ -19,6 +19,8 @@
 import android.annotation.TargetApi;
 import android.graphics.Point;
 import android.os.Build.VERSION_CODES;
+import android.hardware.Camera;
+import android.text.TextUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,9 +29,75 @@
  * Simple size class until we are 'L' only and can use android.util.Size.
  */
 public class Size {
+    public static final String LIST_DELIMITER = ",";
+
     private final int width;
     private final int height;
 
+    public Size(Point point) {
+        this.width = point.x;
+        this.height = point.y;
+    }
+
+    @TargetApi(VERSION_CODES.L)
+    public Size(android.util.Size size) {
+        this.width = size.getWidth();
+        this.height = size.getHeight();
+    }
+
+    public Size(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    /**
+     * Constructor from a source {@link android.hardware.Camera.Size}.
+     *
+     * @param other The source size.
+     */
+    public Size(Camera.Size other) {
+        this.width = other.width;
+        this.height = other.height;
+    }
+
+    public Size(com.android.ex.camera2.portability.Size size) {
+        this.width = size.width();
+        this.height = size.height();
+    }
+
+    public int getWidth() {
+        return width;
+    }
+    public int getHeight() {
+        return height;
+    }
+
+    public int width() {
+        return width;
+    }
+    public int height() {
+        return height;
+    }
+
+    @Override
+    public String toString() {
+        return width + "x" + height;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof Size)) {
+            return false;
+        }
+
+        Size otherSize = (Size) other;
+        return otherSize.width == this.width && otherSize.height == this.height;
+    }
+
+    public com.android.ex.camera2.portability.Size toPortabilitySize() {
+        return new com.android.ex.camera2.portability.Size(width, height);
+    }
+
     @TargetApi(VERSION_CODES.L)
     public static Size[] convert(android.util.Size[] sizes) {
         Size[] converted = new Size[sizes.length];
@@ -47,42 +115,50 @@
         return converted;
     }
 
-    public Size(Point point) {
-        this.width = point.x;
-        this.height = point.y;
-    }
-
-    @TargetApi(VERSION_CODES.L)
-    public Size(android.util.Size size) {
-        this.width = size.getWidth();
-        this.height = size.getHeight();
-    }
-
-    public Size(int width, int height) {
-        this.width = width;
-        this.height = height;
-    }
-
-    public int getWidth() {
-        return width;
-    }
-
-    public int getHeight() {
-        return height;
-    }
-
-    @Override
-    public String toString() {
-        return width + " x " + height;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof Size)) {
-            return false;
+    /**
+     * Encode List of this class as comma-separated list of integers.
+     *
+     * @param sizes List of this class to encode.
+     * @return encoded string.
+     */
+    public static String listToString(List<Size> sizes) {
+        ArrayList<Integer> flatSizes = new ArrayList<>();
+        for (Size s : sizes) {
+            flatSizes.add(s.width());
+            flatSizes.add(s.height());
         }
+        return TextUtils.join(LIST_DELIMITER, flatSizes);
+    }
 
-        Size otherSize = (Size) other;
-        return otherSize.width == this.width && otherSize.height == this.height;
+    /**
+     * Decode comma-separated even-length list of integers into a List of this class.
+     *
+     * @param encodedSizes encoded string.
+     * @return List of this class.
+     */
+    public static List<Size> stringToList(String encodedSizes) {
+        String[] flatSizes = TextUtils.split(encodedSizes, LIST_DELIMITER);
+        ArrayList<Size> list = new ArrayList<>();
+        for (int i = 0; i < flatSizes.length; i += 2) {
+            int width = Integer.parseInt(flatSizes[i]);
+            int height = Integer.parseInt(flatSizes[i + 1]);
+            list.add(new Size(width, height));
+        }
+        return list;
+    }
+
+    /**
+     * An helper method to build a list of this class from a list of
+     * {@link android.hardware.Camera.Size}.
+     *
+     * @param cameraSizes Source.
+     * @return The built list.
+     */
+    public static List<Size> buildListFromCameraSizes(List<Camera.Size> cameraSizes) {
+        ArrayList<Size> list = new ArrayList<Size>(cameraSizes.size());
+        for (Camera.Size cameraSize : cameraSizes) {
+            list.add(new Size(cameraSize));
+        }
+        return list;
     }
 }
diff --git a/src/com/android/camera/widget/AspectRatioDialogLayout.java b/src/com/android/camera/widget/AspectRatioDialogLayout.java
index 972bf35..5f551bd 100644
--- a/src/com/android/camera/widget/AspectRatioDialogLayout.java
+++ b/src/com/android/camera/widget/AspectRatioDialogLayout.java
@@ -18,74 +18,107 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.camera.exif.Rational;
+import com.android.camera.settings.ResolutionUtil;
 import com.android.camera2.R;
 
+/**
+ * Displays a dialog that allows people to choose aspect ratio. Please
+ * instantiate this class programmatically.
+ */
 public class AspectRatioDialogLayout extends FrameLayout {
+
+    private AspectRatioDialogListener mListener;
+
+    private View mAspectRatio4x3Button;
+    private View mAspectRatio16x9Button;
     private View mConfirmButton;
-    private AspectRatioSelector mAspectRatioSelector;
+
+    private Rational mAspectRatio;
     private int mLastOrientation;
-    private AspectRatioChangedListener mListener;
-    private boolean mInitialized;
-    private AspectRatioSelector.AspectRatio mAspectRatio;
 
-    public interface AspectRatioChangedListener {
-        public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio);
+    /**
+     * Constructs a new AspectRatioDialogLayout object.
+     *
+     * @param context The application context.
+     * @param defaultAspectRatio The default aspect ratio to choose.
+     */
+    public AspectRatioDialogLayout(Context context, Rational defaultAspectRatio) {
+        super(context);
+        mAspectRatio = defaultAspectRatio;
+        mLastOrientation = context.getResources().getConfiguration().orientation;
+        setBackgroundResource(R.color.fullscreen_dialog_background_color);
+        inflate(context, R.layout.aspect_ratio_dialog_content, this);
+        updateSubviewReferences();
     }
 
-    public AspectRatioDialogLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mLastOrientation = getResources().getConfiguration().orientation;
-    }
-
-    @Override
-    public void onFinishInflate() {
-        updateViewReference();
-    }
-
-    private void updateViewReference() {
-        mAspectRatioSelector = (AspectRatioSelector) findViewById(R.id.aspect_ratio_selector);
-        mConfirmButton = findViewById(R.id.confirm_button);
-        mConfirmButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mListener != null) {
-                    mListener.onAspectRatioChanged(mAspectRatioSelector.getAspectRatio());
-                }
-            }
-        });
-        if (mInitialized) {
-            mAspectRatioSelector.setAspectRatio(mAspectRatio);
-        }
+    public void setListener(AspectRatioDialogListener listener) {
+        mListener = listener;
     }
 
     @Override
     public void onConfigurationChanged(Configuration config) {
         super.onConfigurationChanged(config);
+
         if (config.orientation == mLastOrientation) {
             return;
         }
         mLastOrientation = config.orientation;
-        mAspectRatio = mAspectRatioSelector.getAspectRatio();
+
         removeAllViews();
         inflate(getContext(), R.layout.aspect_ratio_dialog_content, this);
-        updateViewReference();
+        updateSubviewReferences();
     }
 
-    public void setAspectRatio(AspectRatioSelector.AspectRatio aspectRatio) {
-        mAspectRatioSelector.setAspectRatio(aspectRatio);
+    private void updateSubviewReferences() {
+        mAspectRatio4x3Button = findViewById(R.id.aspect_ratio_4x3_button);
+        mAspectRatio16x9Button = findViewById(R.id.aspect_ratio_16x9_button);
+        mConfirmButton = findViewById(R.id.confirm_button);
+
+        // Set aspect ratio after references to views are established.
+        setAspectRatio(mAspectRatio);
+
+        // Hook onclick events.
+        mAspectRatio4x3Button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                setAspectRatio(ResolutionUtil.ASPECT_RATIO_4x3);
+            }
+        });
+        mAspectRatio16x9Button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                setAspectRatio(ResolutionUtil.ASPECT_RATIO_16x9);
+            }
+        });
+        mConfirmButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mListener != null) {
+                    mListener.onConfirm(mAspectRatio);
+                }
+            }
+        });
     }
 
-    public void initialize(AspectRatioChangedListener listener,
-            AspectRatioSelector.AspectRatio aspectRatio) {
-        mInitialized = true;
-        mListener = listener;
+    private void setAspectRatio(Rational aspectRatio) {
         mAspectRatio = aspectRatio;
-        if (mAspectRatioSelector != null) {
-            mAspectRatioSelector.setAspectRatio(mAspectRatio);
+
+        if (mAspectRatio.equals(ResolutionUtil.ASPECT_RATIO_4x3)) {
+            // Select 4x3 view and unselect 16x9 view.
+            mAspectRatio4x3Button.setSelected(true);
+            mAspectRatio16x9Button.setSelected(false);
+        } else if (mAspectRatio.equals(ResolutionUtil.ASPECT_RATIO_16x9)) {
+            // Select 16x9 view and unselect 4x3 view.
+            mAspectRatio16x9Button.setSelected(true);
+            mAspectRatio4x3Button.setSelected(false);
         }
     }
+
+    public interface AspectRatioDialogListener {
+        public void onConfirm(Rational chosenAspectRatio);
+    }
 }
diff --git a/src/com/android/camera/widget/AspectRatioSelector.java b/src/com/android/camera/widget/AspectRatioSelector.java
deleted file mode 100644
index fbc550c..0000000
--- a/src/com/android/camera/widget/AspectRatioSelector.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.camera2.R;
-
-public class AspectRatioSelector extends LinearLayout {
-    public static enum AspectRatio {
-        ASPECT_RATIO_4x3,
-        ASPECT_RATIO_16x9
-    };
-
-    private AspectRatio mAspectRatio = AspectRatio.ASPECT_RATIO_4x3;
-    private View mAspectRatio4x3Button;
-    private View mAspectRatio16x9Button;
-
-    public AspectRatioSelector(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public void onFinishInflate() {
-        mAspectRatio4x3Button = findViewById(R.id.aspect_ratio_4x3_button);
-        mAspectRatio4x3Button.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setAspectRatio(AspectRatio.ASPECT_RATIO_4x3);
-            }
-        });
-        mAspectRatio16x9Button = findViewById(R.id.aspect_ratio_16x9_button);
-        mAspectRatio16x9Button.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setAspectRatio(AspectRatio.ASPECT_RATIO_16x9);
-            }
-        });
-    }
-
-    public void setAspectRatio(AspectRatio aspectRatio) {
-        if (aspectRatio == AspectRatio.ASPECT_RATIO_4x3) {
-            // Select 4x3 view.
-            mAspectRatio4x3Button.setSelected(true);
-            // Unselect 16x9 view.
-            mAspectRatio16x9Button.setSelected(false);
-        } else if (aspectRatio == AspectRatio.ASPECT_RATIO_16x9) {
-            // Select 16x9 view.
-            mAspectRatio16x9Button.setSelected(true);
-            // Unselect 4x3 view.
-            mAspectRatio4x3Button.setSelected(false);
-        } else {
-            // Log error.
-            return;
-        }
-        mAspectRatio = aspectRatio;
-    }
-
-    public AspectRatio getAspectRatio() {
-        return mAspectRatio;
-    }
-}
diff --git a/src/com/android/camera/widget/LocationDialogLayout.java b/src/com/android/camera/widget/LocationDialogLayout.java
index 5c6351b..94b829c 100644
--- a/src/com/android/camera/widget/LocationDialogLayout.java
+++ b/src/com/android/camera/widget/LocationDialogLayout.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.util.AttributeSet;
 import android.view.View;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
@@ -26,49 +25,62 @@
 
 import com.android.camera2.R;
 
+/**
+ * Displays a dialog that allows people to choose whether they like to enable
+ * location recording or not. Please instantiate this class programmatically.
+ */
 public class LocationDialogLayout extends FrameLayout {
 
-    public interface LocationTaggingSelectionListener {
-        public void onLocationTaggingSelected(boolean selected);
+    public interface LocationDialogListener {
+        public void onConfirm(boolean locationRecordingEnabled);
     }
 
-    private View mConfirmButton;
+    private LocationDialogListener mListener;
     private CheckBox mCheckBox;
+    private View mConfirmButton;
     private int mLastOrientation;
-    private LocationTaggingSelectionListener mListener;
-    private boolean mCheckBoxChecked = true;
+    private boolean mLocationRecordingEnabled;
 
-    public LocationDialogLayout(Context context, AttributeSet attributeSet) {
-        super(context, attributeSet);
+    /**
+     * Constructs a new LocationDialogLayout object.
+     *
+     * @param context The application context.
+     * @param defaultLocationRecordingEnabled Whether to enable location
+     *            recording by default.
+     */
+    public LocationDialogLayout(Context context, boolean defaultLocationRecordingEnabled) {
+        super(context);
+        mLocationRecordingEnabled = defaultLocationRecordingEnabled;
         mLastOrientation = context.getResources().getConfiguration().orientation;
+        setBackgroundResource(R.color.fullscreen_dialog_background_color);
+        inflate(context, R.layout.location_dialog_content, this);
+        updateSubviewReferences();
     }
 
-    @Override
-    public void onFinishInflate() {
-        updateViewReference();
+    public void setListener(LocationDialogListener listener) {
+        mListener = listener;
     }
 
     @Override
     public void onConfigurationChanged(Configuration config) {
         super.onConfigurationChanged(config);
-        // TODO: Extract the orientation checking logic in a super class as it
-        // is also used in the aspect ratio dialog.
         if (config.orientation == mLastOrientation) {
             return;
         }
         mLastOrientation = config.orientation;
+
         removeAllViews();
         inflate(getContext(), R.layout.location_dialog_content, this);
-        updateViewReference();
+        updateSubviewReferences();
     }
 
-    private void updateViewReference() {
+    private void updateSubviewReferences() {
         mCheckBox = (CheckBox) findViewById(R.id.check_box);
-        mCheckBox.setChecked(mCheckBoxChecked);
+        mCheckBox.setChecked(mLocationRecordingEnabled);
         mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mCheckBoxChecked = isChecked;
+                mLocationRecordingEnabled = isChecked;
             }
         });
 
@@ -77,14 +89,9 @@
             @Override
             public void onClick(View v) {
                 if (mListener != null) {
-                    mListener.onLocationTaggingSelected(mCheckBoxChecked);
+                    mListener.onConfirm(mLocationRecordingEnabled);
                 }
             }
         });
     }
-
-    public void setLocationTaggingSelectionListener(LocationTaggingSelectionListener listener) {
-        mListener = listener;
-    }
-
 }