Merge "Fix display of preview thumbnail after recording video."
diff --git a/jni/feature_mos/src/mosaic/Blend.cpp b/jni/feature_mos/src/mosaic/Blend.cpp
index 470fba0..e8b30f3 100644
--- a/jni/feature_mos/src/mosaic/Blend.cpp
+++ b/jni/feature_mos/src/mosaic/Blend.cpp
@@ -148,6 +148,12 @@
double xLeftCorners[2] = {2e30, 2e30};
double xRightCorners[2] = {-2e30, -2e30};
+ // Corners of the top-most and bottom-most frames respectively in the
+ // mosaic coordinate system.
+ double yTopCorners[2] = {2e30, 2e30};
+ double yBottomCorners[2] = {-2e30, -2e30};
+
+
// Determine the extents of the final mosaic
CSite *csite = m_AllSites ;
for(int mfit = 0; mfit < frames_size; mfit++)
@@ -177,6 +183,19 @@
xRightCorners[1] = x2;
}
+ if(y0 < yTopCorners[0] || y3 < yTopCorners[1]) // If either of the top corners is lower
+ {
+ yTopCorners[0] = y0;
+ yTopCorners[1] = y3;
+ }
+
+ if(y1 > yBottomCorners[0] || y2 > yBottomCorners[1]) // If either of the bottom corners is higher
+ {
+ yBottomCorners[0] = y1;
+ yBottomCorners[1] = y2;
+ }
+
+
// Compute the centroid of the warped region
FindQuadCentroid(x0, y0, x1, y1, x2, y2, x3, y3, csite->getVCenter().x, csite->getVCenter().y);
@@ -198,11 +217,15 @@
Mheight = (unsigned short) (fullRect.bottom - fullRect.top + 1);
int xLeftMost, xRightMost;
+ int yTopMost, yBottomMost;
// Rounding up, so that we don't include the gray border.
xLeftMost = max(0, max(xLeftCorners[0], xLeftCorners[1]) - fullRect.left + 1);
xRightMost = min(Mwidth - 1, min(xRightCorners[0], xRightCorners[1]) - fullRect.left - 1);
+ yTopMost = max(0, max(yTopCorners[0], yTopCorners[1]) - fullRect.top + 1);
+ yBottomMost = min(Mheight - 1, min(yBottomCorners[0], yBottomCorners[1]) - fullRect.top - 1);
+
// Make sure image width is multiple of 4
Mwidth = (unsigned short) ((Mwidth + 3) & ~3);
Mheight = (unsigned short) ((Mheight + 3) & ~3); // Round up.
@@ -234,8 +257,16 @@
// cropped out of the computed mosaic to get rid of the gray borders.
MosaicRect cropping_rect;
- cropping_rect.left = xLeftMost;
- cropping_rect.right = xRightMost;
+ if (m_wb.horizontal)
+ {
+ cropping_rect.left = xLeftMost;
+ cropping_rect.right = xRightMost;
+ }
+ else
+ {
+ cropping_rect.top = yTopMost;
+ cropping_rect.bottom = yBottomMost;
+ }
// Do merging and blending :
ret = DoMergeAndBlend(frames, numCenters, width, height, *imgMos, fullRect,
@@ -378,47 +409,95 @@
// between the images on either side of each seam:
if (m_wb.stripType == STRIP_TYPE_WIDE)
{
- // Set the number of pixels around the seam to cross-fade between
- // the two component images,
- int tw = STRIP_CROSS_FADE_WIDTH * width;
-
- for(int y = 0; y < imgMos.Y.height; y++)
+ if(m_wb.horizontal)
{
- for(int x = tw; x < imgMos.Y.width - tw + 1; )
+ // Set the number of pixels around the seam to cross-fade between
+ // the two component images,
+ int tw = STRIP_CROSS_FADE_WIDTH * width;
+
+ for(int y = 0; y < imgMos.Y.height; y++)
{
- // Determine where the seam is...
- if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y][x+1] &&
- imgMos.Y.ptr[y][x] != 255 &&
- imgMos.Y.ptr[y][x+1] != 255)
+ for(int x = tw; x < imgMos.Y.width - tw + 1; )
{
- // Find the image indices on both sides of the seam
- unsigned char idx1 = imgMos.Y.ptr[y][x];
- unsigned char idx2 = imgMos.Y.ptr[y][x+1];
-
- for (int o = tw; o >= 0; o--)
+ // Determine where the seam is...
+ if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y][x+1] &&
+ imgMos.Y.ptr[y][x] != 255 &&
+ imgMos.Y.ptr[y][x+1] != 255)
{
- // Set the image index to use for cross-fading
- imgMos.V.ptr[y][x - o] = idx2;
- // Set the intensity weights to use for cross-fading
- imgMos.U.ptr[y][x - o] = 50 + (99 - 50) * o / tw;
- }
+ // Find the image indices on both sides of the seam
+ unsigned char idx1 = imgMos.Y.ptr[y][x];
+ unsigned char idx2 = imgMos.Y.ptr[y][x+1];
- for (int o = 1; o <= tw; o++)
+ for (int o = tw; o >= 0; o--)
+ {
+ // Set the image index to use for cross-fading
+ imgMos.V.ptr[y][x - o] = idx2;
+ // Set the intensity weights to use for cross-fading
+ imgMos.U.ptr[y][x - o] = 50 + (99 - 50) * o / tw;
+ }
+
+ for (int o = 1; o <= tw; o++)
+ {
+ // Set the image index to use for cross-fading
+ imgMos.V.ptr[y][x + o] = idx1;
+ // Set the intensity weights to use for cross-fading
+ imgMos.U.ptr[y][x + o] = imgMos.U.ptr[y][x - o];
+ }
+
+ x += (tw + 1);
+ }
+ else
{
- // Set the image index to use for cross-fading
- imgMos.V.ptr[y][x + o] = idx1;
- // Set the intensity weights to use for cross-fading
- imgMos.U.ptr[y][x + o] = imgMos.U.ptr[y][x - o];
+ x++;
}
-
- x += (tw + 1);
- }
- else
- {
- x++;
}
}
}
+ else
+ {
+ // Set the number of pixels around the seam to cross-fade between
+ // the two component images,
+ int tw = STRIP_CROSS_FADE_WIDTH * height;
+
+ for(int x = 0; x < imgMos.Y.width; x++)
+ {
+ for(int y = tw; y < imgMos.Y.height - tw + 1; )
+ {
+ // Determine where the seam is...
+ if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y+1][x] &&
+ imgMos.Y.ptr[y][x] != 255 &&
+ imgMos.Y.ptr[y+1][x] != 255)
+ {
+ // Find the image indices on both sides of the seam
+ unsigned char idx1 = imgMos.Y.ptr[y][x];
+ unsigned char idx2 = imgMos.Y.ptr[y+1][x];
+
+ for (int o = tw; o >= 0; o--)
+ {
+ // Set the image index to use for cross-fading
+ imgMos.V.ptr[y - o][x] = idx2;
+ // Set the intensity weights to use for cross-fading
+ imgMos.U.ptr[y - o][x] = 50 + (99 - 50) * o / tw;
+ }
+
+ for (int o = 1; o <= tw; o++)
+ {
+ // Set the image index to use for cross-fading
+ imgMos.V.ptr[y + o][x] = idx1;
+ // Set the intensity weights to use for cross-fading
+ imgMos.U.ptr[y + o][x] = imgMos.U.ptr[y - o][x];
+ }
+
+ y += (tw + 1);
+ }
+ else
+ {
+ y++;
+ }
+ }
+ }
+ }
+
}
// Now perform the actual blending using the frame assignment determined above
@@ -581,39 +660,80 @@
}
}
- //Scan through each row and increment top if the row contains any gray
- for (j = 0; j < imgMos.Y.height; j++)
+ if(m_wb.horizontal)
{
- for (i = cropping_rect.left; i < cropping_rect.right; i++)
+ //Scan through each row and increment top if the row contains any gray
+ for (j = 0; j < imgMos.Y.height; j++)
{
- if (b[j][i])
+ for (i = cropping_rect.left; i < cropping_rect.right; i++)
{
- break; // to next row
+ if (b[j][i])
+ {
+ break; // to next row
+ }
+ }
+
+ if (i == cropping_rect.right) //no gray pixel in this row!
+ {
+ cropping_rect.top = j;
+ break;
}
}
- if (i == cropping_rect.right) //no gray pixel in this row!
+ //Scan through each row and decrement bottom if the row contains any gray
+ for (j = imgMos.Y.height-1; j >= 0; j--)
{
- cropping_rect.top = j;
- break;
+ for (i = cropping_rect.left; i < cropping_rect.right; i++)
+ {
+ if (b[j][i])
+ {
+ break; // to next row
+ }
+ }
+
+ if (i == cropping_rect.right) //no gray pixel in this row!
+ {
+ cropping_rect.bottom = j;
+ break;
+ }
}
}
-
- //Scan through each row and decrement bottom if the row contains any gray
- for (j = imgMos.Y.height-1; j >= 0; j--)
+ else // Vertical Mosaic
{
- for (i = cropping_rect.left; i < cropping_rect.right; i++)
+ //Scan through each column and increment left if the column contains any gray
+ for (i = 0; i < imgMos.Y.width; i++)
{
- if (b[j][i])
+ for (j = cropping_rect.top; j < cropping_rect.bottom; j++)
{
- break; // to next row
+ if (b[j][i])
+ {
+ break; // to next column
+ }
+ }
+
+ if (j == cropping_rect.bottom) //no gray pixel in this column!
+ {
+ cropping_rect.left = i;
+ break;
}
}
- if (i == cropping_rect.right) //no gray pixel in this row!
+ //Scan through each column and decrement right if the column contains any gray
+ for (i = imgMos.Y.width-1; i >= 0; i--)
{
- cropping_rect.bottom = j;
- break;
+ for (j = cropping_rect.top; j < cropping_rect.bottom; j++)
+ {
+ if (b[j][i])
+ {
+ break; // to next column
+ }
+ }
+
+ if (j == cropping_rect.bottom) //no gray pixel in this column!
+ {
+ cropping_rect.right = i;
+ break;
+ }
}
}
@@ -1046,7 +1166,8 @@
double deltaY = currY - prevY;
double center2centerDist = sqrt(deltaY * deltaY + deltaX * deltaX);
- if (fabs(deltaX) > STRIP_SEPARATION_THRESHOLD * last->width)
+ if (fabs(deltaX) > STRIP_SEPARATION_THRESHOLD * last->width ||
+ fabs(deltaY) > STRIP_SEPARATION_THRESHOLD * last->height)
{
relevant_frames[relevant_frames_size] = mb;
relevant_frames_size++;
diff --git a/res/raw/backdropper.graph b/res/raw/backdropper.graph
index e3fe877..25c86e6 100644
--- a/res/raw/backdropper.graph
+++ b/res/raw/backdropper.graph
@@ -35,6 +35,8 @@
@external previewWidth;
@external previewHeight;
+@external orientation;
+
@external learningDoneListener;
// Filters ---------------------------------------------------
@@ -52,6 +54,7 @@
sourceUrl = "no_file_specified";
waitForNewFrame = false;
sourceIsUrl = true;
+ orientation = $orientation;
}
// Background replacer
diff --git a/res/raw/goofy_face.graph b/res/raw/goofy_face.graph
index e346322..430c811 100644
--- a/res/raw/goofy_face.graph
+++ b/res/raw/goofy_face.graph
@@ -37,6 +37,10 @@
@external previewWidth;
@external previewHeight;
+// Not used by this graph, but simplifies higher-level
+// graph initialization code.
+@external orientation;
+
// Filters ---------------------------------------------------
// Camera input
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 07863e5..10f0b80 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -119,9 +119,6 @@
private Parameters mInitialParams;
private boolean mFocusAreaSupported;
private boolean mMeteringAreaSupported;
- private boolean mAwbLockSupported;
- private boolean mAeLockSupported;
- private boolean mAeAwbLock;
private MyOrientationEventListener mOrientationListener;
// The degrees of the device rotated clockwise from its natural orientation.
@@ -1420,9 +1417,6 @@
// Do not do focus if there is not enough storage.
if (pressed && !canTakePicture()) return;
- // Lock AE and AWB so users can half-press shutter and recompose.
- mAeAwbLock = pressed;
- setCameraParameters(UPDATE_PARAM_PREFERENCE);
mFocusManager.doFocus(pressed);
}
@@ -1527,7 +1521,6 @@
if (mFaceView != null) {
mFaceView.setDisplayOrientation(mDisplayOrientation);
}
- mAeAwbLock = false; // Always unlock AE and AWB before start.
setCameraParameters(UPDATE_PARAM_ALL);
// If the focus mode is continuous autofocus, call cancelAutoFocus to
// resume it because it may have been paused by autoFocus call.
@@ -1582,14 +1575,6 @@
}
private void updateCameraParametersPreference() {
- if (mAwbLockSupported) {
- mParameters.setAutoWhiteBalanceLock(mAeAwbLock);
- }
-
- if (mAeLockSupported) {
- mParameters.setAutoExposureLock(mAeAwbLock);
- }
-
if (mFocusAreaSupported) {
mParameters.setFocusAreas(mFocusManager.getFocusAreas());
}
@@ -1985,7 +1970,5 @@
&& isSupported(Parameters.FOCUS_MODE_AUTO,
mInitialParams.getSupportedFocusModes()));
mMeteringAreaSupported = (mInitialParams.getMaxNumMeteringAreas() > 0);
- mAwbLockSupported = mInitialParams.isAutoWhiteBalanceLockSupported();
- mAeLockSupported = mInitialParams.isAutoExposureLockSupported();
}
}
diff --git a/src/com/android/camera/EffectsRecorder.java b/src/com/android/camera/EffectsRecorder.java
index 301f2a2..f177387 100644
--- a/src/com/android/camera/EffectsRecorder.java
+++ b/src/com/android/camera/EffectsRecorder.java
@@ -300,7 +300,8 @@
mGraphEnv.addReferences(
"previewSurface", mPreviewSurfaceHolder.getSurface(),
"previewWidth", mPreviewWidth,
- "previewHeight", mPreviewHeight);
+ "previewHeight", mPreviewHeight,
+ "orientation", mOrientationHint);
if (mState == STATE_PREVIEW) {
// Switching effects while running. Inform video camera.
sendMessage(mCurrentEffect, EFFECT_MSG_SWITCHING_EFFECT);
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index a1605de..09df1e0 100755
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -38,6 +38,7 @@
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
@@ -71,6 +72,7 @@
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.util.List;
/**
@@ -147,9 +149,6 @@
private Thumbnail mThumbnail;
private SharePopup mSharePopup;
- private AnimatorSet mThumbnailViewAndModePickerOut;
- private AnimatorSet mThumbnailViewAndModePickerIn;
-
private int mPreviewWidth;
private int mPreviewHeight;
private Camera mCameraDevice;
@@ -271,9 +270,8 @@
onBackgroundThreadFinished();
// Set the thumbnail bitmap here because mThumbnailView must be accessed
// from the UI thread.
- if (mThumbnail != null) {
- mThumbnailView.setBitmap(mThumbnail.getBitmap());
- }
+ updateThumbnailButton();
+
// Share popup may still have the reference to the old thumbnail. Clear it.
mSharePopup = null;
resetToPreview();
@@ -309,6 +307,12 @@
});
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ updateThumbnailButton();
+ }
+
private void setupCamera() {
openCamera();
Parameters parameters = mCameraDevice.getParameters();
@@ -526,30 +530,6 @@
mCaptureIndicator.setVisibility(View.VISIBLE);
showDirectionIndicators(PanoProgressBar.DIRECTION_NONE);
- // XML-style animations can not be used here. The Y position has to be calculated runtime.
- float ystart = mThumbnailView.getY();
- ValueAnimator va1 = ObjectAnimator.ofFloat(
- mThumbnailView, "y", ystart, -mThumbnailView.getHeight());
- ValueAnimator va1Reverse = ObjectAnimator.ofFloat(
- mThumbnailView, "y", -mThumbnailView.getHeight(), ystart);
- ystart = mModePicker.getY();
- float height = mCaptureLayout.getHeight();
- ValueAnimator va2 = ObjectAnimator.ofFloat(
- mModePicker, "y", ystart, height + 1);
- ValueAnimator va2Reverse = ObjectAnimator.ofFloat(
- mModePicker, "y", height + 1, ystart);
- LinearInterpolator li = new LinearInterpolator();
- mThumbnailViewAndModePickerOut = new AnimatorSet();
- mThumbnailViewAndModePickerOut.play(va1).with(va2);
- mThumbnailViewAndModePickerOut.setDuration(500);
- mThumbnailViewAndModePickerOut.setInterpolator(li);
- mThumbnailViewAndModePickerIn = new AnimatorSet();
- mThumbnailViewAndModePickerIn.play(va1Reverse).with(va2Reverse);
- mThumbnailViewAndModePickerIn.setDuration(500);
- mThumbnailViewAndModePickerIn.setInterpolator(li);
-
- mThumbnailViewAndModePickerOut.start();
-
mCompassValueXStart = mCompassValueXStartBuffer;
mCompassValueYStart = mCompassValueYStartBuffer;
mMinAngleX = 0;
@@ -571,6 +551,8 @@
}
});
+ if (mModePicker != null) mModePicker.setEnabled(false);
+
mPanoProgressBar.reset();
// TODO: calculate the indicator width according to different devices to reflect the actual
// angle of view of the camera device.
@@ -609,7 +591,8 @@
}
});
}
- mThumbnailViewAndModePickerIn.start();
+ // do we have to wait for the thread to complete before enabling this?
+ if (mModePicker != null) mModePicker.setEnabled(true);
}
private void showTooFastIndication() {
@@ -749,6 +732,19 @@
t.start();
}
+ private void updateThumbnailButton() {
+ // Update last image if URI is invalid and the storage is ready.
+ ContentResolver contentResolver = getContentResolver();
+ if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), contentResolver))) {
+ mThumbnail = Thumbnail.getLastThumbnail(contentResolver);
+ }
+ if (mThumbnail != null) {
+ mThumbnailView.setBitmap(mThumbnail.getBitmap());
+ } else {
+ mThumbnailView.setBitmap(null);
+ }
+ }
+
public void saveHighResMosaic() {
runBackgroundThread(new Thread() {
@Override
@@ -884,6 +880,7 @@
stopCapture(true);
reset();
}
+ if (mSharePopup != null) mSharePopup.dismiss();
releaseCamera();
mMosaicView.onPause();
clearMosaicFrameProcessorIfNeeded();