diff options
18 files changed, 193 insertions, 47 deletions
diff --git a/res/drawable-hdpi/ic_discard_disabled.png b/res/drawable-hdpi/ic_discard_disabled.png Binary files differdeleted file mode 100644 index d6395d2ad..000000000 --- a/res/drawable-hdpi/ic_discard_disabled.png +++ /dev/null diff --git a/res/drawable-hdpi/ic_discard_normal.png b/res/drawable-hdpi/ic_discard_normal.png Binary files differdeleted file mode 100644 index 05ca6a799..000000000 --- a/res/drawable-hdpi/ic_discard_normal.png +++ /dev/null diff --git a/res/drawable-hdpi/ic_menu_trash_holo_light.png b/res/drawable-hdpi/ic_menu_trash_holo_light.png Binary files differdeleted file mode 100644 index 721ee5ca2..000000000 --- a/res/drawable-hdpi/ic_menu_trash_holo_light.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_discard_disabled.png b/res/drawable-mdpi/ic_discard_disabled.png Binary files differdeleted file mode 100644 index 8138c5d63..000000000 --- a/res/drawable-mdpi/ic_discard_disabled.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_discard_normal.png b/res/drawable-mdpi/ic_discard_normal.png Binary files differdeleted file mode 100644 index dcbf991aa..000000000 --- a/res/drawable-mdpi/ic_discard_normal.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_menu_trash_holo_light.png b/res/drawable-mdpi/ic_menu_trash_holo_light.png Binary files differdeleted file mode 100644 index f45540b21..000000000 --- a/res/drawable-mdpi/ic_menu_trash_holo_light.png +++ /dev/null diff --git a/res/drawable-xhdpi/ic_discard_disabled.png b/res/drawable-xhdpi/ic_discard_disabled.png Binary files differdeleted file mode 100644 index 37e2bae7a..000000000 --- a/res/drawable-xhdpi/ic_discard_disabled.png +++ /dev/null diff --git a/res/drawable-xhdpi/ic_discard_normal.png b/res/drawable-xhdpi/ic_discard_normal.png Binary files differdeleted file mode 100644 index 27e64f43a..000000000 --- a/res/drawable-xhdpi/ic_discard_normal.png +++ /dev/null diff --git a/res/drawable-xxhdpi/ic_discard_disabled.png b/res/drawable-xxhdpi/ic_discard_disabled.png Binary files differdeleted file mode 100644 index ccb90e52f..000000000 --- a/res/drawable-xxhdpi/ic_discard_disabled.png +++ /dev/null diff --git a/res/drawable-xxhdpi/ic_discard_normal.png b/res/drawable-xxhdpi/ic_discard_normal.png Binary files differdeleted file mode 100644 index 4e0d89d6a..000000000 --- a/res/drawable-xxhdpi/ic_discard_normal.png +++ /dev/null diff --git a/res/drawable/ic_menu_trash.xml b/res/drawable/ic_menu_trash.xml index 318ad41fe..cb94342fb 100644 --- a/res/drawable/ic_menu_trash.xml +++ b/res/drawable/ic_menu_trash.xml @@ -16,7 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" - android:drawable="@drawable/ic_discard_disabled" /> + android:drawable="@drawable/ic_trash_disabled" /> <item android:state_enabled="true" - android:drawable="@drawable/ic_discard_normal" /> + android:drawable="@drawable/ic_trash_normal" /> </selector> diff --git a/src/com/android/camera/one/OneCamera.java b/src/com/android/camera/one/OneCamera.java index 4e95f7fac..a22c889b2 100644 --- a/src/com/android/camera/one/OneCamera.java +++ b/src/com/android/camera/one/OneCamera.java @@ -265,11 +265,11 @@ public interface OneCamera { /** * Meters and triggers auto focus scan with ROI around tap point. * <p/> - * Normalized coordinates are referenced to portrait preview window with 0,0 - * top left and 1,1 bottom right. Rotation has no effect. + * Normalized coordinates are referenced to portrait preview window with + * (0, 0) top left and (1, 1) bottom right. Rotation has no effect. * * @param nx normalized x coordinate. - * @param nx normalized y coordinate. + * @param ny normalized y coordinate. */ public void triggerFocusAndMeterAtPoint(float nx, float ny); diff --git a/src/com/android/camera/one/Settings3A.java b/src/com/android/camera/one/Settings3A.java index 24edd28f9..a8abf69cc 100644 --- a/src/com/android/camera/one/Settings3A.java +++ b/src/com/android/camera/one/Settings3A.java @@ -23,24 +23,82 @@ package com.android.camera.one; public class Settings3A { /** - * Width of touch AF region relative to shortest edge at 1.0 zoom. - * Was 0.125 * longest edge prior to L release. + * Width of touch AF region in [0,1] relative to shorter edge of the current + * crop region. Multiply this number by the number of pixels along the + * shorter edge of the current crop region's width to get a value in pixels. + * + * <p> + * This value has been tested on Nexus 5 and Shamu, but will need to be + * tuned per device depending on how its ISP interprets the metering box and weight. + * </p> + * + * <p> + * Values prior to L release: + * Normal mode: 0.125 * longest edge + * Gcam: Fixed at 300px x 300px. + * </p> */ private static final float AF_REGION_BOX = 0.2f; /** - * Width of touch metering region relative to shortest edge at 1.0 zoom. - * Larger than {@link #AF_REGION_BOX} because exposure is sensitive and it is - * easy to over- or underexposure if area is too small. + * Width of touch metering region in [0,1] relative to shorter edge of the + * current crop region. Multiply this number by the number of pixels along + * shorter edge of the current crop region's width to get a value in pixels. + * + * <p> + * This value has been tested on Nexus 5 and Shamu, but will need to be + * tuned per device depending on how its ISP interprets the metering box and weight. + * </p> + * + * <p> + * Values prior to L release: + * Normal mode: 0.1875 * longest edge + * Gcam: Fixed at 300px x 300px. + * </p> */ private static final float AE_REGION_BOX = 0.3f; - /** Metering region weight between 0 and 1. */ - private static final float REGION_WEIGHT = 0.25f; + /** Metering region weight between 0 and 1. + * + * <p> + * This value has been tested on Nexus 5 and Shamu, but will need to be + * tuned per device depending on how its ISP interprets the metering box and weight. + * </p> + */ + private static final float REGION_WEIGHT = 0.022f; /** Duration to hold after manual tap to focus. */ private static final int FOCUS_HOLD_MILLIS = 3000; + /** + * Width of touch metering region in [0,1] relative to shorter edge of the + * current crop region. Multiply this number by the number of pixels along + * shorter edge of the current crop region's width to get a value in pixels. + * + * <p> + * This value has been tested on Nexus 5 and Shamu, but will need to be + * tuned per device depending on how its ISP interprets the metering box and weight. + * </p> + * + * <p> + * Was fixed at 300px x 300px prior to L release. + * </p> + */ + private static final float GCAM_METERING_REGION_FRACTION = 0.1225f; + + /** + * Weight of a touch metering region, in [0, \inf). + * + * <p> + * This value has been tested on Nexus 5 and Shamu, but will need to be + * tuned per device. + * </p> + * + * <p> + * Was fixed at 15.0f prior to L release. + * </p> + */ + private static final float GCAM_METERING_REGION_WEIGHT = 22.0f; public static float getAutoFocusRegionWidth() { return AF_REGION_BOX; @@ -54,6 +112,14 @@ public class Settings3A { return REGION_WEIGHT; } + public static float getGcamMeteringRegionFraction() { + return GCAM_METERING_REGION_FRACTION; + } + + public static float getGcamMeteringRegionWeight() { + return GCAM_METERING_REGION_WEIGHT; + } + public static int getFocusHoldMillis() { return FOCUS_HOLD_MILLIS; } diff --git a/src/com/android/camera/one/v2/AutoFocusHelper.java b/src/com/android/camera/one/v2/AutoFocusHelper.java index f0e7f8574..8cfab6806 100644 --- a/src/com/android/camera/one/v2/AutoFocusHelper.java +++ b/src/com/android/camera/one/v2/AutoFocusHelper.java @@ -16,6 +16,7 @@ package com.android.camera.one.v2; +import android.graphics.PointF; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureResult; @@ -24,6 +25,7 @@ import android.hardware.camera2.params.MeteringRectangle; import com.android.camera.debug.Log; import com.android.camera.one.OneCamera; import com.android.camera.one.Settings3A; +import com.android.camera.util.CameraUtil; /** * Helper class to implement auto focus and 3A in camera2-based @@ -34,8 +36,8 @@ public class AutoFocusHelper { /** camera2 API metering region weight. */ private static final int CAMERA2_REGION_WEIGHT = (int) - (((1 - Settings3A.getMeteringRegionWeight()) * MeteringRectangle.METERING_WEIGHT_MIN + - Settings3A.getMeteringRegionWeight() * MeteringRectangle.METERING_WEIGHT_MAX)); + (CameraUtil.lerp(MeteringRectangle.METERING_WEIGHT_MIN, MeteringRectangle.METERING_WEIGHT_MAX, + Settings3A.getMeteringRegionWeight())); /** Zero weight 3A region, to reset regions per API. */ private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{ @@ -110,35 +112,79 @@ public class AutoFocusHelper { )); } - /** Compute 3A regions for a sensor-referenced touch coordinate. */ - private static MeteringRectangle[] regionsForSensorCoord(int xc, int yc, float width, - Rect cropRegion) { - float minCropEdge = (float) Math.min(cropRegion.width(), cropRegion.height()); - int delta = (int) (0.5 * width * minCropEdge); - Rect region = new Rect(xc - delta, yc - delta, xc + delta, yc + delta); - // Make sure region is inside the sensor area. - if (!region.intersect(cropRegion)) { - region = cropRegion; - } - return new MeteringRectangle[]{new MeteringRectangle(region, CAMERA2_REGION_WEIGHT)}; + /** Compute 3A regions for a sensor-referenced touch coordinate. + * Returns a MeteringRectangle[] with length 1. + * + * @param nx x coordinate of the touch point, in normalized portrait coordinates. + * @param ny y coordinate of the touch point, in normalized portrait coordinates. + * @param fraction Fraction in [0,1]. Multiplied by min(cropRegion.width(), cropRegion.height()) + * to determine the side length of the square MeteringRectangle. + * @param cropRegion Crop region of the image. + * @param sensorOrientation sensor orientation as defined by + * CameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION). + * + * */ + private static MeteringRectangle[] regionsForNormalizedCoord(float nx, float ny, float fraction, + final Rect cropRegion, int sensorOrientation) { + // Compute half side length in pixels. + int minCropEdge = Math.min(cropRegion.width(), cropRegion.height()); + int halfSideLength = (int) (0.5f * fraction * minCropEdge); + + // Compute the output MeteringRectangle in sensor space. + // nx, ny is normalized to the screen. + // Crop region itself is specified in sensor coordinates. + + // Normalized coordinates, now rotated into sensor space. + PointF nsc = CameraUtil.normalizedSensorCoordsForNormalizedDisplayCoords( + nx, ny, sensorOrientation); + + int xCenterSensor = (int)(cropRegion.left + nsc.x * cropRegion.width()); + int yCenterSensor = (int)(cropRegion.top + nsc.y * cropRegion.height()); + + Rect meteringRegion = new Rect(xCenterSensor - halfSideLength, + yCenterSensor - halfSideLength, + xCenterSensor + halfSideLength, + yCenterSensor + halfSideLength); + + // Clamp meteringRegion to cropRegion. + meteringRegion.left = CameraUtil.clamp(meteringRegion.left, cropRegion.left, cropRegion.right); + meteringRegion.top = CameraUtil.clamp(meteringRegion.top, cropRegion.top, cropRegion.bottom); + meteringRegion.right = CameraUtil.clamp(meteringRegion.right, cropRegion.left, cropRegion.right); + meteringRegion.bottom = CameraUtil.clamp(meteringRegion.bottom, cropRegion.top, cropRegion.bottom); + + return new MeteringRectangle[]{new MeteringRectangle(meteringRegion, CAMERA2_REGION_WEIGHT)}; } /** * Return AF region(s) for a sensor-referenced touch coordinate. * + * <p> + * Normalized coordinates are referenced to portrait preview window with + * (0, 0) top left and (1, 1) bottom right. Rotation has no effect. + * </p> + * * @return AF region(s). */ - public static MeteringRectangle[] afRegionsForSensorCoord(int xc, int yc, Rect cropRegion) { - return regionsForSensorCoord(xc, yc, Settings3A.getAutoFocusRegionWidth(), cropRegion); + public static MeteringRectangle[] afRegionsForNormalizedCoord(float nx, + float ny, final Rect cropRegion, int sensorOrientation) { + return regionsForNormalizedCoord(nx, ny, Settings3A.getAutoFocusRegionWidth(), + cropRegion, sensorOrientation); } /** * Return AE region(s) for a sensor-referenced touch coordinate. * + * <p> + * Normalized coordinates are referenced to portrait preview window with + * (0, 0) top left and (1, 1) bottom right. Rotation has no effect. + * </p> + * * @return AE region(s). */ - public static MeteringRectangle[] aeRegionsForSensorCoord(int xc, int yc, Rect cropRegion) { - return regionsForSensorCoord(xc, yc, Settings3A.getMeteringRegionWidth(), cropRegion); + public static MeteringRectangle[] aeRegionsForNormalizedCoord(float nx, + float ny, final Rect cropRegion, int sensorOrientation) { + return regionsForNormalizedCoord(nx, ny, Settings3A.getMeteringRegionWidth(), + cropRegion, sensorOrientation); } /** diff --git a/src/com/android/camera/one/v2/OneCameraImpl.java b/src/com/android/camera/one/v2/OneCameraImpl.java index 258eaddeb..8f7dc443d 100644 --- a/src/com/android/camera/one/v2/OneCameraImpl.java +++ b/src/com/android/camera/one/v2/OneCameraImpl.java @@ -622,12 +622,10 @@ public class OneCameraImpl extends AbstractOneCamera { @Override public void triggerFocusAndMeterAtPoint(float nx, float ny) { - // xc, yc is center of tap point in sensor coordinate system. - int xc = mCropRegion.left + (int) (mCropRegion.width() * ny); - int yc = mCropRegion.top + (int) (mCropRegion.height() * (1f - nx)); - - mAERegions = AutoFocusHelper.aeRegionsForSensorCoord(xc, yc, mCropRegion); - mAFRegions = AutoFocusHelper.afRegionsForSensorCoord(xc, yc, mCropRegion); + int sensorOrientation = mCharacteristics.get( + CameraCharacteristics.SENSOR_ORIENTATION); + mAERegions = AutoFocusHelper.aeRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation); + mAFRegions = AutoFocusHelper.afRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation); sendAutoFocusTriggerCaptureRequest(RequestTag.TAP_TO_FOCUS); } diff --git a/src/com/android/camera/one/v2/OneCameraZslImpl.java b/src/com/android/camera/one/v2/OneCameraZslImpl.java index 4d6f632e3..aa03b8898 100644 --- a/src/com/android/camera/one/v2/OneCameraZslImpl.java +++ b/src/com/android/camera/one/v2/OneCameraZslImpl.java @@ -999,12 +999,10 @@ public class OneCameraZslImpl extends AbstractOneCamera { */ @Override public void triggerFocusAndMeterAtPoint(float nx, float ny) { - // xc, yc is center of tap point in sensor coordinate system. - int xc = mCropRegion.left + (int) (mCropRegion.width() * ny); - int yc = mCropRegion.top + (int) (mCropRegion.height() * (1f - nx)); - - mAERegions = AutoFocusHelper.aeRegionsForSensorCoord(xc, yc, mCropRegion); - mAFRegions = AutoFocusHelper.afRegionsForSensorCoord(xc, yc, mCropRegion); + int sensorOrientation = mCharacteristics.get( + CameraCharacteristics.SENSOR_ORIENTATION); + mAERegions = AutoFocusHelper.aeRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation); + mAFRegions = AutoFocusHelper.afRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation); startAFCycle(); } diff --git a/src/com/android/camera/settings/CameraSettingsActivity.java b/src/com/android/camera/settings/CameraSettingsActivity.java index 3692a75a7..f09f33b20 100644 --- a/src/com/android/camera/settings/CameraSettingsActivity.java +++ b/src/com/android/camera/settings/CameraSettingsActivity.java @@ -86,6 +86,7 @@ public class CameraSettingsActivity extends FragmentActivity { private String[] mCamcorderProfileNames; private CameraDeviceInfo mInfos; private final String mPrefKey; + private boolean mGetSubPrefAsRoot = true; // Selected resolutions for the different cameras and sizes. private SelectedPictureSizes mOldPictureSizesBack; @@ -104,11 +105,13 @@ public class CameraSettingsActivity extends FragmentActivity { super.onCreate(savedInstanceState); Context context = this.getActivity().getApplicationContext(); addPreferencesFromResource(R.xml.camera_preferences); - // Only add the additional preferences when in the main settings - // view, and not in the sub-preferences screens. - if (mPrefKey == null) { - CameraSettingsActivityHelper.addAdditionalPreferences(this, context); - } + + // Allow the Helper to edit the full preference hierarchy, not the sub + // tree we may show as root. See {@link #getPreferenceScreen()}. + mGetSubPrefAsRoot = false; + CameraSettingsActivityHelper.addAdditionalPreferences(this, context); + mGetSubPrefAsRoot = true; + mCamcorderProfileNames = getResources().getStringArray(R.array.camcorder_profile_names); mInfos = CameraAgentFactory .getAndroidCameraAgent(context, CameraAgentFactory.CameraApi.API_1) @@ -170,7 +173,7 @@ public class CameraSettingsActivity extends FragmentActivity { @Override public PreferenceScreen getPreferenceScreen() { PreferenceScreen root = super.getPreferenceScreen(); - if (mPrefKey == null || root == null) { + if (!mGetSubPrefAsRoot || mPrefKey == null || root == null) { return root; } else { PreferenceScreen match = findByKey(root, mPrefKey); diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index 627b6bf01..3a7e355c2 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -30,6 +30,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.camera2.CameraCharacteristics; @@ -322,6 +323,7 @@ public class CameraUtil { } public static int nextPowerOf2(int n) { + // TODO: what happens if n is negative or already a power of 2? n -= 1; n |= n >>> 16; n |= n >>> 8; @@ -337,6 +339,10 @@ public class CameraUtil { return (float) Math.sqrt(dx * dx + dy * dy); } + /** + * Clamps x to between min and max (inclusive on both ends, x = min --> min, + * x = max --> max). + */ public static int clamp(int x, int min, int max) { if (x > max) { return max; @@ -347,6 +353,10 @@ public class CameraUtil { return x; } + /** + * Clamps x to between min and max (inclusive on both ends, x = min --> min, + * x = max --> max). + */ public static float clamp(float x, float min, float max) { if (x > max) { return max; @@ -366,6 +376,31 @@ public class CameraUtil { } /** + * Given (nx, ny) \in [0, 1]^2, in the display's portrait coordinate system, + * returns normalized sensor coordinates \in [0, 1]^2 depending on how + * the sensor's orientation \in {0, 90, 180, 270}. + * + * <p> + * Returns null if sensorOrientation is not one of the above. + * </p> + */ + public static PointF normalizedSensorCoordsForNormalizedDisplayCoords( + float nx, float ny, int sensorOrientation) { + switch (sensorOrientation) { + case 0: + return new PointF(nx, ny); + case 90: + return new PointF(ny, 1.0f - nx); + case 180: + return new PointF(1.0f - nx, 1.0f - ny); + case 270: + return new PointF(1.0f - ny, nx); + default: + return null; + } + } + + /** * Given a size, return the largest size with the given aspectRatio that * maximally fits into the bounding rectangle of the original Size. * |