summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/camera/ActivityBase.java1
-rw-r--r--src/com/android/camera/CameraActivity.java19
-rw-r--r--src/com/android/camera/CameraPreference.java2
-rw-r--r--src/com/android/camera/CameraSettings.java1
-rw-r--r--src/com/android/camera/CaptureAnimManager.java104
-rw-r--r--src/com/android/camera/CountDownTimerPreference.java2
-rw-r--r--src/com/android/camera/EffectsRecorder.java1
-rw-r--r--src/com/android/camera/FocusOverlayManager.java69
-rw-r--r--src/com/android/camera/IconListPreference.java2
-rw-r--r--src/com/android/camera/ListPreference.java2
-rw-r--r--src/com/android/camera/OnScreenHint.java2
-rw-r--r--src/com/android/camera/PanoramaModule.java1
-rw-r--r--src/com/android/camera/PhotoController.java1
-rw-r--r--src/com/android/camera/PhotoModule.java11
-rw-r--r--src/com/android/camera/PreviewFrameLayout.java1
-rw-r--r--src/com/android/camera/PreviewGestures.java1
-rw-r--r--src/com/android/camera/RotateDialogController.java1
-rw-r--r--src/com/android/camera/SoundClips.java1
-rw-r--r--src/com/android/camera/Util.java1
-rw-r--r--src/com/android/camera/VideoController.java1
-rw-r--r--src/com/android/camera/VideoModule.java1
-rw-r--r--src/com/android/camera/ui/AbstractSettingPopup.java2
-rw-r--r--src/com/android/camera/ui/CameraSwitcher.java2
-rw-r--r--src/com/android/camera/ui/CountDownView.java2
-rw-r--r--src/com/android/camera/ui/EffectSettingPopup.java2
-rw-r--r--src/com/android/camera/ui/FaceView.java2
-rw-r--r--src/com/android/camera/ui/InLineSettingCheckBox.java2
-rw-r--r--src/com/android/camera/ui/InLineSettingItem.java2
-rw-r--r--src/com/android/camera/ui/InLineSettingMenu.java2
-rw-r--r--src/com/android/camera/ui/ListPrefSettingPopup.java2
-rw-r--r--src/com/android/camera/ui/MoreSettingPopup.java2
-rw-r--r--src/com/android/camera/ui/PieRenderer.java4
-rw-r--r--src/com/android/camera/ui/RotateTextToast.java2
-rw-r--r--src/com/android/camera/ui/Switch.java2
-rw-r--r--src/com/android/camera/ui/TimeIntervalPopup.java2
-rw-r--r--src/com/android/camera/ui/TimerSettingPopup.java2
-rw-r--r--src/com/android/camera/ui/ZoomRenderer.java2
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java31
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java1
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorVignette.java55
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterPoint.java21
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java87
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java69
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java114
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilter.java10
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java7
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java66
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java60
-rw-r--r--src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java4
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java256
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java99
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java128
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java29
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java5
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java131
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/Oval.java29
-rw-r--r--src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java2
-rw-r--r--src/com/android/gallery3d/ingest/ui/MtpImageView.java121
-rw-r--r--src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java1
-rwxr-xr-xtests/src/com/android/gallery3d/CameraTestRunner.java46
-rwxr-xr-xtests/src/com/android/gallery3d/StressTests.java47
-rw-r--r--tests/src/com/android/gallery3d/functional/CameraTest.java81
-rw-r--r--tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java148
-rw-r--r--tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java258
-rwxr-xr-xtests/src/com/android/gallery3d/power/ImageAndVideoCapture.java116
-rwxr-xr-xtests/src/com/android/gallery3d/stress/CameraLatency.java149
-rw-r--r--tests/src/com/android/gallery3d/stress/CameraStartUp.java157
-rwxr-xr-xtests/src/com/android/gallery3d/stress/CameraStressTestRunner.java61
-rwxr-xr-xtests/src/com/android/gallery3d/stress/ImageCapture.java121
-rw-r--r--tests/src/com/android/gallery3d/stress/ShotToShotLatency.java143
-rwxr-xr-xtests/src/com/android/gallery3d/stress/SwitchPreview.java117
-rw-r--r--tests/src/com/android/gallery3d/stress/TestUtil.java57
-rwxr-xr-xtests/src/com/android/gallery3d/stress/VideoCapture.java115
-rw-r--r--tests/src/com/android/gallery3d/unittest/CameraUnitTest.java107
-rw-r--r--tests_camera/src/com/android/camera/activity/CameraActivityTest.java2
-rw-r--r--tests_camera/src/com/android/camera/activity/CameraTestCase.java2
-rw-r--r--tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java2
-rw-r--r--tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java2
78 files changed, 2952 insertions, 364 deletions
diff --git a/src/com/android/camera/ActivityBase.java b/src/com/android/camera/ActivityBase.java
index 4e4143ef8..dc866f0e5 100644
--- a/src/com/android/camera/ActivityBase.java
+++ b/src/com/android/camera/ActivityBase.java
@@ -38,6 +38,7 @@ import android.view.animation.DecelerateInterpolator;
import com.android.camera.ui.LayoutChangeNotifier;
import com.android.camera.ui.PopupManager;
+import com.android.gallery3d.R;
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.app.AppBridge;
import com.android.gallery3d.app.FilmstripPage;
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index bf1ec2483..a207b2b71 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -23,11 +23,14 @@ import android.content.Context;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.MediaStore;
+import android.provider.Settings;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -37,6 +40,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.camera.ui.CameraSwitcher;
+import com.android.gallery3d.R;
import com.android.gallery3d.app.PhotoPage;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.util.LightCycleHelper;
@@ -57,6 +61,7 @@ public class CameraActivity extends ActivityBase
private Drawable[] mDrawables;
private int mCurrentModuleIndex;
private MotionEvent mDown;
+ private boolean mAutoRotateScreen;
private MyOrientationEventListener mOrientationListener;
// The degrees of the device rotated clockwise from its natural orientation.
@@ -140,6 +145,12 @@ public class CameraActivity extends ActivityBase
super.onDestroy();
}
+ // Return whether the auto-rotate screen in system settings
+ // is turned on.
+ public boolean isAutoRotateScreen() {
+ return mAutoRotateScreen;
+ }
+
private class MyOrientationEventListener
extends OrientationEventListener {
public MyOrientationEventListener(Context context) {
@@ -317,6 +328,14 @@ public class CameraActivity extends ActivityBase
@Override
public void onResume() {
mPaused = false;
+ if (Settings.System.getInt(getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ mAutoRotateScreen = false;
+ } else {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+ mAutoRotateScreen = true;
+ }
mOrientationListener.enable();
mCurrentModule.onResumeBeforeSuper();
super.onResume();
diff --git a/src/com/android/camera/CameraPreference.java b/src/com/android/camera/CameraPreference.java
index 0a4e9b3ce..5ddd86dbc 100644
--- a/src/com/android/camera/CameraPreference.java
+++ b/src/com/android/camera/CameraPreference.java
@@ -21,6 +21,8 @@ import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.gallery3d.R;
+
/**
* The base class of all Preferences used in Camera. The preferences can be
* loaded from XML resource by <code>PreferenceInflater</code>.
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 3bc58a034..31d31e128 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -30,6 +30,7 @@ import android.media.CamcorderProfile;
import android.util.FloatMath;
import android.util.Log;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.util.ArrayList;
diff --git a/src/com/android/camera/CaptureAnimManager.java b/src/com/android/camera/CaptureAnimManager.java
index 64383aff7..4643c379f 100644
--- a/src/com/android/camera/CaptureAnimManager.java
+++ b/src/com/android/camera/CaptureAnimManager.java
@@ -30,13 +30,18 @@ import com.android.gallery3d.glrenderer.RawTexture;
public class CaptureAnimManager {
@SuppressWarnings("unused")
private static final String TAG = "CAM_Capture";
+ // times mark endpoint of animation phase
private static final int TIME_FLASH = 200;
private static final int TIME_HOLD = 400;
- private static final int TIME_SLIDE = 400; // milliseconds.
+ private static final int TIME_SLIDE = 700;
+ private static final int TIME_HOLD2 = 1000;
+ private static final int TIME_SLIDE2 = 1200;
private static final int ANIM_BOTH = 0;
private static final int ANIM_FLASH = 1;
private static final int ANIM_SLIDE = 2;
+ private static final int ANIM_HOLD2 = 3;
+ private static final int ANIM_SLIDE2 = 4;
private final Interpolator mSlideInterpolator = new DecelerateInterpolator();
@@ -44,15 +49,22 @@ public class CaptureAnimManager {
private long mAnimStartTime; // milliseconds.
private float mX; // The center of the whole view including preview and review.
private float mY;
- private float mDelta;
private int mDrawWidth;
private int mDrawHeight;
private int mAnimType;
+ private int mHoldX;
+ private int mHoldY;
+ private int mHoldW;
+ private int mHoldH;
+
+ private int mOffset = 80;
+
/* preview: camera preview view.
* review: view of picture just taken.
*/
public CaptureAnimManager() {
+
}
public void setOrientation(int displayRotation) {
@@ -83,18 +95,24 @@ public class CaptureAnimManager {
mDrawHeight = h;
mX = x;
mY = y;
+ mHoldW = (int) (mDrawWidth * 0.7f);
+ mHoldH = (int) (mDrawHeight * 0.7f);
switch (mAnimOrientation) {
case 0: // Preview is on the left.
- mDelta = w;
+ mHoldX = x + w - mOffset;
+ mHoldY = y + (mDrawHeight - mHoldH) / 2;
break;
case 90: // Preview is below.
- mDelta = -h;
+ mHoldX = x + (mDrawWidth - mHoldW + 1) / 2;
+ mHoldY = y + mOffset- mHoldH;
break;
case 180: // Preview on the right.
- mDelta = -w;
+ mHoldX = x - w + mOffset;
+ mHoldY = y + (mDrawHeight - mHoldH) / 2;
break;
case 270: // Preview is above.
- mDelta = h;
+ mHoldX = x + (mDrawWidth - mHoldW + 1) / 2;
+ mHoldY = y + h - mOffset;
break;
}
}
@@ -104,14 +122,27 @@ public class CaptureAnimManager {
RawTexture review) {
long timeDiff = SystemClock.uptimeMillis() - mAnimStartTime;
// Check if the animation is over
- if (mAnimType == ANIM_SLIDE && timeDiff > TIME_SLIDE) return false;
- if (mAnimType == ANIM_BOTH && timeDiff > TIME_HOLD + TIME_SLIDE) return false;
+ if (mAnimType == ANIM_SLIDE && timeDiff > TIME_SLIDE2 - TIME_HOLD) return false;
+ if (mAnimType == ANIM_BOTH && timeDiff > TIME_SLIDE2) return false;
+ // determine phase and time in phase
int animStep = mAnimType;
- if (mAnimType == ANIM_BOTH) {
- animStep = (timeDiff < TIME_HOLD) ? ANIM_FLASH : ANIM_SLIDE;
- if (animStep == ANIM_SLIDE) {
+ if (mAnimType == ANIM_SLIDE) {
+ timeDiff += TIME_HOLD;
+ }
+ if (mAnimType == ANIM_SLIDE || mAnimType == ANIM_BOTH) {
+ if (timeDiff < TIME_HOLD) {
+ animStep = ANIM_FLASH;
+ } else if (timeDiff < TIME_SLIDE) {
+ animStep = ANIM_SLIDE;
timeDiff -= TIME_HOLD;
+ } else if (timeDiff < TIME_HOLD2) {
+ animStep = ANIM_HOLD2;
+ timeDiff -= TIME_SLIDE;
+ } else {
+ // SLIDE2
+ animStep = ANIM_SLIDE2;
+ timeDiff -= TIME_HOLD2;
}
}
@@ -123,24 +154,47 @@ public class CaptureAnimManager {
canvas.fillRect(mX, mY, mDrawWidth, mDrawHeight, color);
}
} else if (animStep == ANIM_SLIDE) {
- float fraction = (float) (timeDiff) / TIME_SLIDE;
+ float fraction = mSlideInterpolator.getInterpolation((float) (timeDiff) / (TIME_SLIDE - TIME_HOLD));
float x = mX;
float y = mY;
- if (mAnimOrientation == 0 || mAnimOrientation == 180) {
- x = x + mDelta * mSlideInterpolator.getInterpolation(fraction);
- } else {
- y = y + mDelta * mSlideInterpolator.getInterpolation(fraction);
+ float w = 0;
+ float h = 0;
+ x = interpolate(mX, mHoldX, fraction);
+ y = interpolate(mY, mHoldY, fraction);
+ w = interpolate(mDrawWidth, mHoldW, fraction);
+ h = interpolate(mDrawHeight, mHoldH, fraction);
+ preview.directDraw(canvas, (int) mX, (int) mY, mDrawWidth, mDrawHeight);
+ review.draw(canvas, (int) x, (int) y, (int) w, (int) h);
+ } else if (animStep == ANIM_HOLD2) {
+ preview.directDraw(canvas, (int) mX, (int) mY, mDrawWidth, mDrawHeight);
+ review.draw(canvas, mHoldX, mHoldY, mHoldW, mHoldH);
+ } else if (animStep == ANIM_SLIDE2) {
+ float fraction = (float)(timeDiff) / (TIME_SLIDE2 - TIME_HOLD2);
+ float x = mHoldX;
+ float y = mHoldY;
+ float d = mOffset * fraction;
+ switch (mAnimOrientation) {
+ case 0:
+ x = mHoldX + d;
+ break;
+ case 180:
+ x = mHoldX - d;
+ break;
+ case 90:
+ y = mHoldY - d;
+ break;
+ case 270:
+ y = mHoldY + d;
+ break;
}
- // float alpha = canvas.getAlpha();
- // canvas.setAlpha(fraction);
- preview.directDraw(canvas, (int) mX, (int) mY,
- mDrawWidth, mDrawHeight);
- // canvas.setAlpha(alpha);
-
- review.draw(canvas, (int) x, (int) y, mDrawWidth, mDrawHeight);
- } else {
- return false;
+ preview.directDraw(canvas, (int) mX, (int) mY, mDrawWidth, mDrawHeight);
+ review.draw(canvas, (int) x, (int) y, mHoldW, mHoldH);
}
return true;
}
+
+ private static float interpolate(float start, float end, float fraction) {
+ return start + (end - start) * fraction;
+ }
+
}
diff --git a/src/com/android/camera/CountDownTimerPreference.java b/src/com/android/camera/CountDownTimerPreference.java
index 6c0f67369..0bbf6bc9d 100644
--- a/src/com/android/camera/CountDownTimerPreference.java
+++ b/src/com/android/camera/CountDownTimerPreference.java
@@ -19,6 +19,8 @@ package com.android.camera;
import android.content.Context;
import android.util.AttributeSet;
+import com.android.gallery3d.R;
+
import java.util.List;
/* CountDownTimerPreference generates entries (i.e. what users see in the UI),
diff --git a/src/com/android/camera/EffectsRecorder.java b/src/com/android/camera/EffectsRecorder.java
index 4601ab9ec..2db44c76f 100644
--- a/src/com/android/camera/EffectsRecorder.java
+++ b/src/com/android/camera/EffectsRecorder.java
@@ -26,6 +26,7 @@ import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.io.FileDescriptor;
diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java
index 2bec18760..a3726ed56 100644
--- a/src/com/android/camera/FocusOverlayManager.java
+++ b/src/com/android/camera/FocusOverlayManager.java
@@ -94,6 +94,8 @@ public class FocusOverlayManager {
private ComboPreferences mPreferences;
private Handler mHandler;
Listener mListener;
+ private boolean mPreviousMoving;
+ private boolean mFocusDefault;
public interface Listener {
public void autoFocus();
@@ -131,6 +133,7 @@ public class FocusOverlayManager {
setParameters(parameters);
mListener = listener;
setMirror(mirror);
+ mFocusDefault = true;
}
public void setFocusRenderer(PieRenderer renderer) {
@@ -277,7 +280,7 @@ public class FocusOverlayManager {
updateFocusUI();
// If this is triggered by touch focus, cancel focus after a
// while.
- if (mFocusArea != null) {
+ if (!mFocusDefault) {
mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
}
if (shutterButtonPressed) {
@@ -302,29 +305,28 @@ public class FocusOverlayManager {
// continuous autofocus.
if (mState != STATE_IDLE) return;
- if (moving) {
+ // animate on false->true trasition only b/8219520
+ if (moving && !mPreviousMoving) {
mPieRenderer.showStart();
- } else {
+ } else if (!moving) {
mPieRenderer.showSuccess(true);
}
+ mPreviousMoving = moving;
}
@TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void initializeFocusAreas(int focusWidth, int focusHeight,
- int x, int y, int previewWidth, int previewHeight) {
+ private void initializeFocusAreas(int x, int y) {
if (mFocusArea == null) {
mFocusArea = new ArrayList<Object>();
mFocusArea.add(new Area(new Rect(), 1));
}
// Convert the coordinates to driver format.
- calculateTapArea(focusWidth, focusHeight, 1f, x, y, previewWidth, previewHeight,
- ((Area) mFocusArea.get(0)).rect);
+ calculateTapArea(x, y, 1f, ((Area) mFocusArea.get(0)).rect);
}
@TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void initializeMeteringAreas(int focusWidth, int focusHeight,
- int x, int y, int previewWidth, int previewHeight) {
+ private void initializeMeteringAreas(int x, int y) {
if (mMeteringArea == null) {
mMeteringArea = new ArrayList<Object>();
mMeteringArea.add(new Area(new Rect(), 1));
@@ -333,34 +335,26 @@ public class FocusOverlayManager {
// Convert the coordinates to driver format.
// AE area is bigger because exposure is sensitive and
// easy to over- or underexposure if area is too small.
- calculateTapArea(focusWidth, focusHeight, 1.5f, x, y, previewWidth, previewHeight,
- ((Area) mMeteringArea.get(0)).rect);
+ calculateTapArea(x, y, 1.5f, ((Area) mMeteringArea.get(0)).rect);
}
public void onSingleTapUp(int x, int y) {
if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) return;
// Let users be able to cancel previous touch focus.
- if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
+ if ((!mFocusDefault) && (mState == STATE_FOCUSING ||
mState == STATE_SUCCESS || mState == STATE_FAIL)) {
cancelAutoFocus();
}
- // Initialize variables.
- int focusWidth = mPieRenderer.getSize();
- int focusHeight = mPieRenderer.getSize();
- if (focusWidth == 0 || mPieRenderer.getWidth() == 0
- || mPieRenderer.getHeight() == 0) return;
- int previewWidth = mPreviewWidth;
- int previewHeight = mPreviewHeight;
+ if (mPreviewWidth == 0 || mPreviewHeight == 0) return;
+ mFocusDefault = false;
// Initialize mFocusArea.
if (mFocusAreaSupported) {
- initializeFocusAreas(
- focusWidth, focusHeight, x, y, previewWidth, previewHeight);
+ initializeFocusAreas(x, y);
}
// Initialize mMeteringArea.
if (mMeteringAreaSupported) {
- initializeMeteringAreas(
- focusWidth, focusHeight, x, y, previewWidth, previewHeight);
+ initializeMeteringAreas(x, y);
}
// Use margin to set the focus indicator to the touched area.
@@ -430,9 +424,10 @@ public class FocusOverlayManager {
public String getFocusMode() {
if (mOverrideFocusMode != null) return mOverrideFocusMode;
+ if (mParameters == null) return Parameters.FOCUS_MODE_AUTO;
List<String> supportedFocusModes = mParameters.getSupportedFocusModes();
- if (mFocusAreaSupported && mFocusArea != null) {
+ if (mFocusAreaSupported && !mFocusDefault) {
// Always use autofocus in tap-to-focus.
mFocusMode = Parameters.FOCUS_MODE_AUTO;
} else {
@@ -479,7 +474,7 @@ public class FocusOverlayManager {
FocusIndicator focusIndicator = (faceExists) ? mFaceView : mPieRenderer;
if (mState == STATE_IDLE) {
- if (mFocusArea == null) {
+ if (mFocusDefault) {
focusIndicator.clear();
} else {
// Users touch on the preview and the indicator represents the
@@ -506,19 +501,23 @@ public class FocusOverlayManager {
// Put focus indicator to the center. clear reset position
mPieRenderer.clear();
-
- mFocusArea = null;
- mMeteringArea = null;
+ // Initialize mFocusArea.
+ if (mFocusAreaSupported) {
+ initializeFocusAreas(mPreviewWidth / 2, mPreviewHeight / 2);
+ }
+ // Initialize mMeteringArea.
+ if (mMeteringAreaSupported) {
+ initializeMeteringAreas(mPreviewWidth / 2, mPreviewHeight / 2);
+ }
+ mFocusDefault = true;
}
- private void calculateTapArea(int focusWidth, int focusHeight, float areaMultiple,
- int x, int y, int previewWidth, int previewHeight, Rect rect) {
- int areaWidth = (int) (focusWidth * areaMultiple);
- int areaHeight = (int) (focusHeight * areaMultiple);
- int left = Util.clamp(x - areaWidth / 2, 0, previewWidth - areaWidth);
- int top = Util.clamp(y - areaHeight / 2, 0, previewHeight - areaHeight);
+ private void calculateTapArea(int x, int y, float areaMultiple, Rect rect) {
+ int areaSize = (int) (Math.min(mPreviewWidth, mPreviewHeight) * areaMultiple / 20);
+ int left = Util.clamp(x - areaSize, 0, mPreviewWidth - 2 * areaSize);
+ int top = Util.clamp(y - areaSize, 0, mPreviewHeight - 2 * areaSize);
- RectF rectF = new RectF(left, top, left + areaWidth, top + areaHeight);
+ RectF rectF = new RectF(left, top, left + 2 * areaSize, top + 2 * areaSize);
mMatrix.mapRect(rectF);
Util.rectFToRect(rectF, rect);
}
diff --git a/src/com/android/camera/IconListPreference.java b/src/com/android/camera/IconListPreference.java
index 6bcd59df1..e5f75d3a5 100644
--- a/src/com/android/camera/IconListPreference.java
+++ b/src/com/android/camera/IconListPreference.java
@@ -21,6 +21,8 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.gallery3d.R;
+
import java.util.List;
/** A {@code ListPreference} where each entry has a corresponding icon. */
diff --git a/src/com/android/camera/ListPreference.java b/src/com/android/camera/ListPreference.java
index 17266ea73..a29b19719 100644
--- a/src/com/android/camera/ListPreference.java
+++ b/src/com/android/camera/ListPreference.java
@@ -23,6 +23,8 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
+import com.android.gallery3d.R;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/camera/OnScreenHint.java b/src/com/android/camera/OnScreenHint.java
index 80063e429..4d7fa7088 100644
--- a/src/com/android/camera/OnScreenHint.java
+++ b/src/com/android/camera/OnScreenHint.java
@@ -25,6 +25,8 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
+import com.android.gallery3d.R;
+
/**
* A on-screen hint is a view containing a little message for the user and will
* be shown on the screen continuously. This class helps you create and show
diff --git a/src/com/android/camera/PanoramaModule.java b/src/com/android/camera/PanoramaModule.java
index 6302158e9..4edc68657 100644
--- a/src/com/android/camera/PanoramaModule.java
+++ b/src/com/android/camera/PanoramaModule.java
@@ -58,6 +58,7 @@ import com.android.camera.ui.LayoutChangeNotifier;
import com.android.camera.ui.LayoutNotifyView;
import com.android.camera.ui.PopupManager;
import com.android.camera.ui.Rotatable;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.exif.ExifData;
import com.android.gallery3d.exif.ExifInvalidFormatException;
diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java
index ad8659ee8..c2501c781 100644
--- a/src/com/android/camera/PhotoController.java
+++ b/src/com/android/camera/PhotoController.java
@@ -27,6 +27,7 @@ import com.android.camera.ui.PieItem;
import com.android.camera.ui.PieItem.OnClickListener;
import com.android.camera.ui.PieRenderer;
import com.android.camera.ui.TimerSettingPopup;
+import com.android.gallery3d.R;
public class PhotoController extends PieController
implements MoreSettingPopup.Listener,
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 60cb67896..15f40461d 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -72,6 +72,7 @@ import com.android.camera.ui.Rotatable;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.ui.TwoStateImageView;
import com.android.camera.ui.ZoomRenderer;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.filtershow.CropExtras;
import com.android.gallery3d.filtershow.FilterShowActivity;
@@ -1133,7 +1134,15 @@ public class PhotoModule
}
// Set rotation and gps data.
- mJpegRotation = Util.getJpegRotation(mCameraId, mOrientation);
+ int orientation;
+ // We need to be consistent with the framework orientation (i.e. the
+ // orientation of the UI.) when the auto-rotate screen setting is on.
+ if (mActivity.isAutoRotateScreen()) {
+ orientation = (360 - mDisplayRotation) % 360;
+ } else {
+ orientation = mOrientation;
+ }
+ mJpegRotation = Util.getJpegRotation(mCameraId, orientation);
mParameters.setRotation(mJpegRotation);
Location loc = mLocationManager.getCurrentLocation();
Util.setGpsParameters(mParameters, loc);
diff --git a/src/com/android/camera/PreviewFrameLayout.java b/src/com/android/camera/PreviewFrameLayout.java
index 451a35ad3..87e3c8dfc 100644
--- a/src/com/android/camera/PreviewFrameLayout.java
+++ b/src/com/android/camera/PreviewFrameLayout.java
@@ -25,6 +25,7 @@ import android.widget.RelativeLayout;
import com.android.camera.ui.LayoutChangeHelper;
import com.android.camera.ui.LayoutChangeNotifier;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
/**
diff --git a/src/com/android/camera/PreviewGestures.java b/src/com/android/camera/PreviewGestures.java
index 2dccc3e45..cb7ca09c7 100644
--- a/src/com/android/camera/PreviewGestures.java
+++ b/src/com/android/camera/PreviewGestures.java
@@ -27,6 +27,7 @@ import android.view.ViewConfiguration;
import com.android.camera.ui.PieRenderer;
import com.android.camera.ui.RenderOverlay;
import com.android.camera.ui.ZoomRenderer;
+import com.android.gallery3d.R;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/camera/RotateDialogController.java b/src/com/android/camera/RotateDialogController.java
index 700d35434..5d5e5e70f 100644
--- a/src/com/android/camera/RotateDialogController.java
+++ b/src/com/android/camera/RotateDialogController.java
@@ -28,6 +28,7 @@ import android.widget.TextView;
import com.android.camera.ui.Rotatable;
import com.android.camera.ui.RotateLayout;
+import com.android.gallery3d.R;
public class RotateDialogController implements Rotatable {
diff --git a/src/com/android/camera/SoundClips.java b/src/com/android/camera/SoundClips.java
index b5e783105..6388fec56 100644
--- a/src/com/android/camera/SoundClips.java
+++ b/src/com/android/camera/SoundClips.java
@@ -23,6 +23,7 @@ import android.media.MediaActionSound;
import android.media.SoundPool;
import android.util.Log;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
/*
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 2953d6ae7..ed42de85a 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -52,6 +52,7 @@ import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.io.Closeable;
diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java
index d84c1ad1f..3a220773b 100644
--- a/src/com/android/camera/VideoController.java
+++ b/src/com/android/camera/VideoController.java
@@ -26,6 +26,7 @@ import com.android.camera.ui.PieItem;
import com.android.camera.ui.PieItem.OnClickListener;
import com.android.camera.ui.PieRenderer;
import com.android.camera.ui.TimeIntervalPopup;
+import com.android.gallery3d.R;
public class VideoController extends PieController
implements MoreSettingPopup.Listener,
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index b7bd20831..4d01bc320 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -75,6 +75,7 @@ import com.android.camera.ui.RotateLayout;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.ui.TwoStateImageView;
import com.android.camera.ui.ZoomRenderer;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.util.AccessibilityUtils;
diff --git a/src/com/android/camera/ui/AbstractSettingPopup.java b/src/com/android/camera/ui/AbstractSettingPopup.java
index 49df77b30..783b6c771 100644
--- a/src/com/android/camera/ui/AbstractSettingPopup.java
+++ b/src/com/android/camera/ui/AbstractSettingPopup.java
@@ -21,7 +21,7 @@ import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.camera.R;
+import com.android.gallery3d.R;
// A popup window that shows one or more camera settings.
abstract public class AbstractSettingPopup extends RotateLayout {
diff --git a/src/com/android/camera/ui/CameraSwitcher.java b/src/com/android/camera/ui/CameraSwitcher.java
index 7b9fb6499..8d2cd7117 100644
--- a/src/com/android/camera/ui/CameraSwitcher.java
+++ b/src/com/android/camera/ui/CameraSwitcher.java
@@ -32,7 +32,7 @@ import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
public class CameraSwitcher extends RotateImageView
diff --git a/src/com/android/camera/ui/CountDownView.java b/src/com/android/camera/ui/CountDownView.java
index ade25c33a..907d33508 100644
--- a/src/com/android/camera/ui/CountDownView.java
+++ b/src/com/android/camera/ui/CountDownView.java
@@ -31,7 +31,7 @@ import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.TextView;
-import com.android.camera.R;
+import com.android.gallery3d.R;
public class CountDownView extends FrameLayout {
diff --git a/src/com/android/camera/ui/EffectSettingPopup.java b/src/com/android/camera/ui/EffectSettingPopup.java
index 628d8155a..568781a01 100644
--- a/src/com/android/camera/ui/EffectSettingPopup.java
+++ b/src/com/android/camera/ui/EffectSettingPopup.java
@@ -26,8 +26,8 @@ import android.widget.GridView;
import android.widget.SimpleAdapter;
import com.android.camera.IconListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.util.ArrayList;
diff --git a/src/com/android/camera/ui/FaceView.java b/src/com/android/camera/ui/FaceView.java
index 9e6f98245..099f3bf4b 100644
--- a/src/com/android/camera/ui/FaceView.java
+++ b/src/com/android/camera/ui/FaceView.java
@@ -33,8 +33,8 @@ import android.view.View;
import com.android.camera.CameraActivity;
import com.android.camera.CameraScreenNail;
-import com.android.camera.R;
import com.android.camera.Util;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
@TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
diff --git a/src/com/android/camera/ui/InLineSettingCheckBox.java b/src/com/android/camera/ui/InLineSettingCheckBox.java
index 5d9cc388d..c1aa5a91c 100644
--- a/src/com/android/camera/ui/InLineSettingCheckBox.java
+++ b/src/com/android/camera/ui/InLineSettingCheckBox.java
@@ -25,7 +25,7 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
/* A check box setting control which turns on/off the setting. */
public class InLineSettingCheckBox extends InLineSettingItem {
diff --git a/src/com/android/camera/ui/InLineSettingItem.java b/src/com/android/camera/ui/InLineSettingItem.java
index 4f88f2738..839a77fd0 100644
--- a/src/com/android/camera/ui/InLineSettingItem.java
+++ b/src/com/android/camera/ui/InLineSettingItem.java
@@ -23,7 +23,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
/**
* A one-line camera setting could be one of three types: knob, switch or restore
diff --git a/src/com/android/camera/ui/InLineSettingMenu.java b/src/com/android/camera/ui/InLineSettingMenu.java
index 2fe89349a..8e45c3e38 100644
--- a/src/com/android/camera/ui/InLineSettingMenu.java
+++ b/src/com/android/camera/ui/InLineSettingMenu.java
@@ -23,7 +23,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
/* Setting menu item that will bring up a menu when you click on it. */
public class InLineSettingMenu extends InLineSettingItem {
diff --git a/src/com/android/camera/ui/ListPrefSettingPopup.java b/src/com/android/camera/ui/ListPrefSettingPopup.java
index c0411c90d..cfef73f49 100644
--- a/src/com/android/camera/ui/ListPrefSettingPopup.java
+++ b/src/com/android/camera/ui/ListPrefSettingPopup.java
@@ -27,7 +27,7 @@ import android.widget.SimpleAdapter;
import com.android.camera.IconListPreference;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/src/com/android/camera/ui/MoreSettingPopup.java b/src/com/android/camera/ui/MoreSettingPopup.java
index ab1babaab..5900058df 100644
--- a/src/com/android/camera/ui/MoreSettingPopup.java
+++ b/src/com/android/camera/ui/MoreSettingPopup.java
@@ -28,7 +28,7 @@ import android.widget.ListView;
import com.android.camera.ListPreference;
import com.android.camera.PreferenceGroup;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import java.util.ArrayList;
diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java
index b592508e1..95597b2a1 100644
--- a/src/com/android/camera/ui/PieRenderer.java
+++ b/src/com/android/camera/ui/PieRenderer.java
@@ -36,7 +36,7 @@ import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.util.ArrayList;
@@ -717,7 +717,7 @@ public class PieRenderer extends OverlayRenderer
private void cancelFocus() {
mFocusCancelled = true;
mOverlay.removeCallbacks(mDisappear);
- if (mAnimation != null) {
+ if (mAnimation != null && !mAnimation.hasEnded()) {
mAnimation.cancel();
}
mFocusCancelled = false;
diff --git a/src/com/android/camera/ui/RotateTextToast.java b/src/com/android/camera/ui/RotateTextToast.java
index f73c03362..c78a258b0 100644
--- a/src/com/android/camera/ui/RotateTextToast.java
+++ b/src/com/android/camera/ui/RotateTextToast.java
@@ -23,8 +23,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.camera.R;
import com.android.camera.Util;
+import com.android.gallery3d.R;
public class RotateTextToast {
private static final int TOAST_DURATION = 5000; // milliseconds
diff --git a/src/com/android/camera/ui/Switch.java b/src/com/android/camera/ui/Switch.java
index 5b1ab4c97..ac21758a7 100644
--- a/src/com/android/camera/ui/Switch.java
+++ b/src/com/android/camera/ui/Switch.java
@@ -42,7 +42,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.CompoundButton;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.util.Arrays;
diff --git a/src/com/android/camera/ui/TimeIntervalPopup.java b/src/com/android/camera/ui/TimeIntervalPopup.java
index b79663be2..18ad9f5da 100644
--- a/src/com/android/camera/ui/TimeIntervalPopup.java
+++ b/src/com/android/camera/ui/TimeIntervalPopup.java
@@ -28,7 +28,7 @@ import android.widget.TextView;
import com.android.camera.IconListPreference;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
/**
* This is a popup window that allows users to turn on/off time lapse feature,
diff --git a/src/com/android/camera/ui/TimerSettingPopup.java b/src/com/android/camera/ui/TimerSettingPopup.java
index 06d7e4e50..983c7f21b 100644
--- a/src/com/android/camera/ui/TimerSettingPopup.java
+++ b/src/com/android/camera/ui/TimerSettingPopup.java
@@ -30,7 +30,7 @@ import android.widget.Switch;
import android.widget.TextView;
import com.android.camera.ListPreference;
-import com.android.camera.R;
+import com.android.gallery3d.R;
/**
* This is a popup window that allows users to turn on/off time lapse feature,
diff --git a/src/com/android/camera/ui/ZoomRenderer.java b/src/com/android/camera/ui/ZoomRenderer.java
index 10c5e80d4..86b82b459 100644
--- a/src/com/android/camera/ui/ZoomRenderer.java
+++ b/src/com/android/camera/ui/ZoomRenderer.java
@@ -24,7 +24,7 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.view.ScaleGestureDetector;
-import com.android.camera.R;
+import com.android.gallery3d.R;
public class ZoomRenderer extends OverlayRenderer
implements ScaleGestureDetector.OnScaleGestureListener {
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 0660eda30..f7147eac1 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -88,6 +88,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
// fields for supporting crop action
public static final String CROP_ACTION = "com.android.camera.action.CROP";
private CropExtras mCropExtras = null;
+ private String mAction = "";
MasterImage mMasterImage = null;
public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
@@ -146,6 +147,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private FilterIconButton mNullBorderFilter;
private int mIconSeedSize = 140;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -308,6 +310,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
+ mAction = intent.getAction();
+
if (intent.getData() != null) {
startLoadBitmap(intent.getData());
} else {
@@ -315,8 +319,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
// Handle behavior for various actions
- String action = intent.getAction();
- if (action.equalsIgnoreCase(CROP_ACTION)) {
+ if (mAction.equalsIgnoreCase(CROP_ACTION)) {
Bundle extras = intent.getExtras();
if (extras != null) {
mCropExtras = new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),
@@ -345,9 +348,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
mPanelController.setFixedAspect(mCropExtras.getAspectX() > 0
&& mCropExtras.getAspectY() > 0);
}
- mPanelController.showComponent(findViewById(R.id.cropButton));
- } else if (action.equalsIgnoreCase(TINY_PLANET_ACTION)) {
- mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
}
}
@@ -502,6 +502,13 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
mLoadBitmapTask = null;
+
+ if (mAction == CROP_ACTION) {
+ mPanelController.showComponent(findViewById(R.id.cropButton));
+ } else if (mAction == TINY_PLANET_ACTION) {
+ mPanelController.showComponent(findViewById(R.id.tinyplanetButton));
+ }
+
super.onPostExecute(result);
}
@@ -1037,31 +1044,31 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private boolean mSaveToExtraUri = false;
private boolean mSaveAsWallpaper = false;
private boolean mReturnAsExtra = false;
- private boolean outputted = false;
+ private boolean mOutputted = false;
public void saveImage() {
if (mCropExtras != null) {
if (mCropExtras.getExtraOutput() != null) {
mSaveToExtraUri = true;
- outputted = true;
+ mOutputted = true;
}
if (mCropExtras.getSetAsWallpaper()) {
mSaveAsWallpaper = true;
- outputted = true;
+ mOutputted = true;
}
if (mCropExtras.getReturnData()) {
mReturnAsExtra = true;
- outputted = true;
+ mOutputted = true;
}
- if (outputted) {
+ if (mOutputted) {
mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
showSavingProgress(null);
mImageShow.returnFilteredResult(this);
}
}
- if (!outputted) {
+ if (!mOutputted) {
if (mImageShow.hasModifications()) {
// Get the name of the album, to which the image will be saved
File saveDir = SaveCopyTask.getFinalSaveDirectory(this, mImageLoader.getUri());
@@ -1111,7 +1118,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
}
public void done() {
- if (outputted) {
+ if (mOutputted) {
hideSavingProgress();
}
finish();
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 00fcf4e19..698992ac9 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -456,6 +456,7 @@ public class ImageLoader {
Log.w(LOGTAG, "Failed to save image!");
return null;
}
+ bitmap = param.applyGeometry(bitmap);
return param.apply(bitmap);
}
};
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
new file mode 100644
index 000000000..a60c1681e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.filtershow.editors;
+
+import android.content.Context;
+import android.util.Log;
+import android.widget.FrameLayout;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTinyPlanetRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterVignetteRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageVignette;
+
+public class EditorVignette extends BasicEditor {
+ public static final int ID = R.id.vignetteEditor;
+ private static final String LOGTAG = "EditorVignettePlanet";
+ ImageVignette mImageVignette;
+
+ public EditorVignette() {
+ super(ID, R.layout.filtershow_vignette_editor, R.id.imageVignette);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ mImageVignette = (ImageVignette) mImageShow;
+ mImageVignette.setEditor(this);
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ super.reflectCurrentFilter();
+
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep != null && getLocalRepresentation() instanceof FilterVignetteRepresentation) {
+ FilterVignetteRepresentation drawRep = (FilterVignetteRepresentation) rep;
+ mImageVignette.setRepresentation(drawRep);
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterPoint.java b/src/com/android/gallery3d/filtershow/filters/FilterPoint.java
new file mode 100644
index 000000000..4520717a1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterPoint.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 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.gallery3d.filtershow.filters;
+
+public interface FilterPoint {
+
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java
new file mode 100644
index 000000000..fc01650ae
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 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.gallery3d.filtershow.filters;
+
+import java.util.Vector;
+
+public abstract class FilterPointRepresentation extends FilterRepresentation {
+ private static final String LOGTAG = "FilterPointRepresentation";
+ private Vector<FilterPoint> mCandidates = new Vector<FilterPoint>();
+
+ public FilterPointRepresentation(String type, int textid, int editorID) {
+ super(type);
+ setFilterClass(ImageFilterRedEye.class);
+ setPriority(FilterRepresentation.TYPE_NORMAL);
+ setTextId(textid);
+ setEditorId(editorID);
+ }
+
+ @Override
+ public FilterRepresentation clone() throws CloneNotSupportedException {
+ FilterPointRepresentation representation = (FilterPointRepresentation) super
+ .clone();
+ representation.mCandidates = (Vector<FilterPoint>) mCandidates.clone();
+ return representation;
+ }
+
+ public boolean hasCandidates() {
+ return mCandidates != null;
+ }
+
+ public Vector<FilterPoint> getCandidates() {
+ return mCandidates;
+ }
+
+ @Override
+ public boolean isNil() {
+ if (getCandidates() != null && getCandidates().size() > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public Object getCandidate(int index) {
+ return this.mCandidates.get(index);
+ }
+
+ public void addCandidate(FilterPoint c) {
+ this.mCandidates.add(c);
+ }
+
+ @Override
+ public void useParametersFrom(FilterRepresentation a) {
+ if (a instanceof FilterPointRepresentation) {
+ FilterPointRepresentation representation = (FilterPointRepresentation) a;
+ mCandidates.clear();
+ for (FilterPoint redEyeCandidate : representation.mCandidates) {
+ mCandidates.add(redEyeCandidate);
+ }
+ }
+ }
+
+ public void removeCandidate(RedEyeCandidate c) {
+ this.mCandidates.remove(c);
+ }
+
+ public void clearCandidates() {
+ this.mCandidates.clear();
+ }
+
+ public int getNumberOfCandidates() {
+ return mCandidates.size();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
index 7779211df..70d016f69 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -24,80 +24,19 @@ import com.android.gallery3d.filtershow.editors.EditorRedEye;
import java.util.Vector;
-public class FilterRedEyeRepresentation extends FilterRepresentation {
+public class FilterRedEyeRepresentation extends FilterPointRepresentation {
private static final String LOGTAG = "FilterRedEyeRepresentation";
- private Vector<RedEyeCandidate> mCandidates = new Vector<RedEyeCandidate>();
public FilterRedEyeRepresentation() {
- super("RedEye");
+ super("RedEye",R.string.redeye,EditorRedEye.ID);
setFilterClass(ImageFilterRedEye.class);
- setPriority(FilterRepresentation.TYPE_NORMAL);
- setTextId(R.string.redeye);
- setEditorId(EditorRedEye.ID);
setOverlayId(R.drawable.photoeditor_effect_redeye);
}
- @Override
- public FilterRepresentation clone() throws CloneNotSupportedException {
- FilterRedEyeRepresentation representation = (FilterRedEyeRepresentation) super
- .clone();
- representation.mCandidates = (Vector<RedEyeCandidate>) mCandidates.clone();
- return representation;
- }
-
- public boolean hasCandidates() {
- return mCandidates != null;
- }
-
- public Vector<RedEyeCandidate> getCandidates() {
- return mCandidates;
- }
-
- public void setCandidates(Vector<RedEyeCandidate> mCandidates) {
- this.mCandidates = mCandidates;
- }
-
- public RedEyeCandidate getCandidate(int index) {
- return this.mCandidates.get(index);
- }
-
- public void addCandidate(RedEyeCandidate c) {
- this.mCandidates.add(c);
- }
-
- @Override
- public void useParametersFrom(FilterRepresentation a) {
- if (a instanceof FilterRedEyeRepresentation) {
- FilterRedEyeRepresentation representation = (FilterRedEyeRepresentation) a;
- mCandidates.clear();
- for (RedEyeCandidate redEyeCandidate : representation.mCandidates) {
- mCandidates.add(redEyeCandidate);
- }
- }
- }
-
- public void removeCandidate(RedEyeCandidate c) {
- this.mCandidates.remove(c);
- }
-
- public void clearCandidates() {
- this.mCandidates.clear();
- }
-
- public int getNumberOfCandidates() {
- if (mCandidates == null) {
- return 0;
- }
- return mCandidates.size();
- }
-
public void addRect(RectF rect, RectF bounds) {
- if (!hasCandidates()) {
- setCandidates(new Vector<RedEyeCandidate>());
- }
Vector<RedEyeCandidate> intersects = new Vector<RedEyeCandidate>();
for (int i = 0; i < getCandidates().size(); i++) {
- RedEyeCandidate r = getCandidate(i);
+ RedEyeCandidate r = (RedEyeCandidate) getCandidate(i);
if (r.intersect(rect)) {
intersects.add(r);
}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
new file mode 100644
index 000000000..eef54ef58
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.filtershow.filters;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorVignette;
+import com.android.gallery3d.filtershow.imageshow.Oval;
+
+public class FilterVignetteRepresentation extends FilterBasicRepresentation implements Oval {
+ private static final String LOGTAG = "FilterVignetteRepresentation";
+ private float mCenterX = Float.NaN;
+ private float mCenterY;
+ private float mRadiusX = Float.NaN;
+ private float mRadiusY;
+
+ public FilterVignetteRepresentation() {
+ super("Vignette", -100, 50, 100);
+ setShowParameterValue(true);
+ setPriority(FilterRepresentation.TYPE_VIGNETTE);
+ setTextId(R.string.vignette);
+ setButtonId(R.id.vignetteEditor);
+ setEditorId(EditorVignette.ID);
+ setName("Vignette");
+ setFilterClass(ImageFilterVignette.class);
+
+ setMinimum(-100);
+ setMaximum(100);
+ setDefaultValue(0);
+ }
+
+ @Override
+ public void useParametersFrom(FilterRepresentation a) {
+ super.useParametersFrom(a);
+ mCenterX = ((FilterVignetteRepresentation) a).mCenterX;
+ mCenterY = ((FilterVignetteRepresentation) a).mCenterY;
+ mRadiusX = ((FilterVignetteRepresentation) a).mRadiusX;
+ mRadiusY = ((FilterVignetteRepresentation) a).mRadiusY;
+ }
+
+ @Override
+ public FilterRepresentation clone() throws CloneNotSupportedException {
+ FilterVignetteRepresentation representation = (FilterVignetteRepresentation) super
+ .clone();
+ representation.mCenterX = mCenterX;
+ representation.mCenterY = mCenterY;
+
+ return representation;
+ }
+
+ @Override
+ public void setCenter(float centerX, float centerY) {
+ mCenterX = centerX;
+ mCenterY = centerY;
+ }
+
+ @Override
+ public float getCenterX() {
+ return mCenterX;
+ }
+
+ @Override
+ public float getCenterY() {
+ return mCenterY;
+ }
+
+ @Override
+ public void setRadius(float radiusX, float radiusY) {
+ mRadiusX = radiusX;
+ mRadiusY = radiusY;
+ }
+
+ @Override
+ public void setRadiusX(float radiusX) {
+ mRadiusX = radiusX;
+ }
+
+ @Override
+ public void setRadiusY(float radiusY) {
+ mRadiusY = radiusY;
+ }
+
+ @Override
+ public float getRadiusX() {
+ return mRadiusX;
+ }
+
+ @Override
+ public float getRadiusY() {
+ return mRadiusY;
+ }
+
+ public boolean isCenterSet() {
+ return mCenterX != Float.NaN;
+ }
+
+ @Override
+ public boolean isNil() {
+ return getValue() == 0;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index 7c5a75232..614c6a01d 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -17,9 +17,11 @@
package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.editors.BasicEditor;
+import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
import com.android.gallery3d.filtershow.presets.ImagePreset;
public abstract class ImageFilter implements Cloneable {
@@ -67,4 +69,12 @@ public abstract class ImageFilter implements Cloneable {
return null;
}
+ protected Matrix getOriginalToScreenMatrix(int w, int h) {
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ Matrix originalToScreen = geo.getOriginalToScreen(true,
+ getImagePreset().getImageLoader().getOriginalBounds().width(),
+ getImagePreset().getImageLoader().getOriginalBounds().height(),
+ w, h);
+ return originalToScreen;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
index 4b21d3595..6d7614ec9 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java
@@ -267,11 +267,8 @@ public class ImageFilterDraw extends ImageFilter {
public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- ImagePreset imgPreset = getImagePreset();
- Rect bounds = imgPreset.getImageLoader().getOriginalBounds();
- Matrix m = imgPreset.mGeoData.getOriginalToScreen(true,
- bounds.width(),
- bounds.height(), w, h);
+
+ Matrix m = getOriginalToScreenMatrix(w, h);
drawData(new Canvas(bitmap), m, quality);
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
index 42587c06f..511f9e90f 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -17,14 +17,8 @@
package com.android.gallery3d.filtershow.filters;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.Log;
-
-import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
import java.util.Vector;
@@ -42,23 +36,14 @@ public class ImageFilterRedEye extends ImageFilter {
}
public boolean isNil() {
- if (mParameters.getCandidates() != null && mParameters.getCandidates().size() > 0) {
- return false;
- }
- return true;
+ return mParameters.isNil();
}
- public Vector<RedEyeCandidate> getCandidates() {
- if (!mParameters.hasCandidates()) {
- mParameters.setCandidates(new Vector<RedEyeCandidate>());
- }
+ public Vector<FilterPoint> getCandidates() {
return mParameters.getCandidates();
}
public void clear() {
- if (!mParameters.hasCandidates()) {
- mParameters.setCandidates(new Vector<RedEyeCandidate>());
- }
mParameters.clearCandidates();
}
@@ -75,46 +60,19 @@ public class ImageFilterRedEye extends ImageFilter {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
short[] rect = new short[4];
+
int size = mParameters.getNumberOfCandidates();
+ Matrix originalToScreen = getOriginalToScreenMatrix(w, h);
for (int i = 0; i < size; i++) {
- RectF r = new RectF(mParameters.getCandidate(i).mRect);
- GeometryMetadata geo = getImagePreset().mGeoData;
- Matrix originalToScreen = geo.getOriginalToScreen(true,
- getImagePreset().getImageLoader().getOriginalBounds().width(),
- getImagePreset().getImageLoader().getOriginalBounds().height(),
- w, h);
+ RectF r = new RectF(((RedEyeCandidate) (mParameters.getCandidate(i))).mRect);
originalToScreen.mapRect(r);
- if (r.left < 0) {
- r.left = 0;
- }
- if (r.left > w) {
- r.left = w;
- }
- if (r.top < 0) {
- r.top = 0;
+ if (r.intersect(0, 0, w, h)) {
+ rect[0] = (short) r.left;
+ rect[1] = (short) r.top;
+ rect[2] = (short) r.width();
+ rect[3] = (short) r.height();
+ nativeApplyFilter(bitmap, w, h, rect);
}
- if (r.top > h) {
- r.top = h;
- }
- if (r.right < 0) {
- r.right = 0;
- }
- if (r.right > w) {
- r.right = w;
- }
- if (r.bottom < 0) {
- r.bottom = 0;
- }
- if (r.bottom > h) {
- r.bottom = h;
- }
-
- rect[0] = (short) r.left;
- rect[1] = (short) r.top;
- rect[2] = (short) r.width();
- rect[3] = (short) r.height();
-
- nativeApplyFilter(bitmap, w, h, rect);
}
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
index 465d90bfd..9ff737e32 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java
@@ -16,47 +16,67 @@
package com.android.gallery3d.filtershow.filters;
-import com.android.gallery3d.R;
-
import android.graphics.Bitmap;
+import android.graphics.Matrix;
+
import com.android.gallery3d.app.Log;
public class ImageFilterVignette extends SimpleImageFilter {
-
private static final String LOGTAG = "ImageFilterVignette";
public ImageFilterVignette() {
mName = "Vignette";
}
+ @Override
public FilterRepresentation getDefaultRepresentation() {
- FilterBasicRepresentation representation =
- (FilterBasicRepresentation) super.getDefaultRepresentation();
- representation.setName("Vignette");
- representation.setFilterClass(ImageFilterVignette.class);
- representation.setPriority(FilterRepresentation.TYPE_VIGNETTE);
- representation.setTextId(R.string.vignette);
- representation.setButtonId(R.id.vignetteButton);
-
- representation.setMinimum(-100);
- representation.setMaximum(100);
- representation.setDefaultValue(0);
-
+ FilterVignetteRepresentation representation = new FilterVignetteRepresentation();
return representation;
}
- native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength);
+ native protected void nativeApplyFilter(
+ Bitmap bitmap, int w, int h, int cx, int cy, float radx, float rady, float strength);
+
+ private float calcRadius(float cx, float cy, int w, int h) {
+ float d = cx;
+ if (d < (w - cx)) {
+ d = w - cx;
+ }
+ if (d < cy) {
+ d = cy;
+ }
+ if (d < (h - cy)) {
+ d = h - cy;
+ }
+ return d * d * 2.0f;
+ }
@Override
public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
- if (getParameters() == null) {
+ FilterVignetteRepresentation rep = (FilterVignetteRepresentation) getParameters();
+ if (rep == null) {
return bitmap;
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
- float value = getParameters().getValue() / 100.0f;
- nativeApplyFilter(bitmap, w, h, value);
-
+ float value = rep.getValue() / 100.0f;
+ float cx = w / 2;
+ float cy = h / 2;
+ float r = calcRadius(cx, cy, w, h);
+ float rx = r;
+ float ry = r;
+ if (rep.isCenterSet()) {
+ Matrix m = getOriginalToScreenMatrix(w, h);
+ cx = rep.getCenterX();
+ cy = rep.getCenterY();
+ float[] center = new float[] { cx, cy };
+ m.mapPoints(center);
+ cx = center[0];
+ cy = center[1];
+ rx = m.mapRadius(rep.getRadiusX());
+ ry = m.mapRadius(rep.getRadiusY());
+ }
+ nativeApplyFilter(bitmap, w, h, (int) cx, (int) cy, rx, ry, value);
return bitmap;
}
}
diff --git a/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java
index 58d3afa3b..a40d4fa3b 100644
--- a/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java
+++ b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -18,7 +18,7 @@ package com.android.gallery3d.filtershow.filters;
import android.graphics.RectF;
-public class RedEyeCandidate {
+public class RedEyeCandidate implements FilterPoint {
RectF mRect = new RectF();
RectF mBounds = new RectF();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java
new file mode 100644
index 000000000..b4ca8e1f1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader;
+
+import com.android.gallery3d.R;
+
+public class EclipseControl {
+ private float mCenterX = Float.NaN;
+ private float mCenterY = 0;
+ private float mRadiusX = 200;
+ private float mRadiusY = 300;
+ private static int MIN_TOUCH_DIST = 80;// should be a resource & in dips
+
+ private float[] handlex = new float[9];
+ private float[] handley = new float[9];
+ private int mSliderColor;
+ private int mCenterDotSize = 40;
+ private float mDownX;
+ private float mDownY;
+ private float mDownCenterX;
+ private float mDownCenterY;
+ private float mDownRadiusX;
+ private float mDownRadiusY;
+ private Matrix mScrToImg;
+
+ private final static int HAN_CENTER = 0;
+ private final static int HAN_NORTH = 7;
+ private final static int HAN_NE = 8;
+ private final static int HAN_EAST = 1;
+ private final static int HAN_SE = 2;
+ private final static int HAN_SOUTH = 3;
+ private final static int HAN_SW = 4;
+ private final static int HAN_WEST = 5;
+ private final static int HAN_NW = 6;
+
+ public EclipseControl(Context context) {
+ mSliderColor = context.getResources().getColor(R.color.slider_line_color);
+ }
+
+ public void setRadius(float x, float y) {
+ mRadiusX = x;
+ mRadiusY = y;
+ }
+
+ public void setCenter(float x, float y) {
+ mCenterX = x;
+ mCenterY = y;
+ }
+
+ public int getCloseHandle(float x, float y) {
+ float min = Float.MAX_VALUE;
+ int handle = -1;
+ for (int i = 0; i < handlex.length; i++) {
+ float dx = handlex[i] - x;
+ float dy = handley[i] - y;
+ float dist = dx * dx + dy * dy;
+ if (dist < min) {
+ min = dist;
+ handle = i;
+ }
+ }
+
+ if (min < MIN_TOUCH_DIST * MIN_TOUCH_DIST) {
+ return handle;
+ }
+ for (int i = 0; i < handlex.length; i++) {
+ float dx = handlex[i] - x;
+ float dy = handley[i] - y;
+ float dist = (float) Math.sqrt(dx * dx + dy * dy);
+ }
+
+ return -1;
+ }
+
+ public void setScrToImageMatrix(Matrix scrToImg) {
+ mScrToImg = scrToImg;
+ }
+
+ public void actionDown(float x, float y, Oval oval) {
+ float[] point = new float[] {
+ x, y };
+ mScrToImg.mapPoints(point);
+ mDownX = point[0];
+ mDownY = point[1];
+ mDownCenterX = oval.getCenterX();
+ mDownCenterY = oval.getCenterY();
+ mDownRadiusX = oval.getRadiusX();
+ mDownRadiusY = oval.getRadiusY();
+ }
+
+ public void actionMove(int handle, float x, float y, Oval oval) {
+ float[] point = new float[] {
+ x, y };
+ mScrToImg.mapPoints(point);
+ x = point[0];
+ y = point[1];
+ int sign = 1;
+ switch (handle) {
+ case HAN_CENTER:
+ float ctrdx = mDownX - mDownCenterX;
+ float ctrdy = mDownY - mDownCenterY;
+ oval.setCenter(x - ctrdx, y - ctrdy);
+ // setRepresentation(mVignetteRep);
+ break;
+ case HAN_NORTH:
+ sign = -1;
+ case HAN_SOUTH:
+ float raddy = mDownRadiusY - Math.abs(mDownY - mDownCenterY);
+ oval.setRadiusY(Math.abs(y - oval.getCenterY() + sign * raddy));
+ break;
+ case HAN_EAST:
+ sign = -1;
+ case HAN_WEST:
+ float raddx = mDownRadiusX - Math.abs(mDownX - mDownCenterX);
+ oval.setRadiusX(Math.abs(x - oval.getCenterX() - sign * raddx));
+ break;
+ case HAN_SE:
+ case HAN_NE:
+ case HAN_SW:
+ case HAN_NW:
+ float sin45 = (float) Math.sin(45);
+ float dr = (mDownRadiusX + mDownRadiusY) * sin45;
+ float ctr_dx = mDownX - mDownCenterX;
+ float ctr_dy = mDownY - mDownCenterY;
+ float downRad = Math.abs(ctr_dx) + Math.abs(ctr_dy) - dr;
+ float rx = oval.getRadiusX();
+ float ry = oval.getRadiusY();
+ float r = (Math.abs(rx) + Math.abs(ry)) * sin45;
+ float dx = x - oval.getCenterX();
+ float dy = y - oval.getCenterY();
+ float nr = Math.abs(Math.abs(dx) + Math.abs(dy) - downRad);
+ oval.setRadius(rx * nr / r, ry * nr / r);
+
+ break;
+ }
+ }
+
+ void paintPoint(Canvas canvas, float x, float y) {
+ if (x == Float.NaN) {
+ return;
+ }
+
+ Paint paint = new Paint();
+
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(Color.BLUE);
+ int[] colors3 = new int[] {
+ mSliderColor, mSliderColor, 0x66000000, 0 };
+ RadialGradient g = new RadialGradient(x, y, mCenterDotSize, colors3, new float[] {
+ 0, .3f, .31f, 1 }, Shader.TileMode.CLAMP);
+ paint.setShader(g);
+ canvas.drawCircle(x, y, mCenterDotSize, paint);
+ }
+
+ void paintRadius(Canvas canvas, float cx, float cy, float rx, float ry) {
+ if (cx == Float.NaN) {
+ return;
+ }
+ int mSliderColor = 0xFF33B5E5;
+ Paint paint = new Paint();
+ RectF rect = new RectF(cx - rx, cy - ry, cx + rx, cy + ry);
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(6);
+ paint.setColor(Color.BLACK);
+ paintOvallines(canvas, rect, paint, cx, cy, rx, ry);
+
+ paint.setStrokeWidth(3);
+ paint.setColor(Color.WHITE);
+ paintOvallines(canvas, rect, paint, cx, cy, rx, ry);
+ }
+
+ public void paintOvallines(
+ Canvas canvas, RectF rect, Paint paint, float cx, float cy, float rx, float ry) {
+ canvas.drawOval(rect, paint);
+ float da = 4;
+ float arclen = da + da;
+ for (int i = 0; i < 361; i += 90) {
+ float dx = rx + 10;
+ float dy = ry + 10;
+ rect.left = cx - dx;
+ rect.top = cy - dy;
+ rect.right = cx + dx;
+ rect.bottom = cy + dy;
+ canvas.drawArc(rect, i - da, arclen, false, paint);
+ dx = rx - 10;
+ dy = ry - 10;
+ rect.left = cx - dx;
+ rect.top = cy - dy;
+ rect.right = cx + dx;
+ rect.bottom = cy + dy;
+ canvas.drawArc(rect, i - da, arclen, false, paint);
+ }
+ da *= 2;
+ for (int i = 45; i < 361; i += 90) {
+ double angle = Math.PI * i / 180.;
+ float x = cx + (float) (rx * Math.cos(angle));
+ float y = cy + (float) (ry * Math.sin(angle));
+ canvas.drawRect(x - da, y - da, x + da, y + da, paint);
+ }
+ rect.left = cx - rx;
+ rect.top = cy - ry;
+ rect.right = cx + rx;
+ rect.bottom = cy + ry;
+ }
+
+ public void fillHandles(Canvas canvas, float cx, float cy, float rx, float ry) {
+ handlex[0] = cx;
+ handley[0] = cy;
+ int k = 1;
+
+ for (int i = 0; i < 360; i += 45) {
+ double angle = Math.PI * i / 180.;
+
+ float x = cx + (float) (rx * Math.cos(angle));
+ float y = cy + (float) (ry * Math.sin(angle));
+ handlex[k] = x;
+ handley[k] = y;
+
+ k++;
+ }
+ }
+
+ public void draw(Canvas canvas) {
+ paintRadius(canvas, mCenterX, mCenterY, mRadiusX, mRadiusY);
+ fillHandles(canvas, mCenterX, mCenterY, mRadiusX, mRadiusY);
+ paintPoint(canvas, mCenterX, mCenterY);
+ }
+
+ public boolean isUndefined() {
+ return Float.isNaN(mCenterX);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java b/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
new file mode 100644
index 000000000..625cdbe0d
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImagePoint.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 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.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.filtershow.editors.EditorRedEye;
+import com.android.gallery3d.filtershow.filters.FilterPoint;
+import com.android.gallery3d.filtershow.filters.FilterRedEyeRepresentation;
+import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
+import com.android.gallery3d.filtershow.filters.RedEyeCandidate;
+
+public abstract class ImagePoint extends ImageShow {
+
+ private static final String LOGTAG = "ImageRedEyes";
+ protected EditorRedEye mEditorRedEye;
+ protected FilterRedEyeRepresentation mRedEyeRep;
+ protected static float mTouchPadding = 80;
+
+ public static void setTouchPadding(float padding) {
+ mTouchPadding = padding;
+ }
+
+ public ImagePoint(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ImagePoint(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void resetParameter() {
+ ImageFilterRedEye filter = (ImageFilterRedEye) getCurrentFilter();
+ if (filter != null) {
+ filter.clear();
+ }
+ invalidate();
+ }
+
+ @Override
+ public void updateImage() {
+ super.updateImage();
+ invalidate();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ Paint paint = new Paint();
+ paint.setStyle(Style.STROKE);
+ paint.setColor(Color.RED);
+ paint.setStrokeWidth(2);
+
+ Matrix originalToScreen = getImageToScreenMatrix(false);
+ Matrix originalRotateToScreen = getImageToScreenMatrix(true);
+
+ if (mRedEyeRep != null) {
+ for (FilterPoint candidate : mRedEyeRep.getCandidates()) {
+ drawPoint(candidate, canvas, originalToScreen, originalRotateToScreen, paint);
+ }
+ }
+ }
+
+ protected abstract void drawPoint(
+ FilterPoint candidate, Canvas canvas, Matrix originalToScreen,
+ Matrix originalRotateToScreen, Paint paint);
+
+ public void setEditor(EditorRedEye editorRedEye) {
+ mEditorRedEye = editorRedEye;
+ }
+
+ public void setRepresentation(FilterRedEyeRepresentation redEyeRep) {
+ mRedEyeRep = redEyeRep;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java
index ba3dcdd1d..9e667986e 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2013 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.gallery3d.filtershow.imageshow;
@@ -8,30 +23,14 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
-import com.android.gallery3d.filtershow.editors.EditorRedEye;
-import com.android.gallery3d.filtershow.filters.FilterRedEyeRepresentation;
-import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
+import com.android.gallery3d.filtershow.filters.FilterPoint;
import com.android.gallery3d.filtershow.filters.RedEyeCandidate;
-public class ImageRedEye extends ImageShow {
-
+public class ImageRedEye extends ImagePoint {
private static final String LOGTAG = "ImageRedEyes";
private RectF mCurrentRect = null;
- private EditorRedEye mEditorRedEye;
- private FilterRedEyeRepresentation mRedEyeRep;
- private static float mTouchPadding = 80;
-
- public static void setTouchPadding(float padding) {
- mTouchPadding = padding;
- }
-
- public ImageRedEye(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
public ImageRedEye(Context context) {
super(context);
@@ -39,21 +38,12 @@ public class ImageRedEye extends ImageShow {
@Override
public void resetParameter() {
- ImageFilterRedEye filter = (ImageFilterRedEye) getCurrentFilter();
- if (filter != null) {
- filter.clear();
- }
- mCurrentRect = null;
+ super.resetParameter();
invalidate();
}
@Override
- public void updateImage() {
- super.updateImage();
- invalidate();
- }
- @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
float ex = event.getX();
@@ -72,16 +62,8 @@ public class ImageRedEye extends ImageShow {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (mCurrentRect != null) {
// transform to original coordinates
- GeometryMetadata geo = getImagePreset().mGeoData;
- Matrix originalToScreen = geo.getOriginalToScreen(true,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(),
- getWidth(), getHeight());
- Matrix originalNoRotateToScreen = geo.getOriginalToScreen(false,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(),
- getWidth(), getHeight());
-
+ Matrix originalNoRotateToScreen = getImageToScreenMatrix(false);
+ Matrix originalToScreen = getImageToScreenMatrix(true);
Matrix invert = new Matrix();
originalToScreen.invert(invert);
RectF r = new RectF(mCurrentRect);
@@ -112,49 +94,35 @@ public class ImageRedEye extends ImageShow {
RectF drawRect = new RectF(mCurrentRect);
canvas.drawRect(drawRect, paint);
}
-
- GeometryMetadata geo = getImagePreset().mGeoData;
- Matrix originalToScreen = geo.getOriginalToScreen(false,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
- Matrix originalRotateToScreen = geo.getOriginalToScreen(true,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
- if (mRedEyeRep != null) {
- for (RedEyeCandidate candidate : mRedEyeRep.getCandidates()) {
- RectF rect = candidate.getRect();
- RectF drawRect = new RectF();
- originalToScreen.mapRect(drawRect, rect);
- RectF fullRect = new RectF();
- originalRotateToScreen.mapRect(fullRect, rect);
- paint.setColor(Color.BLUE);
- canvas.drawRect(fullRect, paint);
- canvas.drawLine(fullRect.centerX(), fullRect.top,
- fullRect.centerX(), fullRect.bottom, paint);
- canvas.drawLine(fullRect.left, fullRect.centerY(),
- fullRect.right, fullRect.centerY(), paint);
- paint.setColor(Color.GREEN);
- float dw = drawRect.width();
- float dh = drawRect.height();
- float dx = fullRect.centerX() - dw / 2;
- float dy = fullRect.centerY() - dh / 2;
- drawRect.set(dx, dy, dx + dw, dy + dh);
- canvas.drawRect(drawRect, paint);
- canvas.drawLine(drawRect.centerX(), drawRect.top,
- drawRect.centerX(), drawRect.bottom, paint);
- canvas.drawLine(drawRect.left, drawRect.centerY(),
- drawRect.right, drawRect.centerY(), paint);
- canvas.drawCircle(drawRect.centerX(), drawRect.centerY(),
- mTouchPadding, paint);
- }
- }
- }
-
- public void setEditor(EditorRedEye editorRedEye) {
- mEditorRedEye = editorRedEye;
}
- public void setRepresentation(FilterRedEyeRepresentation redEyeRep) {
- mRedEyeRep = redEyeRep;
+ @Override
+ protected void drawPoint(FilterPoint point, Canvas canvas, Matrix originalToScreen,
+ Matrix originalRotateToScreen, Paint paint) {
+ RedEyeCandidate candidate = (RedEyeCandidate) point;
+ RectF rect = candidate.getRect();
+ RectF drawRect = new RectF();
+ originalToScreen.mapRect(drawRect, rect);
+ RectF fullRect = new RectF();
+ originalRotateToScreen.mapRect(fullRect, rect);
+ paint.setColor(Color.BLUE);
+ canvas.drawRect(fullRect, paint);
+ canvas.drawLine(fullRect.centerX(), fullRect.top,
+ fullRect.centerX(), fullRect.bottom, paint);
+ canvas.drawLine(fullRect.left, fullRect.centerY(),
+ fullRect.right, fullRect.centerY(), paint);
+ paint.setColor(Color.GREEN);
+ float dw = drawRect.width();
+ float dh = drawRect.height();
+ float dx = fullRect.centerX() - dw / 2;
+ float dy = fullRect.centerY() - dh / 2;
+ drawRect.set(dx, dy, dx + dw, dy + dh);
+ canvas.drawRect(drawRect, paint);
+ canvas.drawLine(drawRect.centerX(), drawRect.top,
+ drawRect.centerX(), drawRect.bottom, paint);
+ canvas.drawLine(drawRect.left, drawRect.centerY(),
+ drawRect.right, drawRect.centerY(), paint);
+ canvas.drawCircle(drawRect.centerX(), drawRect.centerY(),
+ mTouchPadding, paint);
}
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 2d50d116f..a215465c0 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -269,6 +270,34 @@ public class ImageShow extends View implements OnGestureListener,
return GeometryMath.roundNearest(getImagePreset().mGeoData.getPreviewCropBounds());
}
+ /* consider moving the following 2 methods into a subclass */
+ /**
+ * This function calculates a Image to Screen Transformation matrix
+ *
+ * @param reflectRotation set true if you want the rotation encoded
+ * @return Image to Screen transformation matrix
+ */
+ protected Matrix getImageToScreenMatrix(boolean reflectRotation) {
+ GeometryMetadata geo = getImagePreset().mGeoData;
+ Matrix m = geo.getOriginalToScreen(reflectRotation,
+ mImageLoader.getOriginalBounds().width(),
+ mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
+ return m;
+ }
+
+ /**
+ * This function calculates a to Screen Image Transformation matrix
+ *
+ * @param reflectRotation set true if you want the rotation encoded
+ * @return Screen to Image transformation matrix
+ */
+ protected Matrix getScreenToImageMatrix(boolean reflectRotation) {
+ Matrix m = getImageToScreenMatrix(reflectRotation);
+ Matrix invert = new Matrix();
+ m.invert(invert);
+ return invert;
+ }
+
public Rect getDisplayedImageBounds() {
return mImageBounds;
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java
index 3e95d4e15..3795d1f21 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTinyPlanet.java
@@ -22,6 +22,7 @@ import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import com.android.gallery3d.filtershow.editors.BasicEditor;
import com.android.gallery3d.filtershow.editors.EditorTinyPlanet;
import com.android.gallery3d.filtershow.filters.FilterCurvesRepresentation;
import com.android.gallery3d.filtershow.filters.FilterTinyPlanetRepresentation;
@@ -37,7 +38,7 @@ public class ImageTinyPlanet extends ImageShow {
private float mCenterY = 0;
private float mStartAngle = 0;
private FilterTinyPlanetRepresentation mTinyPlanetRep;
- private EditorTinyPlanet mEditorTinyPlanet;
+ private BasicEditor mEditorTinyPlanet;
public ImageTinyPlanet(Context context) {
super(context);
@@ -94,7 +95,7 @@ public class ImageTinyPlanet extends ImageShow {
mTinyPlanetRep = tinyPlanetRep;
}
- public void setEditor(EditorTinyPlanet editorTinyPlanet) {
+ public void setEditor(BasicEditor editorTinyPlanet) {
mEditorTinyPlanet = editorTinyPlanet;
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
new file mode 100644
index 000000000..729ac7f41
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.filtershow.editors.EditorVignette;
+import com.android.gallery3d.filtershow.filters.FilterVignetteRepresentation;
+
+public class ImageVignette extends ImageShow {
+ private static final String LOGTAG = "ImageVignette";
+
+ private FilterVignetteRepresentation mVignetteRep;
+ private EditorVignette mEditorVignette;
+
+ private int mActiveHandle = -1;
+
+ EclipseControl mElipse;
+
+ public ImageVignette(Context context) {
+ super(context);
+ mElipse = new EclipseControl(context);
+ }
+
+ public ImageVignette(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mElipse = new EclipseControl(context);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int mask = event.getActionMasked();
+ if (MotionEvent.ACTION_UP == mask) {
+ mActiveHandle = -1;
+ }
+ if (MotionEvent.ACTION_DOWN == mask && event.getPointerCount() == 1) {
+ mActiveHandle = mElipse.getCloseHandle(event.getX(), event.getY());
+ }
+ if (mActiveHandle == -1 || event.getPointerCount() > 1) {
+ mActiveHandle = -1;
+
+ return super.onTouchEvent(event);
+ }
+ float x = event.getX();
+ float y = event.getY();
+
+ mElipse.setScrToImageMatrix(getScreenToImageMatrix(true));
+
+ switch (mask) {
+ case (MotionEvent.ACTION_DOWN):
+ mElipse.actionDown(x, y, mVignetteRep);
+ break;
+ case (MotionEvent.ACTION_UP):
+ case (MotionEvent.ACTION_MOVE):
+
+ mElipse.actionMove(mActiveHandle, x, y, mVignetteRep);
+ setRepresentation(mVignetteRep);
+ break;
+ }
+ resetImageCaches(this);
+ invalidate();
+ mEditorVignette.commitLocalRepresentation();
+ return true;
+ }
+
+ public void setRepresentation(FilterVignetteRepresentation vignetteRep) {
+ mVignetteRep = vignetteRep;
+ Matrix toImg = getScreenToImageMatrix(false);
+ Matrix toScr = new Matrix();
+ toImg.invert(toScr);
+
+ float[] c = new float[] {
+ mVignetteRep.getCenterX(), mVignetteRep.getCenterY() };
+ if (Float.isNaN(c[0])) {
+ float cx = mImageLoader.getOriginalBounds().width() / 2;
+ float cy = mImageLoader.getOriginalBounds().height() / 2;
+ float rx = Math.min(cx, cy) * .8f;
+ float ry = rx;
+ mVignetteRep.setCenter(cx, cy);
+ mVignetteRep.setRadius(rx, ry);
+
+ c[0] = cx;
+ c[1] = cy;
+ toScr.mapPoints(c);
+ if (getWidth() != 0) {
+ mElipse.setCenter(c[0], c[1]);
+ mElipse.setRadius(c[0] * 0.8f, c[1] * 0.8f);
+ }
+ } else {
+
+ toScr.mapPoints(c);
+
+ mElipse.setCenter(c[0], c[1]);
+ mElipse.setRadius(toScr.mapRadius(mVignetteRep.getRadiusX()),
+ toScr.mapRadius(mVignetteRep.getRadiusY()));
+ }
+ }
+
+ public void setEditor(EditorVignette editorVignette) {
+ mEditorVignette = editorVignette;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mElipse.isUndefined()) {
+ setRepresentation(mVignetteRep);
+ }
+ mElipse.draw(canvas);
+
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/Oval.java b/src/com/android/gallery3d/filtershow/imageshow/Oval.java
new file mode 100644
index 000000000..28f278f1c
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/Oval.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.filtershow.imageshow;
+
+public interface Oval {
+ void setCenter(float x, float y);
+ void setRadius(float w, float h);
+ float getCenterX();
+ float getCenterY();
+ float getRadiusX();
+ float getRadiusY();
+ void setRadiusY(float y);
+ void setRadiusX(float x);
+
+}
diff --git a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
index 88645e8d0..46a2051be 100644
--- a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
+++ b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
@@ -43,6 +43,7 @@ public class MtpBitmapFetch {
public static Bitmap getThumbnail(MtpDevice device, MtpObjectInfo info) {
byte[] imageBytes = device.getThumbnail(info.getObjectHandle());
+ if (imageBytes == null) return null;
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
@@ -60,6 +61,7 @@ public class MtpBitmapFetch {
public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info, int maxSide) {
byte[] imageBytes = device.getObject(info.getObjectHandle(), info.getCompressedSize());
+ if (imageBytes == null) return null;
Bitmap created;
if (maxSide > 0) {
BitmapFactory.Options o = new BitmapFactory.Options();
diff --git a/src/com/android/gallery3d/ingest/ui/MtpImageView.java b/src/com/android/gallery3d/ingest/ui/MtpImageView.java
index 9c197851e..5664d8a34 100644
--- a/src/com/android/gallery3d/ingest/ui/MtpImageView.java
+++ b/src/com/android/gallery3d/ingest/ui/MtpImageView.java
@@ -19,19 +19,32 @@ package com.android.gallery3d.ingest.ui;
import android.content.Context;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
-import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.android.gallery3d.ingest.data.BitmapWithMetadata;
import com.android.gallery3d.ingest.data.MtpBitmapFetch;
-public class MtpImageView extends ImageView {
- private static final int FADE_IN_TIME_MS = 80;
+import java.lang.ref.WeakReference;
+public class MtpImageView extends ImageView {
private int mObjectHandle;
private int mGeneration;
+ private WeakReference<MtpImageView> mWeakReference = new WeakReference<MtpImageView>(this);
+ private Object mFetchLock = new Object();
+ private boolean mFetchPending = false;
+ private MtpObjectInfo mFetchObjectInfo;
+ private MtpDevice mFetchDevice;
+ private Object mFetchResult;
+
+ private static final FetchImageHandler sFetchHandler = FetchImageHandler.createOnNewThread();
+ private static final ShowImageHandler sFetchCompleteHandler = new ShowImageHandler();
+
private void init() {
showPlaceholder();
}
@@ -55,8 +68,6 @@ public class MtpImageView extends ImageView {
setImageResource(android.R.color.transparent);
}
- private LoadMtpImageTask mTask;
-
public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) {
int handle = object.getObjectHandle();
if (handle == mObjectHandle && gen == mGeneration) {
@@ -66,8 +77,14 @@ public class MtpImageView extends ImageView {
showPlaceholder();
mGeneration = gen;
mObjectHandle = handle;
- mTask = new LoadMtpImageTask(device);
- mTask.execute(object);
+ synchronized (mFetchLock) {
+ mFetchObjectInfo = object;
+ mFetchDevice = device;
+ if (mFetchPending) return;
+ mFetchPending = true;
+ sFetchHandler.sendMessage(
+ sFetchHandler.obtainMessage(0, mWeakReference));
+ }
}
protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) {
@@ -80,51 +97,71 @@ public class MtpImageView extends ImageView {
setRotation(bitmapWithMetadata.rotationDegrees);
}
- private class LoadMtpImageTask extends AsyncTask<MtpObjectInfo, Void, Object> {
- private MtpDevice mDevice;
-
- public LoadMtpImageTask(MtpDevice device) {
- mDevice = device;
+ protected void cancelLoadingAndClear() {
+ synchronized (mFetchLock) {
+ mFetchDevice = null;
+ mFetchObjectInfo = null;
+ mFetchResult = null;
}
+ setImageResource(android.R.color.transparent);
+ setRotation(0);
+ }
- @Override
- protected Object doInBackground(MtpObjectInfo... args) {
- Object result = null;
- if (!isCancelled()) {
- result = fetchMtpImageDataFromDevice(mDevice, args[0]);
- }
- mDevice = null;
- return result;
+ @Override
+ public void onDetachedFromWindow() {
+ cancelLoadingAndClear();
+ super.onDetachedFromWindow();
+ }
+
+ private static class FetchImageHandler extends Handler {
+ public FetchImageHandler(Looper l) {
+ super(l);
}
- @Override
- protected void onPostExecute(Object result) {
- if (isCancelled() || result == null) {
- return;
- }
- setAlpha(0f);
- onMtpImageDataFetchedFromDevice(result);
- animate().alpha(1f).setDuration(FADE_IN_TIME_MS);
+ public static FetchImageHandler createOnNewThread() {
+ HandlerThread t = new HandlerThread("MtpImageView Fetch");
+ t.start();
+ return new FetchImageHandler(t.getLooper());
}
@Override
- protected void onCancelled() {
+ public void handleMessage(Message msg) {
+ @SuppressWarnings("unchecked")
+ MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get();
+ if (parent == null) return;
+ MtpObjectInfo objectInfo;
+ MtpDevice device;
+ synchronized (parent.mFetchLock) {
+ parent.mFetchPending = false;
+ device = parent.mFetchDevice;
+ objectInfo = parent.mFetchObjectInfo;
+ }
+ if (device == null) return;
+ Object result = parent.fetchMtpImageDataFromDevice(device, objectInfo);
+ if (result == null) return;
+ synchronized (parent.mFetchLock) {
+ if (parent.mFetchObjectInfo != objectInfo) return;
+ parent.mFetchResult = result;
+ parent.mFetchDevice = null;
+ parent.mFetchObjectInfo = null;
+ sFetchCompleteHandler.sendMessage(
+ sFetchCompleteHandler.obtainMessage(0, parent.mWeakReference));
+ }
}
}
- protected void cancelLoadingAndClear() {
- if (mTask != null) {
- mTask.cancel(true);
+ private static class ShowImageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ @SuppressWarnings("unchecked")
+ MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get();
+ if (parent == null) return;
+ Object result;
+ synchronized (parent.mFetchLock) {
+ result = parent.mFetchResult;
+ }
+ if (result == null) return;
+ parent.onMtpImageDataFetchedFromDevice(result);
}
- mTask = null;
- animate().cancel();
- setImageResource(android.R.color.transparent);
- setRotation(0);
- }
-
- @Override
- public void onDetachedFromWindow() {
- cancelLoadingAndClear();
- super.onDetachedFromWindow();
}
}
diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
index 67ccf9c80..92962cbb1 100644
--- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
+++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
@@ -28,6 +28,7 @@ public class EditorManager {
editorPlaceHolder.addEditor(new EditorCurves());
editorPlaceHolder.addEditor(new EditorTinyPlanet());
editorPlaceHolder.addEditor(new EditorDraw());
+ editorPlaceHolder.addEditor(new EditorVignette());
}
}
diff --git a/tests/src/com/android/gallery3d/CameraTestRunner.java b/tests/src/com/android/gallery3d/CameraTestRunner.java
new file mode 100755
index 000000000..503233675
--- /dev/null
+++ b/tests/src/com/android/gallery3d/CameraTestRunner.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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.gallery3d;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import com.android.gallery3d.functional.CameraTest;
+import com.android.gallery3d.functional.ImageCaptureIntentTest;
+import com.android.gallery3d.functional.VideoCaptureIntentTest;
+import com.android.gallery3d.unittest.CameraUnitTest;
+
+import junit.framework.TestSuite;
+
+
+public class CameraTestRunner extends InstrumentationTestRunner {
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(CameraTest.class);
+ suite.addTestSuite(ImageCaptureIntentTest.class);
+ suite.addTestSuite(VideoCaptureIntentTest.class);
+ suite.addTestSuite(CameraUnitTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return CameraTestRunner.class.getClassLoader();
+ }
+}
diff --git a/tests/src/com/android/gallery3d/StressTests.java b/tests/src/com/android/gallery3d/StressTests.java
new file mode 100755
index 000000000..32eefdcec
--- /dev/null
+++ b/tests/src/com/android/gallery3d/StressTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 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.gallery3d;
+
+import com.android.gallery3d.stress.CameraLatency;
+import com.android.gallery3d.stress.CameraStartUp;
+import com.android.gallery3d.stress.ImageCapture;
+import com.android.gallery3d.stress.SwitchPreview;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation Test Runner for all Camera tests.
+ *
+ * Running all tests:
+ *
+ * adb shell am instrument \
+ * -e class com.android.gallery3d.StressTests \
+ * -w com.google.android.gallery3d.tests/com.android.gallery3d.stress.CameraStressTestRunner
+ */
+
+public class StressTests extends TestSuite {
+ public static Test suite() {
+ TestSuite result = new TestSuite();
+ result.addTestSuite(CameraLatency.class);
+ result.addTestSuite(CameraStartUp.class);
+ result.addTestSuite(ImageCapture.class);
+ result.addTestSuite(SwitchPreview.class);
+ return result;
+ }
+}
diff --git a/tests/src/com/android/gallery3d/functional/CameraTest.java b/tests/src/com/android/gallery3d/functional/CameraTest.java
new file mode 100644
index 000000000..c293c0d4a
--- /dev/null
+++ b/tests/src/com/android/gallery3d/functional/CameraTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.functional;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Process;
+import android.provider.MediaStore;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class CameraTest extends InstrumentationTestCase {
+ @LargeTest
+ public void testVideoCaptureIntentFdLeak() throws Exception {
+ Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://"
+ + Environment.getExternalStorageDirectory().toString()
+ + "test_fd_leak.3gp"));
+ getInstrumentation().startActivitySync(intent).finish();
+ // Test if the fd is closed.
+ for (File f: new File("/proc/" + Process.myPid() + "/fd").listFiles()) {
+ assertEquals(-1, f.getCanonicalPath().indexOf("test_fd_leak.3gp"));
+ }
+ }
+
+ @LargeTest
+ public void testActivityLeak() throws Exception {
+ checkActivityLeak(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ checkActivityLeak(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+ }
+
+ private void checkActivityLeak(String action) throws Exception {
+ final int TEST_COUNT = 5;
+ Intent intent = new Intent(action);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClass(getInstrumentation().getTargetContext(),
+ CameraActivity.class);
+ ArrayList<WeakReference<Activity>> refs =
+ new ArrayList<WeakReference<Activity>>();
+ for (int i = 0; i < TEST_COUNT; i++) {
+ Activity activity = getInstrumentation().startActivitySync(intent);
+ refs.add(new WeakReference<Activity>(activity));
+ activity.finish();
+ getInstrumentation().waitForIdleSync();
+ activity = null;
+ }
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().runFinalization();
+ Runtime.getRuntime().gc();
+ int refCount = 0;
+ for (WeakReference<Activity> c: refs) {
+ if (c.get() != null) refCount++;
+ }
+ // If applications are leaking activity, every reference is reachable.
+ assertTrue(refCount != TEST_COUNT);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java b/tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java
new file mode 100644
index 000000000..8d394b5db
--- /dev/null
+++ b/tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.functional;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+
+public class ImageCaptureIntentTest extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private Intent mIntent;
+
+ public ImageCaptureIntentTest() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ }
+
+ @LargeTest
+ public void testNoExtraOutput() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ takePicture();
+ pressDone();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_OK, getActivity().getResultCode());
+ Intent resultData = getActivity().getResultData();
+ Bitmap bitmap = (Bitmap) resultData.getParcelableExtra("data");
+ assertNotNull(bitmap);
+ assertTrue(bitmap.getWidth() > 0);
+ assertTrue(bitmap.getHeight() > 0);
+ }
+
+ @LargeTest
+ public void testExtraOutput() throws Exception {
+ File file = new File(Environment.getExternalStorageDirectory(),
+ "test.jpg");
+ BufferedInputStream stream = null;
+ byte[] jpegData;
+
+ try {
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
+ setActivityIntent(mIntent);
+ getActivity();
+
+ takePicture();
+ pressDone();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_OK, getActivity().getResultCode());
+
+ // Verify the jpeg file
+ int fileLength = (int) file.length();
+ assertTrue(fileLength > 0);
+ jpegData = new byte[fileLength];
+ stream = new BufferedInputStream(new FileInputStream(file));
+ stream.read(jpegData);
+ } finally {
+ if (stream != null) stream.close();
+ file.delete();
+ }
+
+ Bitmap b = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
+ assertTrue(b.getWidth() > 0);
+ assertTrue(b.getHeight() > 0);
+ }
+
+ @LargeTest
+ public void testCancel() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ pressCancel();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
+ }
+
+ @LargeTest
+ public void testSnapshotCancel() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ takePicture();
+ pressCancel();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
+ }
+
+ private void takePicture() throws Exception {
+ getInstrumentation().sendKeySync(
+ new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS));
+ getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+ Thread.sleep(4000);
+ }
+
+ private void pressDone() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().findViewById(R.id.btn_done).performClick();
+ }
+ });
+ }
+
+ private void pressCancel() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().findViewById(R.id.btn_cancel).performClick();
+ }
+ });
+ }
+}
diff --git a/tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java b/tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java
new file mode 100644
index 000000000..c8d7bbb1c
--- /dev/null
+++ b/tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.functional;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.R;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Video.VideoColumns;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.File;
+
+public class VideoCaptureIntentTest extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private static final String TAG = "VideoCaptureIntentTest";
+ private Intent mIntent;
+ private Uri mVideoUri;
+ private File mFile, mFile2;
+
+ public VideoCaptureIntentTest() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mVideoUri != null) {
+ ContentResolver resolver = getActivity().getContentResolver();
+ Uri query = mVideoUri.buildUpon().build();
+ String[] projection = new String[] {VideoColumns.DATA};
+
+ Cursor cursor = null;
+ try {
+ cursor = resolver.query(query, projection, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ new File(cursor.getString(0)).delete();
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+
+ resolver.delete(mVideoUri, null, null);
+ }
+ if (mFile != null) mFile.delete();
+ if (mFile2 != null) mFile2.delete();
+ super.tearDown();
+ }
+
+ @LargeTest
+ public void testNoExtraOutput() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo();
+ pressDone();
+
+ Intent resultData = getActivity().getResultData();
+ mVideoUri = resultData.getData();
+ assertNotNull(mVideoUri);
+ verify(getActivity(), mVideoUri);
+ }
+
+ @LargeTest
+ public void testExtraOutput() throws Exception {
+ mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
+
+ Uri uri = Uri.fromFile(mFile);
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo();
+ pressDone();
+
+ verify(getActivity(), uri);
+ }
+
+ @LargeTest
+ public void testCancel() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ pressCancel();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
+ }
+
+ @LargeTest
+ public void testRecordCancel() throws Exception {
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo();
+ pressCancel();
+
+ assertTrue(getActivity().isFinishing());
+ assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
+ }
+
+ @LargeTest
+ public void testExtraSizeLimit() throws Exception {
+ mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
+ final long sizeLimit = 500000; // bytes
+
+ Uri uri = Uri.fromFile(mFile);
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeLimit);
+ mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // use low quality to speed up
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo(5000);
+ pressDone();
+
+ verify(getActivity(), uri);
+ long length = mFile.length();
+ Log.v(TAG, "Video size is " + length + " bytes.");
+ assertTrue(length > 0);
+ assertTrue("Actual size=" + length, length <= sizeLimit);
+ }
+
+ @LargeTest
+ public void testExtraDurationLimit() throws Exception {
+ mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
+ final int durationLimit = 2; // seconds
+
+ Uri uri = Uri.fromFile(mFile);
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, durationLimit);
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo(5000);
+ pressDone();
+
+ int duration = verify(getActivity(), uri);
+ // The duraion should be close to to the limit. The last video duration
+ // also has duration, so the total duration may exceeds the limit a
+ // little bit.
+ Log.v(TAG, "Video length is " + duration + " ms.");
+ assertTrue(duration < (durationLimit + 1) * 1000);
+ }
+
+ @LargeTest
+ public void testExtraVideoQuality() throws Exception {
+ mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
+ mFile2 = new File(Environment.getExternalStorageDirectory(), "video2.tmp");
+
+ Uri uri = Uri.fromFile(mFile);
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // low quality
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo();
+ pressDone();
+
+ verify(getActivity(), uri);
+ setActivity(null);
+
+ uri = Uri.fromFile(mFile2);
+ mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // high quality
+ setActivityIntent(mIntent);
+ getActivity();
+
+ recordVideo();
+ pressDone();
+
+ verify(getActivity(), uri);
+ assertTrue(mFile.length() <= mFile2.length());
+ }
+
+ // Verify result code, result data, and the duration.
+ private int verify(CameraActivity activity, Uri uri) throws Exception {
+ assertTrue(activity.isFinishing());
+ assertEquals(Activity.RESULT_OK, activity.getResultCode());
+
+ // Verify the video file
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(activity, uri);
+ String duration = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_DURATION);
+ assertNotNull(duration);
+ int durationValue = Integer.parseInt(duration);
+ Log.v(TAG, "Video duration is " + durationValue);
+ assertTrue(durationValue > 0);
+ return durationValue;
+ }
+
+ private void recordVideo(int ms) throws Exception {
+ getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+ Thread.sleep(ms);
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ // If recording is in progress, stop it. Run these atomically in
+ // UI thread.
+ CameraActivity activity = getActivity();
+ if (activity.isRecording()) {
+ activity.findViewById(R.id.shutter_button).performClick();
+ }
+ }
+ });
+ }
+
+ private void recordVideo() throws Exception {
+ recordVideo(2000);
+ }
+
+ private void pressDone() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().findViewById(R.id.btn_done).performClick();
+ }
+ });
+ }
+
+ private void pressCancel() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().findViewById(R.id.btn_cancel).performClick();
+ }
+ });
+ }
+}
diff --git a/tests/src/com/android/gallery3d/power/ImageAndVideoCapture.java b/tests/src/com/android/gallery3d/power/ImageAndVideoCapture.java
new file mode 100755
index 000000000..cd5079355
--- /dev/null
+++ b/tests/src/com/android/gallery3d/power/ImageAndVideoCapture.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 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.gallery3d.power;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Instrumentation;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.content.Intent;
+/**
+ * Junit / Instrumentation test case for camera power measurement
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ * -e com.android.camera.power.ImageAndVideoCapture \
+ * -w com.android.camera.tests/android.test.InstrumentationTestRunner
+ *
+ */
+
+public class ImageAndVideoCapture extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private String TAG = "ImageAndVideoCapture";
+ private static final int TOTAL_NUMBER_OF_IMAGECAPTURE = 5;
+ private static final int TOTAL_NUMBER_OF_VIDEOCAPTURE = 5;
+ private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 1500; //1.5 sedconds
+ private static final long WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN = 10000; //10 seconds
+ private static final long WAIT_FOR_PREVIEW = 1500; //1.5 seconds
+ private static final long WAIT_FOR_STABLE_STATE = 2000; //2 seconds
+
+ public ImageAndVideoCapture() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ getActivity();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @LargeTest
+ public void testLaunchCamera() {
+ // This test case capture the baseline for the image preview.
+ try {
+ Thread.sleep(WAIT_FOR_STABLE_STATE);
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ assertTrue("testImageCaptureDoNothing", false);
+ }
+ }
+
+ @LargeTest
+ public void testCapture5Image() {
+ // This test case will use the default camera setting
+ Instrumentation inst = getInstrumentation();
+ try {
+ for (int i = 0; i < TOTAL_NUMBER_OF_IMAGECAPTURE; i++) {
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ }
+ Thread.sleep(WAIT_FOR_STABLE_STATE);
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ assertTrue("testImageCapture", false);
+ }
+ }
+
+ @LargeTest
+ public void testCapture5Videos() {
+ // This test case will use the default camera setting
+ Instrumentation inst = getInstrumentation();
+ try {
+ // Switch to the video mode
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+ intent.setClass(getInstrumentation().getTargetContext(),
+ CameraActivity.class);
+ getActivity().startActivity(intent);
+ for (int i = 0; i < TOTAL_NUMBER_OF_VIDEOCAPTURE; i++) {
+ Thread.sleep(WAIT_FOR_PREVIEW);
+ // record a video
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ Thread.sleep(WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN);
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ Thread.sleep(WAIT_FOR_PREVIEW);
+ }
+ Thread.sleep(WAIT_FOR_STABLE_STATE);
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ assertTrue("testVideoCapture", false);
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/CameraLatency.java b/tests/src/com/android/gallery3d/stress/CameraLatency.java
new file mode 100755
index 000000000..7177abe6c
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/CameraLatency.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2009 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Instrumentation;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ */
+
+public class CameraLatency extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private String TAG = "CameraLatency";
+ private static final int TOTAL_NUMBER_OF_IMAGECAPTURE = 20;
+ private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 4000;
+ private static final String CAMERA_TEST_OUTPUT_FILE =
+ Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+
+ private long mTotalAutoFocusTime;
+ private long mTotalShutterLag;
+ private long mTotalShutterToPictureDisplayedTime;
+ private long mTotalPictureDisplayedToJpegCallbackTime;
+ private long mTotalJpegCallbackFinishTime;
+ private long mAvgAutoFocusTime;
+ private long mAvgShutterLag = mTotalShutterLag;
+ private long mAvgShutterToPictureDisplayedTime;
+ private long mAvgPictureDisplayedToJpegCallbackTime;
+ private long mAvgJpegCallbackFinishTime;
+
+ public CameraLatency() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ getActivity();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @LargeTest
+ public void testImageCapture() {
+ Log.v(TAG, "start testImageCapture test");
+ Instrumentation inst = getInstrumentation();
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ try {
+ for (int i = 0; i < TOTAL_NUMBER_OF_IMAGECAPTURE; i++) {
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ //skip the first measurement
+ if (i != 0) {
+ CameraActivity c = getActivity();
+
+ // if any of the latency var accessor methods return -1 then the
+ // camera is set to a different module other than PhotoModule so
+ // skip the shot and try again
+ if (c.getAutoFocusTime() != -1) {
+ mTotalAutoFocusTime += c.getAutoFocusTime();
+ mTotalShutterLag += c.getShutterLag();
+ mTotalShutterToPictureDisplayedTime +=
+ c.getShutterToPictureDisplayedTime();
+ mTotalPictureDisplayedToJpegCallbackTime +=
+ c.getPictureDisplayedToJpegCallbackTime();
+ mTotalJpegCallbackFinishTime += c.getJpegCallbackFinishTime();
+ }
+ else {
+ i--;
+ continue;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ }
+ //ToDO: yslau
+ //1) Need to get the baseline from the cupcake so that we can add the
+ //failure condition of the camera latency.
+ //2) Only count those number with succesful capture. Set the timer to invalid
+ //before capture and ignore them if the value is invalid
+ int numberofRun = TOTAL_NUMBER_OF_IMAGECAPTURE - 1;
+ mAvgAutoFocusTime = mTotalAutoFocusTime / numberofRun;
+ mAvgShutterLag = mTotalShutterLag / numberofRun;
+ mAvgShutterToPictureDisplayedTime =
+ mTotalShutterToPictureDisplayedTime / numberofRun;
+ mAvgPictureDisplayedToJpegCallbackTime =
+ mTotalPictureDisplayedToJpegCallbackTime / numberofRun;
+ mAvgJpegCallbackFinishTime =
+ mTotalJpegCallbackFinishTime / numberofRun;
+
+ try {
+ FileWriter fstream = null;
+ fstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+ BufferedWriter out = new BufferedWriter(fstream);
+ out.write("Camera Latency : \n");
+ out.write("Number of loop: " + TOTAL_NUMBER_OF_IMAGECAPTURE + "\n");
+ out.write("Avg AutoFocus = " + mAvgAutoFocusTime + "\n");
+ out.write("Avg mShutterLag = " + mAvgShutterLag + "\n");
+ out.write("Avg mShutterToPictureDisplayedTime = "
+ + mAvgShutterToPictureDisplayedTime + "\n");
+ out.write("Avg mPictureDisplayedToJpegCallbackTime = "
+ + mAvgPictureDisplayedToJpegCallbackTime + "\n");
+ out.write("Avg mJpegCallbackFinishTime = " +
+ mAvgJpegCallbackFinishTime + "\n");
+ out.close();
+ fstream.close();
+ } catch (Exception e) {
+ fail("Camera Latency write output to file");
+ }
+ Log.v(TAG, "The Image capture wait time = " +
+ WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ Log.v(TAG, "Avg AutoFocus = " + mAvgAutoFocusTime);
+ Log.v(TAG, "Avg mShutterLag = " + mAvgShutterLag);
+ Log.v(TAG, "Avg mShutterToPictureDisplayedTime = "
+ + mAvgShutterToPictureDisplayedTime);
+ Log.v(TAG, "Avg mPictureDisplayedToJpegCallbackTime = "
+ + mAvgPictureDisplayedToJpegCallbackTime);
+ Log.v(TAG, "Avg mJpegCallbackFinishTime = " + mAvgJpegCallbackFinishTime);
+ }
+}
+
diff --git a/tests/src/com/android/gallery3d/stress/CameraStartUp.java b/tests/src/com/android/gallery3d/stress/CameraStartUp.java
new file mode 100644
index 000000000..8524465ac
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/CameraStartUp.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2009 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
+/**
+ * Test cases to measure the camera and video recorder startup time.
+ */
+public class CameraStartUp extends InstrumentationTestCase {
+
+ private static final int TOTAL_NUMBER_OF_STARTUP = 20;
+
+ private String TAG = "CameraStartUp";
+ private static final String CAMERA_TEST_OUTPUT_FILE =
+ Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+ private static int WAIT_TIME_FOR_PREVIEW = 1500; //1.5 second
+
+ private long launchCamera() {
+ long startupTime = 0;
+ try {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ long beforeStart = System.currentTimeMillis();
+ Instrumentation inst = getInstrumentation();
+ Activity cameraActivity = inst.startActivitySync(intent);
+ long cameraStarted = System.currentTimeMillis();
+ Thread.sleep(WAIT_TIME_FOR_PREVIEW);
+ cameraActivity.finish();
+ startupTime = cameraStarted - beforeStart;
+ Thread.sleep(1000);
+ Log.v(TAG, "camera startup time: " + startupTime);
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ fail("Fails to get the output file");
+ }
+ return startupTime;
+ }
+
+ private long launchVideo() {
+ long startupTime = 0;
+
+ try {
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ long beforeStart = System.currentTimeMillis();
+ Instrumentation inst = getInstrumentation();
+ Activity recorderActivity = inst.startActivitySync(intent);
+ long cameraStarted = System.currentTimeMillis();
+ recorderActivity.finish();
+ startupTime = cameraStarted - beforeStart;
+ Log.v(TAG, "Video Startup Time = " + startupTime);
+ // wait for 1s to make sure it reach a clean stage
+ Thread.sleep(WAIT_TIME_FOR_PREVIEW);
+ Log.v(TAG, "video startup time: " + startupTime);
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception", e);
+ fail("Fails to launch video output file");
+ }
+ return startupTime;
+ }
+
+ private void writeToOutputFile(long totalStartupTime,
+ String individualStartupTime, boolean firstStartUp, String Type) throws Exception {
+ // TODO (yslau) : Need to integrate the output data with central
+ // dashboard
+ try {
+ FileWriter fstream = null;
+ fstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+ BufferedWriter out = new BufferedWriter(fstream);
+ if (firstStartUp) {
+ out.write("First " + Type + " Startup: " + totalStartupTime + "\n");
+ } else {
+ long averageStartupTime = totalStartupTime / (TOTAL_NUMBER_OF_STARTUP -1);
+ out.write(Type + "startup time: " + "\n");
+ out.write("Number of loop: " + (TOTAL_NUMBER_OF_STARTUP -1) + "\n");
+ out.write(individualStartupTime + "\n\n");
+ out.write(Type + " average startup time: " + averageStartupTime + " ms\n\n");
+ }
+ out.close();
+ fstream.close();
+ } catch (Exception e) {
+ fail("Camera write output to file");
+ }
+ }
+
+ @LargeTest
+ public void testLaunchVideo() throws Exception {
+ String individualStartupTime;
+ individualStartupTime = "Individual Video Startup Time = ";
+ long totalStartupTime = 0;
+ long startupTime = 0;
+ for (int i = 0; i < TOTAL_NUMBER_OF_STARTUP; i++) {
+ if (i == 0) {
+ // Capture the first startup time individually
+ long firstStartUpTime = launchVideo();
+ writeToOutputFile(firstStartUpTime, "na", true, "Video");
+ } else {
+ startupTime = launchVideo();
+ totalStartupTime += startupTime;
+ individualStartupTime += startupTime + " ,";
+ }
+ }
+ Log.v(TAG, "totalStartupTime =" + totalStartupTime);
+ writeToOutputFile(totalStartupTime, individualStartupTime, false, "Video");
+ }
+
+ @LargeTest
+ public void testLaunchCamera() throws Exception {
+ String individualStartupTime;
+ individualStartupTime = "Individual Camera Startup Time = ";
+ long totalStartupTime = 0;
+ long startupTime = 0;
+ for (int i = 0; i < TOTAL_NUMBER_OF_STARTUP; i++) {
+ if (i == 0) {
+ // Capture the first startup time individually
+ long firstStartUpTime = launchCamera();
+ writeToOutputFile(firstStartUpTime, "na", true, "Camera");
+ } else {
+ startupTime = launchCamera();
+ totalStartupTime += startupTime;
+ individualStartupTime += startupTime + " ,";
+ }
+ }
+ Log.v(TAG, "totalStartupTime =" + totalStartupTime);
+ writeToOutputFile(totalStartupTime,
+ individualStartupTime, false, "Camera");
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java b/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
new file mode 100755
index 000000000..57ae69125
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.stress;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import junit.framework.TestSuite;
+
+public class CameraStressTestRunner extends InstrumentationTestRunner {
+
+ // Default recorder settings
+ public static int mVideoDuration = 20000; // set default to 20 seconds
+ public static int mVideoIterations = 100; // set default to 100 videos
+ public static int mImageIterations = 100; // set default to 100 images
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(ImageCapture.class);
+ suite.addTestSuite(VideoCapture.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return CameraStressTestRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ String video_iterations = (String) icicle.get("video_iterations");
+ String image_iterations = (String) icicle.get("image_iterations");
+ String video_duration = (String) icicle.get("video_duration");
+
+ if ( video_iterations != null ) {
+ mVideoIterations = Integer.parseInt(video_iterations);
+ }
+ if ( image_iterations != null) {
+ mImageIterations = Integer.parseInt(image_iterations);
+ }
+ if ( video_duration != null) {
+ mVideoDuration = Integer.parseInt(video_duration);
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/ImageCapture.java b/tests/src/com/android/gallery3d/stress/ImageCapture.java
new file mode 100755
index 000000000..e322eb516
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/ImageCapture.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.stress.CameraStressTestRunner;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.app.Activity;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ * -e class com.android.camera.stress.ImageCapture \
+ * -w com.google.android.camera.tests/android.test.InstrumentationTestRunner
+ *
+ */
+
+public class ImageCapture extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private String TAG = "ImageCapture";
+ private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 1500; //1.5 sedconds
+ private static final long WAIT_FOR_SWITCH_CAMERA = 3000; //3 seconds
+
+ private TestUtil testUtil = new TestUtil();
+
+ // Private intent extras.
+ private final static String EXTRAS_CAMERA_FACING =
+ "android.intent.extras.CAMERA_FACING";
+
+ public ImageCapture() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ testUtil.prepareOutputFile();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ testUtil.closeOutputFile();
+ super.tearDown();
+ }
+
+ public void captureImages(String reportTag, Instrumentation inst) {
+ int total_num_of_images = CameraStressTestRunner.mImageIterations;
+ Log.v(TAG, "no of images = " + total_num_of_images);
+
+ //TODO(yslau): Need to integrate the outoput with the central dashboard,
+ //write to a txt file as a temp solution
+ boolean memoryResult = false;
+ KeyEvent focusEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS);
+
+ try {
+ testUtil.writeReportHeader(reportTag, total_num_of_images);
+ for (int i = 0; i < total_num_of_images; i++) {
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ inst.sendKeySync(focusEvent);
+ inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+ Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+ testUtil.writeResult(i);
+ }
+ } catch (Exception e) {
+ Log.v(TAG, "Got exception: " + e.toString());
+ assertTrue("testImageCapture", false);
+ }
+ }
+
+ @LargeTest
+ public void testBackImageCapture() throws Exception {
+ Instrumentation inst = getInstrumentation();
+ Intent intent = new Intent();
+
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRAS_CAMERA_FACING,
+ android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
+ Activity act = inst.startActivitySync(intent);
+ Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+ captureImages("Back Camera Image Capture\n", inst);
+ act.finish();
+ }
+
+ @LargeTest
+ public void testFrontImageCapture() throws Exception {
+ Instrumentation inst = getInstrumentation();
+ Intent intent = new Intent();
+
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRAS_CAMERA_FACING,
+ android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
+ Activity act = inst.startActivitySync(intent);
+ Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+ captureImages("Front Camera Image Capture\n", inst);
+ act.finish();
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/ShotToShotLatency.java b/tests/src/com/android/gallery3d/stress/ShotToShotLatency.java
new file mode 100644
index 000000000..a27bd90e6
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/ShotToShotLatency.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.gallery3d.stress;
+
+import android.app.Instrumentation;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import com.android.camera.CameraActivity;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Junit / Instrumentation test case for measuring camera shot to shot latency
+ */
+public class ShotToShotLatency extends ActivityInstrumentationTestCase2<CameraActivity> {
+ private String TAG = "ShotToShotLatency";
+ private static final int TOTAL_NUMBER_OF_SNAPSHOTS = 250;
+ private static final long SNAPSHOT_WAIT = 1000;
+ private static final String CAMERA_TEST_OUTPUT_FILE =
+ Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+ private static final String CAMERA_IMAGE_DIRECTORY =
+ Environment.getExternalStorageDirectory().toString() + "/DCIM/Camera/";
+
+ public ShotToShotLatency() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ getActivity();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private void cleanupLatencyImages() {
+ try {
+ File sdcard = new File(CAMERA_IMAGE_DIRECTORY);
+ File[] pics = null;
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jpg");
+ }
+ };
+ pics = sdcard.listFiles(filter);
+ for (File f : pics) {
+ f.delete();
+ }
+ } catch (SecurityException e) {
+ Log.e(TAG, "Security manager access violation: " + e.toString());
+ }
+ }
+
+ private void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Sleep InterruptedException " + e.toString());
+ }
+ }
+
+ @LargeTest
+ public void testShotToShotLatency() {
+ long sigmaOfDiffFromMeanSquared = 0;
+ double mean = 0;
+ double standardDeviation = 0;
+ ArrayList<Long> captureTimes = new ArrayList<Long>();
+ ArrayList<Long> latencyTimes = new ArrayList<Long>();
+
+ Log.v(TAG, "start testShotToShotLatency test");
+ Instrumentation inst = getInstrumentation();
+
+ // Generate data points
+ for (int i = 0; i < TOTAL_NUMBER_OF_SNAPSHOTS; i++) {
+ inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ sleep(SNAPSHOT_WAIT);
+ CameraActivity c = getActivity();
+ if (c.getCaptureStartTime() > 0) {
+ captureTimes.add(c.getCaptureStartTime());
+ }
+ }
+
+ // Calculate latencies
+ for (int j = 1; j < captureTimes.size(); j++) {
+ latencyTimes.add(captureTimes.get(j) - captureTimes.get(j - 1));
+ }
+
+ // Crunch numbers
+ for (long dataPoint : latencyTimes) {
+ mean += (double) dataPoint;
+ }
+ mean /= latencyTimes.size();
+
+ for (long dataPoint : latencyTimes) {
+ sigmaOfDiffFromMeanSquared += (dataPoint - mean) * (dataPoint - mean);
+ }
+ standardDeviation = Math.sqrt(sigmaOfDiffFromMeanSquared / latencyTimes.size());
+
+ // Report statistics
+ File outFile = new File(CAMERA_TEST_OUTPUT_FILE);
+ BufferedWriter output = null;
+ try {
+ output = new BufferedWriter(new FileWriter(outFile, true));
+ output.write("Shot to shot latency - mean: " + mean + "\n");
+ output.write("Shot to shot latency - standard deviation: " + standardDeviation + "\n");
+ cleanupLatencyImages();
+ } catch (IOException e) {
+ Log.e(TAG, "testShotToShotLatency IOException writing to log " + e.toString());
+ } finally {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error closing file: " + e.toString());
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/SwitchPreview.java b/tests/src/com/android/gallery3d/stress/SwitchPreview.java
new file mode 100755
index 000000000..955d092a6
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/SwitchPreview.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ * -e class com.android.camera.stress.SwitchPreview \
+ * -w com.android.camera.tests/com.android.camera.stress.CameraStressTestRunner
+ *
+ */
+public class SwitchPreview extends ActivityInstrumentationTestCase2 <CameraActivity>{
+ private String TAG = "SwitchPreview";
+ private static final int TOTAL_NUMBER_OF_SWITCHING = 200;
+ private static final long WAIT_FOR_PREVIEW = 4000;
+
+ private static final String CAMERA_TEST_OUTPUT_FILE =
+ Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+ private BufferedWriter mOut;
+ private FileWriter mfstream;
+
+ public SwitchPreview() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ getActivity();
+ prepareOutputFile();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getActivity().finish();
+ closeOutputFile();
+ super.tearDown();
+ }
+
+ private void prepareOutputFile(){
+ try{
+ mfstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+ mOut = new BufferedWriter(mfstream);
+ } catch (Exception e){
+ assertTrue("Camera Switch Mode", false);
+ }
+ }
+
+ private void closeOutputFile() {
+ try {
+ mOut.write("\n");
+ mOut.close();
+ mfstream.close();
+ } catch (Exception e) {
+ assertTrue("CameraSwitchMode close output", false);
+ }
+ }
+
+ @LargeTest
+ public void testSwitchMode() {
+ //Switching the video and the video recorder mode
+ Instrumentation inst = getInstrumentation();
+ try{
+ mOut.write("Camera Switch Mode:\n");
+ mOut.write("No of loops :" + TOTAL_NUMBER_OF_SWITCHING + "\n");
+ mOut.write("loop: ");
+ for (int i=0; i< TOTAL_NUMBER_OF_SWITCHING; i++) {
+ Thread.sleep(WAIT_FOR_PREVIEW);
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.setClass(getInstrumentation().getTargetContext(),
+ CameraActivity.class);
+ getActivity().startActivity(intent);
+ Thread.sleep(WAIT_FOR_PREVIEW);
+ intent = new Intent();
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.setClass(getInstrumentation().getTargetContext(),
+ CameraActivity.class);
+ getActivity().startActivity(intent);
+ mOut.write(" ," + i);
+ mOut.flush();
+ }
+ } catch (Exception e){
+ Log.v(TAG, "Got exception", e);
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/TestUtil.java b/tests/src/com/android/gallery3d/stress/TestUtil.java
new file mode 100644
index 000000000..56ab715f7
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/TestUtil.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.stress;
+
+import android.os.Environment;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
+
+/**
+ * Collection of utility functions used for the test.
+ */
+public class TestUtil {
+ public BufferedWriter mOut;
+ public FileWriter mfstream;
+
+ public TestUtil() {
+ }
+
+ public void prepareOutputFile() throws Exception {
+ String camera_test_output_file =
+ Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+ mfstream = new FileWriter(camera_test_output_file, true);
+ mOut = new BufferedWriter(mfstream);
+ }
+
+ public void closeOutputFile() throws Exception {
+ mOut.write("\n");
+ mOut.close();
+ mfstream.close();
+ }
+
+ public void writeReportHeader(String reportTag, int iteration) throws Exception {
+ mOut.write(reportTag);
+ mOut.write("No of loops :" + iteration + "\n");
+ mOut.write("loop: ");
+ }
+
+ public void writeResult(int iteration) throws Exception {
+ mOut.write(" ," + iteration);
+ mOut.flush();
+ }
+}
diff --git a/tests/src/com/android/gallery3d/stress/VideoCapture.java b/tests/src/com/android/gallery3d/stress/VideoCapture.java
new file mode 100755
index 000000000..dbbd124d0
--- /dev/null
+++ b/tests/src/com/android/gallery3d/stress/VideoCapture.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.stress.TestUtil;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+
+import com.android.gallery3d.stress.CameraStressTestRunner;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ * -e class com.android.camera.stress.VideoCapture \
+ * -w com.google.android.camera.tests/android.test.InstrumentationTestRunner
+ *
+ */
+
+public class VideoCapture extends ActivityInstrumentationTestCase2 <CameraActivity> {
+ private static final long WAIT_FOR_PREVIEW = 1500; //1.5 seconds
+ private static final long WAIT_FOR_SWITCH_CAMERA = 3000; //2 seconds
+
+ // Private intent extras which control the camera facing.
+ private final static String EXTRAS_CAMERA_FACING =
+ "android.intent.extras.CAMERA_FACING";
+
+ private TestUtil testUtil = new TestUtil();
+
+ public VideoCapture() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ testUtil.prepareOutputFile();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ testUtil.closeOutputFile();
+ super.tearDown();
+ }
+
+ @LargeTest
+ public void captureVideos(String reportTag, Instrumentation inst) throws Exception{
+ boolean memoryResult = false;
+ int total_num_of_videos = CameraStressTestRunner.mVideoIterations;
+ int video_duration = CameraStressTestRunner.mVideoDuration;
+ testUtil.writeReportHeader(reportTag, total_num_of_videos);
+
+ for (int i = 0; i < total_num_of_videos; i++) {
+ Thread.sleep(WAIT_FOR_PREVIEW);
+ // record a video
+ inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+ Thread.sleep(video_duration);
+ inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+ testUtil.writeResult(i);
+ }
+ }
+
+ @LargeTest
+ public void testBackVideoCapture() throws Exception {
+ Instrumentation inst = getInstrumentation();
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRAS_CAMERA_FACING,
+ android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
+ Activity act = inst.startActivitySync(intent);
+ Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+ captureVideos("Back Camera Video Capture\n", inst);
+ act.finish();
+ }
+
+ @LargeTest
+ public void testFrontVideoCapture() throws Exception {
+ Instrumentation inst = getInstrumentation();
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+
+ intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRAS_CAMERA_FACING,
+ android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
+ Activity act = inst.startActivitySync(intent);
+ Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+ captureVideos("Front Camera Video Capture\n", inst);
+ act.finish();
+ }
+}
diff --git a/tests/src/com/android/gallery3d/unittest/CameraUnitTest.java b/tests/src/com/android/gallery3d/unittest/CameraUnitTest.java
new file mode 100644
index 000000000..b8fb05fc2
--- /dev/null
+++ b/tests/src/com/android/gallery3d/unittest/CameraUnitTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.unittest;
+
+import com.android.camera.Util;
+
+import android.graphics.Matrix;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class CameraUnitTest extends TestCase {
+ public void testRoundOrientation() {
+ int h = Util.ORIENTATION_HYSTERESIS;
+ assertEquals(0, Util.roundOrientation(0, 0));
+ assertEquals(0, Util.roundOrientation(359, 0));
+ assertEquals(0, Util.roundOrientation(0 + 44 + h, 0));
+ assertEquals(90, Util.roundOrientation(0 + 45 + h, 0));
+ assertEquals(0, Util.roundOrientation(360 - 44 - h, 0));
+ assertEquals(270, Util.roundOrientation(360 - 45 - h, 0));
+
+ assertEquals(90, Util.roundOrientation(90, 90));
+ assertEquals(90, Util.roundOrientation(90 + 44 + h, 90));
+ assertEquals(180, Util.roundOrientation(90 + 45 + h, 90));
+ assertEquals(90, Util.roundOrientation(90 - 44 - h, 90));
+ assertEquals(0, Util.roundOrientation(90 - 45 - h, 90));
+
+ assertEquals(180, Util.roundOrientation(180, 180));
+ assertEquals(180, Util.roundOrientation(180 + 44 + h, 180));
+ assertEquals(270, Util.roundOrientation(180 + 45 + h, 180));
+ assertEquals(180, Util.roundOrientation(180 - 44 - h, 180));
+ assertEquals(90, Util.roundOrientation(180 - 45 - h, 180));
+
+ assertEquals(270, Util.roundOrientation(270, 270));
+ assertEquals(270, Util.roundOrientation(270 + 44 + h, 270));
+ assertEquals(0, Util.roundOrientation(270 + 45 + h, 270));
+ assertEquals(270, Util.roundOrientation(270 - 44 - h, 270));
+ assertEquals(180, Util.roundOrientation(270 - 45 - h, 270));
+
+ assertEquals(90, Util.roundOrientation(90, 0));
+ assertEquals(180, Util.roundOrientation(180, 0));
+ assertEquals(270, Util.roundOrientation(270, 0));
+
+ assertEquals(0, Util.roundOrientation(0, 90));
+ assertEquals(180, Util.roundOrientation(180, 90));
+ assertEquals(270, Util.roundOrientation(270, 90));
+
+ assertEquals(0, Util.roundOrientation(0, 180));
+ assertEquals(90, Util.roundOrientation(90, 180));
+ assertEquals(270, Util.roundOrientation(270, 180));
+
+ assertEquals(0, Util.roundOrientation(0, 270));
+ assertEquals(90, Util.roundOrientation(90, 270));
+ assertEquals(180, Util.roundOrientation(180, 270));
+ }
+
+ public void testPrepareMatrix() {
+ Matrix matrix = new Matrix();
+ float[] points;
+ int[] expected;
+
+ Util.prepareMatrix(matrix, false, 0, 800, 480);
+ points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250};
+ expected = new int[] {0, 0, 400, 240, 800, 480, 400, 480, 100, 300};
+ matrix.mapPoints(points);
+ assertEquals(expected, points);
+
+ Util.prepareMatrix(matrix, false, 90, 800, 480);
+ points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250};
+ expected = new int[] {800, 0, 400, 240, 0, 480, 0, 240, 300, 60};
+ matrix.mapPoints(points);
+ assertEquals(expected, points);
+
+ Util.prepareMatrix(matrix, false, 180, 800, 480);
+ points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250};
+ expected = new int[] {800, 480, 400, 240, 0, 0, 400, 0, 700, 180};
+ matrix.mapPoints(points);
+ assertEquals(expected, points);
+
+ Util.prepareMatrix(matrix, true, 180, 800, 480);
+ points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250};
+ expected = new int[] {0, 480, 400, 240, 800, 0, 400, 0, 100, 180};
+ matrix.mapPoints(points);
+ assertEquals(expected, points);
+ }
+
+ private void assertEquals(int expected[], float[] actual) {
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("Array index " + i + " mismatch", expected[i], Math.round(actual[i]));
+ }
+ }
+}
diff --git a/tests_camera/src/com/android/camera/activity/CameraActivityTest.java b/tests_camera/src/com/android/camera/activity/CameraActivityTest.java
index cc8ed83c3..eb027e9d3 100644
--- a/tests_camera/src/com/android/camera/activity/CameraActivityTest.java
+++ b/tests_camera/src/com/android/camera/activity/CameraActivityTest.java
@@ -21,7 +21,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import com.android.camera.CameraActivity;
import com.android.camera.CameraHolder;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import static com.google.testing.littlemock.LittleMock.doReturn;
diff --git a/tests_camera/src/com/android/camera/activity/CameraTestCase.java b/tests_camera/src/com/android/camera/activity/CameraTestCase.java
index 7c7c38daf..27be3c7d3 100644
--- a/tests_camera/src/com/android/camera/activity/CameraTestCase.java
+++ b/tests_camera/src/com/android/camera/activity/CameraTestCase.java
@@ -31,8 +31,8 @@ import android.view.View;
import com.android.camera.CameraHolder;
import com.android.camera.CameraManager.CameraProxy;
-import com.android.camera.R;
import com.android.camera.Util;
+import com.android.gallery3d.R;
import static com.google.testing.littlemock.LittleMock.mock;
import static com.google.testing.littlemock.LittleMock.doAnswer;
diff --git a/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java b/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java
index 620ff50b0..54ac1b497 100644
--- a/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java
+++ b/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java
@@ -17,7 +17,7 @@
package com.android.camera.functional;
import com.android.camera.CameraActivity;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import android.app.Activity;
import android.content.Intent;
diff --git a/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java b/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java
index 292543ccf..43e91ca84 100644
--- a/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java
+++ b/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java
@@ -17,7 +17,7 @@
package com.android.camera.functional;
import com.android.camera.CameraActivity;
-import com.android.camera.R;
+import com.android.gallery3d.R;
import android.app.Activity;
import android.content.ContentResolver;