diff options
21 files changed, 428 insertions, 220 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifInterface.java b/gallerycommon/src/com/android/gallery3d/exif/ExifInterface.java index 2fef9ede0..a1cf0fc85 100644 --- a/gallerycommon/src/com/android/gallery3d/exif/ExifInterface.java +++ b/gallerycommon/src/com/android/gallery3d/exif/ExifInterface.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.SparseIntArray; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; @@ -758,7 +759,7 @@ public class ExifInterface { } InputStream is = null; try { - is = (InputStream) new FileInputStream(inFileName); + is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName)); readExif(is); } catch (IOException e) { closeSilently(is); @@ -800,6 +801,7 @@ public class ExifInterface { } OutputStream s = getExifWriterStream(exifOutStream); s.write(jpeg, 0, jpeg.length); + s.flush(); } /** @@ -817,6 +819,7 @@ public class ExifInterface { } OutputStream s = getExifWriterStream(exifOutStream); bmap.compress(Bitmap.CompressFormat.JPEG, 90, s); + s.flush(); } /** @@ -834,6 +837,7 @@ public class ExifInterface { } OutputStream s = getExifWriterStream(exifOutStream); doExifStreamIO(jpegStream, s); + s.flush(); } /** @@ -1010,7 +1014,7 @@ public class ExifInterface { boolean ret; try { File temp = new File(filename); - is = new FileInputStream(temp); + is = new BufferedInputStream(new FileInputStream(temp)); // Parse beginning of APP1 in exif to find size of exif header. ExifParser parser = null; diff --git a/gallerycommon/src/com/android/gallery3d/exif/ExifOutputStream.java b/gallerycommon/src/com/android/gallery3d/exif/ExifOutputStream.java index e5a5bf009..ae501a50f 100644 --- a/gallerycommon/src/com/android/gallery3d/exif/ExifOutputStream.java +++ b/gallerycommon/src/com/android/gallery3d/exif/ExifOutputStream.java @@ -18,6 +18,7 @@ package com.android.gallery3d.exif; import android.util.Log; +import java.io.BufferedOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -58,6 +59,7 @@ import java.nio.ByteOrder; class ExifOutputStream extends FilterOutputStream { private static final String TAG = "ExifOutputStream"; private static final boolean DEBUG = false; + private static final int STREAMBUFFER_SIZE = 0x00010000; // 64Kb private static final int STATE_SOI = 0; private static final int STATE_FRAME_HEADER = 1; @@ -75,11 +77,12 @@ class ExifOutputStream extends FilterOutputStream { private int mState = STATE_SOI; private int mByteToSkip; private int mByteToCopy; + private byte[] mSingleByteArray = new byte[1]; private ByteBuffer mBuffer = ByteBuffer.allocate(4); private final ExifInterface mInterface; protected ExifOutputStream(OutputStream ou, ExifInterface iRef) { - super(ou); + super(new BufferedOutputStream(ou, STREAMBUFFER_SIZE)); mInterface = iRef; } @@ -190,10 +193,8 @@ class ExifOutputStream extends FilterOutputStream { */ @Override public void write(int oneByte) throws IOException { - byte[] buf = new byte[] { - (byte) (0xff & oneByte) - }; - write(buf); + mSingleByteArray[0] = (byte) (0xff & oneByte); + write(mSingleByteArray); } /** diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 3813cce34..1215cecf0 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -118,7 +118,6 @@ public class CameraActivity extends ActivityBase public void init() { boolean landscape = Util.getDisplayRotation(this) % 180 == 90; - setMargins(landscape); mControlsBackground = findViewById(R.id.blocker); mCameraControls = findViewById(R.id.camera_controls); mShutter = (ShutterButton) findViewById(R.id.shutter_button); @@ -318,24 +317,9 @@ public class CameraActivity extends ActivityBase @Override public void onConfigurationChanged(Configuration config) { super.onConfigurationChanged(config); - boolean landscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE); - setMargins(landscape); mCurrentModule.onConfigurationChanged(config); } - private void setMargins(boolean landscape) { - ViewGroup appRoot = (ViewGroup) findViewById(R.id.content); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) appRoot.getLayoutParams(); - int navBarWidth = getResources().getDimensionPixelSize(R.dimen.navigation_bar_width); - int navBarHeight = getResources().getDimensionPixelSize(R.dimen.navigation_bar_height); - if (landscape) { - lp.setMargins(navBarHeight, 0, navBarHeight - navBarWidth, 0); - } else { - lp.setMargins(0, navBarHeight, 0, 0); - } - appRoot.setLayoutParams(lp); - } - @Override public void onPause() { mPaused = true; diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java index be82ea613..b354654b6 100644 --- a/src/com/android/camera/CameraManager.java +++ b/src/com/android/camera/CameraManager.java @@ -74,7 +74,6 @@ public class CameraManager { private static final int ENABLE_SHUTTER_SOUND = 24; private Handler mCameraHandler; - private CameraProxy mCameraProxy; private android.hardware.Camera mCamera; // This holder is used when we need to pass the exception @@ -139,7 +138,6 @@ public class CameraManager { case RELEASE: mCamera.release(); mCamera = null; - mCameraProxy = null; return; case RECONNECT: @@ -226,11 +224,15 @@ public class CameraManager { return; case SET_PARAMETERS: + mParametersIsDirty = true; mCamera.setParameters((Parameters) msg.obj); return; case GET_PARAMETERS: - mParameters = mCamera.getParameters(); + if (mParametersIsDirty) { + mParameters = mCamera.getParameters(); + mParametersIsDirty = false; + } return; case SET_PARAMETERS_ASYNC: @@ -256,7 +258,6 @@ public class CameraManager { Log.e(TAG, "Fail to release the camera."); } mCamera = null; - mCameraProxy = null; } throw e; } @@ -280,9 +281,8 @@ public class CameraManager { // a view hierarchy can touch its views. mCamera = android.hardware.Camera.open(cameraId); if (mCamera != null) { - mCameraProxy = new CameraProxy(); mParametersIsDirty = true; - return mCameraProxy; + return new CameraProxy(); } else { return null; } @@ -334,8 +334,11 @@ public class CameraManager { mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC); } + // stopPreview() is synchronous because many resources should be released after + // the preview is stopped. public void stopPreview() { mCameraHandler.sendEmptyMessage(STOP_PREVIEW); + waitDone(); } public void setPreviewCallback(final PreviewCallback cb) { @@ -424,7 +427,6 @@ public class CameraManager { Log.v(TAG, "null parameters in setParameters()"); return; } - mParametersIsDirty = true; mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget(); } @@ -434,16 +436,13 @@ public class CameraManager { Log.v(TAG, "null parameters in setParameters()"); return; } - mParametersIsDirty = true; mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC); mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget(); } public Parameters getParameters() { - if (mParametersIsDirty || mParameters == null) { - mCameraHandler.sendEmptyMessage(GET_PARAMETERS); - if (waitDone()) mParametersIsDirty = false; - } + mCameraHandler.sendEmptyMessage(GET_PARAMETERS); + waitDone(); return mParameters; } diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java index 280ad44a9..92396c71b 100644 --- a/src/com/android/camera/PhotoMenu.java +++ b/src/com/android/camera/PhotoMenu.java @@ -34,6 +34,15 @@ public class PhotoMenu extends PieController TimerSettingPopup.Listener, ListPrefSettingPopup.Listener { private static String TAG = "CAM_photomenu"; + + private static final int POS_HDR = 0; + private static final int POS_EXP = 1; + private static final int POS_MORE = 2; + private static final int POS_FLASH = 3; + private static final int POS_SWITCH = 4; + private static final int POS_WB = 1; + private static final int POS_SET = 2; + private final String mSettingOff; private PhotoUI mUI; @@ -53,20 +62,19 @@ public class PhotoMenu extends PieController super.initialize(group); mPopup = null; mSecondPopup = null; - float sweep = (float) (SWEEP * Math.PI); PieItem item = null; // flash if (group.findPreference(CameraSettings.KEY_FLASH_MODE) != null) { - item = makeItem(CameraSettings.KEY_FLASH_MODE, CENTER - sweep, sweep); + item = makeItem(CameraSettings.KEY_FLASH_MODE, POS_FLASH, 5); mRenderer.addItem(item); } // exposure compensation - item = makeItem(CameraSettings.KEY_EXPOSURE, CENTER + sweep, sweep); + item = makeItem(CameraSettings.KEY_EXPOSURE, POS_EXP, 5); mRenderer.addItem(item); // camera switcher if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { item = makeItem(R.drawable.ic_switch_photo_facing_holo_light); - item.setFixedSlice(CENTER - 2 * sweep, sweep); + item.setPosition(POS_SWITCH, 5); item.setOnClickListener(new OnClickListener() { @Override public void onClick(PieItem item) { @@ -88,7 +96,7 @@ public class PhotoMenu extends PieController // hdr if (group.findPreference(CameraSettings.KEY_CAMERA_HDR) != null) { item = makeItem(R.drawable.ic_hdr); - item.setFixedSlice(CENTER + 2 * sweep, sweep); + item.setPosition(POS_HDR, 5); item.setOnClickListener(new OnClickListener() { @Override public void onClick(PieItem item) { @@ -108,11 +116,10 @@ public class PhotoMenu extends PieController // more settings PieItem more = makeItem(R.drawable.ic_settings_holo_light); - more.setFixedSlice(CENTER, sweep); + more.setPosition(POS_MORE, 5); mRenderer.addItem(more); // white balance - item = makeItem(CameraSettings.KEY_WHITE_BALANCE, - CENTER + sweep, sweep); + item = makeItem(CameraSettings.KEY_WHITE_BALANCE, POS_WB, 5); more.addItem(item); // settings popup mOtherKeys = new String[] { @@ -124,7 +131,7 @@ public class PhotoMenu extends PieController CameraSettings.KEY_TIMER_SOUND_EFFECTS, }; item = makeItem(R.drawable.ic_settings_holo_light); - item.setFixedSlice(CENTER, sweep); + item.setPosition(POS_SET, 5); item.setOnClickListener(new OnClickListener() { @Override public void onClick(PieItem item) { diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index f4bd4ce1d..22bd6503f 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -1013,6 +1013,8 @@ public class PhotoModule mFaceDetectionStarted = false; setCameraState(SNAPSHOT_IN_PROGRESS); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + UsageStatistics.ACTION_CAPTURE_DONE, "Photo"); return true; } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index 1af870abc..29ebd6a70 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -115,6 +115,8 @@ public class PhotoUI implements PieListener, h = width; } if (mPreviewWidth != w || mPreviewHeight != h) { + mPreviewWidth = w; + mPreviewHeight = h; mController.onScreenSizeChanged(width, height, w, h); } } diff --git a/src/com/android/camera/PieController.java b/src/com/android/camera/PieController.java index 2145fd894..c5d1b8b41 100644 --- a/src/com/android/camera/PieController.java +++ b/src/com/android/camera/PieController.java @@ -37,10 +37,6 @@ public class PieController { protected static final int MODE_PHOTO = 0; protected static final int MODE_VIDEO = 1; - protected static float CENTER = (float) Math.PI / 2; - protected static final float SWEEP = 0.06f; - - protected CameraActivity mActivity; protected PreferenceGroup mPreferenceGroup; protected OnPreferenceChangedListener mListener; @@ -88,7 +84,7 @@ public class PieController { return new PieItem(drawable, 0); } - public PieItem makeItem(String prefKey, float center, float sweep) { + public PieItem makeItem(String prefKey, int position, int count) { final IconListPreference pref = (IconListPreference) mPreferenceGroup.findPreference(prefKey); if (pref == null) return null; @@ -103,8 +99,7 @@ public class PieController { resid = pref.getSingleIcon(); } PieItem item = makeItem(resid); - // use center and sweep to determine layout - item.setFixedSlice(center, sweep); + item.setPosition(position, count); mPreferences.add(pref); mPreferenceMap.put(pref, item); int nOfEntries = pref.getEntries().length; @@ -116,7 +111,7 @@ public class PieController { } else { inner = makeItem(pref.getEntries()[i]); } - layoutInner(inner, i, nOfEntries); + inner.setPosition(i, nOfEntries); item.addItem(inner); final int index = i; inner.setOnClickListener(new OnClickListener() { @@ -137,14 +132,8 @@ public class PieController { return item; } - protected void layoutInner(PieItem item, int ix, int n) { - float sweep = (float) (SWEEP * Math.PI);//FLOAT_PI_DIVIDED_BY_TWO / Math.max(n, 5); - float start = CENTER + (n - 1) * (sweep / 2f); - item.setFixedSlice(start - ix * sweep, sweep); - } - - public void addItem(String prefKey, float center, float sweep) { - PieItem item = makeItem(prefKey, center, sweep); + public void addItem(String prefKey, int position, int count) { + PieItem item = makeItem(prefKey, position, count); mRenderer.addItem(item); } diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java index 0f987aa87..d9629d3ac 100644 --- a/src/com/android/camera/VideoMenu.java +++ b/src/com/android/camera/VideoMenu.java @@ -34,6 +34,10 @@ public class VideoMenu extends PieController TimeIntervalPopup.Listener { private static String TAG = "CAM_VideoMenu"; + private static final int POS_WB = 1; + private static final int POS_SET = 2; + private static final int POS_FLASH = 3; + private static final int POS_SWITCH = 4; private VideoUI mUI; private String[] mOtherKeys; @@ -53,13 +57,14 @@ public class VideoMenu extends PieController super.initialize(group); mPopup = null; mPopupStatus = POPUP_NONE; - float sweep = (float)(SWEEP * Math.PI); - addItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, CENTER - sweep, sweep); - addItem(CameraSettings.KEY_WHITE_BALANCE, CENTER + sweep, sweep); + PieItem item = makeItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, POS_FLASH, 5); + mRenderer.addItem(item); + item = makeItem(CameraSettings.KEY_WHITE_BALANCE, POS_WB, 5); + mRenderer.addItem(item); // camera switcher - PieItem item = makeItem(R.drawable.ic_switch_video_facing_holo_light); - item.setFixedSlice(CENTER - 2 * sweep, sweep); + item = makeItem(R.drawable.ic_switch_video_facing_holo_light); + item.setPosition(POS_SWITCH, 5); item.setOnClickListener(new OnClickListener() { @Override @@ -84,7 +89,7 @@ public class VideoMenu extends PieController CameraSettings.KEY_RECORD_LOCATION }; item = makeItem(R.drawable.ic_settings_holo_light); - item.setFixedSlice(CENTER, sweep); + item.setPosition(POS_SET, 5); item.setOnClickListener(new OnClickListener() { @Override public void onClick(PieItem item) { diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 1f31778df..09a406ce5 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -450,6 +450,8 @@ public class VideoModule implements CameraModule, mActivity.mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc)); showVideoSnapshotUI(true); mSnapshotInProgress = true; + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + UsageStatistics.ACTION_CAPTURE_DONE, "VideoSnapshot"); } @Override @@ -1547,6 +1549,8 @@ public class VideoModule implements CameraModule, updateRecordingTime(); keepScreenOn(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + UsageStatistics.ACTION_CAPTURE_START, "Video"); } private void showCaptureResult() { @@ -1662,6 +1666,10 @@ public class VideoModule implements CameraModule, // Update the parameters here because the parameters might have been altered // by MediaRecorder. if (!mPaused) mParameters = mActivity.mCameraDevice.getParameters(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + fail ? UsageStatistics.ACTION_CAPTURE_FAIL : + UsageStatistics.ACTION_CAPTURE_DONE, "Video", + SystemClock.uptimeMillis() - mRecordingStartTime); return fail; } diff --git a/src/com/android/camera/ui/SwitcherBackgroundView.java b/src/com/android/camera/ui/CameraControls.java index 710412cce..a7d1f215e 100644 --- a/src/com/android/camera/ui/SwitcherBackgroundView.java +++ b/src/com/android/camera/ui/CameraControls.java @@ -27,38 +27,57 @@ import android.widget.FrameLayout.LayoutParams; import com.android.camera.Util; import com.android.gallery3d.R; -/* - * This is a simple view that has a gradient background. The background - * needs to rotate when orientation changes, so that the side of the drawable - * that is dark is always aligned to the side of the screen, and the side that is - * closer to the center of the screen is transparent. - * */ -public class SwitcherBackgroundView extends View +public class CameraControls extends RotatableLayout { - public SwitcherBackgroundView(Context context, AttributeSet attrs) { + private View mBackgroundView; + public CameraControls(Context context, AttributeSet attrs) { super(context, attrs); - setBackgroundResource(R.drawable.switcher_bg); } - public SwitcherBackgroundView(Context context) { + public CameraControls(Context context) { super(context); - setBackgroundResource(R.drawable.switcher_bg); } + @Override public void onConfigurationChanged(Configuration config) { super.onConfigurationChanged(config); + adjustBackground(); + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + mBackgroundView = findViewById(R.id.blocker); + } + + // In reverse landscape and reverse portrait, camera controls will be laid out + // on the wrong side of the screen. We need to make adjustment to move the controls + // to the USB side + public void adjustControlsToRightPosition() { + Configuration config = getResources().getConfiguration(); + int orientation = Util.getDisplayRotation((Activity) getContext()); + if (orientation == 270 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) { + flipChildren(); + } + if (orientation == 180 && config.orientation == Configuration.ORIENTATION_PORTRAIT) { + flipChildren(); + } + adjustBackground(); + } + + private void adjustBackground() { // remove current drawable and reset rotation - setBackgroundDrawable(null); - setRotationX(0); - setRotationY(0); + mBackgroundView.setBackgroundDrawable(null); + mBackgroundView.setRotationX(0); + mBackgroundView.setRotationY(0); // if the switcher background is top aligned we need to flip the background // drawable vertically; if left aligned, flip horizontally - int gravity = ((LayoutParams) getLayoutParams()).gravity; + int gravity = ((LayoutParams) mBackgroundView.getLayoutParams()).gravity; if ((gravity & Gravity.TOP) == Gravity.TOP) { - setRotationX(180); + mBackgroundView.setRotationX(180); } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) { - setRotationY(180); + mBackgroundView.setRotationY(180); } - setBackgroundResource(R.drawable.switcher_bg); + mBackgroundView.setBackgroundResource(R.drawable.switcher_bg); } } diff --git a/src/com/android/camera/ui/CameraRootView.java b/src/com/android/camera/ui/CameraRootView.java new file mode 100644 index 000000000..cce649530 --- /dev/null +++ b/src/com/android/camera/ui/CameraRootView.java @@ -0,0 +1,85 @@ +/* + * 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.camera.ui; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; + +import com.android.camera.Util; +import com.android.gallery3d.R; + +public class CameraRootView extends RelativeLayout + implements RotatableLayout.RotationListener { + + private int mOffset = 0; + public CameraRootView(Context context, AttributeSet attrs) { + super(context, attrs); + // Layout the window as if we did not need navigation bar + setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + super.fitSystemWindows(insets); + // insets include status bar, navigation bar, etc + // In this case, we are only concerned with the size of nav bar + if (mOffset > 0) return true; + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); + if (insets.bottom > 0) { + mOffset = insets.bottom; + } else if (insets.right > 0) { + mOffset = insets.right; + } + Configuration config = getResources().getConfiguration(); + if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { + lp.setMargins(0, 0, 0, mOffset); + } else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) { + lp.setMargins(0, 0, mOffset, 0); + } + CameraControls controls = (CameraControls) findViewById(R.id.camera_controls); + if (controls != null) { + controls.setRotationListener(this); + controls.adjustControlsToRightPosition(); + } + return true; + } + + @Override + public void onRotation(int rotation) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); + int b = lp.bottomMargin; + int t = lp.topMargin; + int l = lp.leftMargin; + int r = lp.rightMargin; + rotation = (rotation + 360) % 360; + if (rotation == 90) { + lp.setMargins(b, l, t, r); + } else if (rotation == 270) { + lp.setMargins(t, r, b, l); + } else if (rotation == 180) { + lp.setMargins(r, b, l, t); + } + } +} diff --git a/src/com/android/camera/ui/PieItem.java b/src/com/android/camera/ui/PieItem.java index bbfa1dc82..6128e0422 100644 --- a/src/com/android/camera/ui/PieItem.java +++ b/src/com/android/camera/ui/PieItem.java @@ -19,7 +19,6 @@ package com.android.camera.ui; import android.content.Context; import android.graphics.Canvas; import android.graphics.Path; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import java.util.ArrayList; @@ -36,12 +35,9 @@ public class PieItem { private Drawable mDrawable; private int level; - private float mCenter; - private float start; - private float sweep; - private float animate; - private int inner; - private int outer; + private int mPosition; + private int mCount; + private boolean mSelected; private boolean mEnabled; private List<PieItem> mItems; @@ -61,9 +57,19 @@ public class PieItem { setAlpha(1f); } mEnabled = true; - setAnimationAngle(getAnimationAngle()); - start = -1; - mCenter = -1; + } + + public void setPosition(int pos, int count) { + mPosition = pos; + mCount = count; + } + + public int getPosition() { + return mPosition; + } + + public int getCount() { + return mCount; } public boolean hasItems() { @@ -85,6 +91,10 @@ public class PieItem { mItems = null; } + public void setLevel(int level) { + this.level = level; + } + public void setPath(Path p) { mPath = p; } @@ -102,14 +112,6 @@ public class PieItem { mDrawable.setAlpha((int) (255 * alpha)); } - public void setAnimationAngle(float a) { - animate = a; - } - - public float getAnimationAngle() { - return animate; - } - public void setEnabled(boolean enabled) { mEnabled = enabled; if (mChangeAlphaWhenDisabled) { @@ -137,41 +139,6 @@ public class PieItem { return level; } - public void setGeometry(float st, float sw, int inside, int outside) { - start = st; - sweep = sw; - inner = inside; - outer = outside; - } - - public void setFixedSlice(float center, float sweep) { - mCenter = center; - this.sweep = sweep; - } - - public float getCenter() { - return mCenter; - } - - public float getStart() { - return start; - } - - public float getStartAngle() { - return start + animate; - } - - public float getSweep() { - return sweep; - } - - public int getInnerRadius() { - return inner; - } - - public int getOuterRadius() { - return outer; - } public void setOnClickListener(OnClickListener listener) { mOnClickListener = listener; diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java index dffa47e1e..0d8312ca4 100644 --- a/src/com/android/camera/ui/PieRenderer.java +++ b/src/com/android/camera/ui/PieRenderer.java @@ -74,10 +74,14 @@ public class PieRenderer extends OverlayRenderer private static final int MSG_OPEN = 0; private static final int MSG_CLOSE = 1; private static final int MSG_OPENSUBMENU = 2; - private static final float PIE_SWEEP = (float)(Math.PI / 2); + + protected static float CENTER = (float) Math.PI / 2; + protected static final float SWEEP_SLICE = 0.14f; + protected static final float SWEEP_ARC = 0.23f; + // geometry - private Point mSliceCenter; private int mRadius; + private int mRadiusInc; // the detection if touch is inside a slice is offset // inbounds by this amount to allow the selection to show before the @@ -101,9 +105,11 @@ public class PieRenderer extends OverlayRenderer private int mFocusY; private int mCenterX; private int mCenterY; + private int mArcCenterY; + private int mSliceCenterY; private int mPieCenterX; private int mPieCenterY; - private int mIconRadius; + private int mSliceRadius; private int mArcRadius; private int mArcOffset; @@ -126,6 +132,9 @@ public class PieRenderer extends OverlayRenderer private LinearAnimation mFadeIn; private FadeOutAnimation mFadeOut; private volatile boolean mFocusCancelled; + private PointF mPolar = new PointF(); + + private Handler mHandler = new Handler() { public void handleMessage(Message msg) { @@ -169,9 +178,9 @@ public class PieRenderer extends OverlayRenderer mOpen.add(new PieItem(null, 0)); Resources res = ctx.getResources(); mRadius = (int) res.getDimensionPixelSize(R.dimen.pie_radius_start); + mRadiusInc = (int) res.getDimensionPixelSize(R.dimen.pie_radius_increment); mCircleSize = mRadius - res.getDimensionPixelSize(R.dimen.focus_radius_offset); mTouchOffset = (int) res.getDimensionPixelSize(R.dimen.pie_touch_offset); - mSliceCenter = new Point(0,0); mSelectedPaint = new Paint(); mSelectedPaint.setColor(Color.argb(255, 51, 181, 229)); mSelectedPaint.setAntiAlias(true); @@ -201,7 +210,7 @@ public class PieRenderer extends OverlayRenderer mMenuArcPaint.setColor(Color.argb(140, 255, 255, 255)); mMenuArcPaint.setStrokeWidth(10); mMenuArcPaint.setStyle(Paint.Style.STROKE); - mIconRadius = res.getDimensionPixelSize(R.dimen.pie_item_radius); + mSliceRadius = res.getDimensionPixelSize(R.dimen.pie_item_radius); mArcRadius = res.getDimensionPixelSize(R.dimen.pie_arc_radius); mArcOffset = res.getDimensionPixelSize(R.dimen.pie_arc_offset); } @@ -299,8 +308,8 @@ public class PieRenderer extends OverlayRenderer public void setCenter(int x, int y) { mPieCenterX = x; mPieCenterY = y; - mSliceCenter.x = x; - mSliceCenter.y = y - mArcOffset + mIconRadius; + mSliceCenterY = y - mArcOffset + mSliceRadius; + mArcCenterY = y - mArcOffset + mArcRadius; } @Override @@ -325,60 +334,40 @@ public class PieRenderer extends OverlayRenderer } private void layoutPie() { - int inner = mIconRadius; - int outer = inner + mTouchOffset; - int gap = 1; - layoutItems(0, getRoot().getItems(), (float) (Math.PI / 2), inner, outer, gap); - } - - private void layoutItems(int level, List<PieItem> items, float centerAngle, int inner, int outer, int gap) { - float emptyangle = PIE_SWEEP / 16; - float sweep = (float) (PIE_SWEEP - 2 * emptyangle) / items.size(); - float angle = centerAngle - PIE_SWEEP / 2 + emptyangle + sweep / 2; - // check if we have custom geometry - // first item we find triggers custom sweep for all - // this allows us to re-use the path - for (PieItem item : items) { - if (item.getCenter() >= 0) { - sweep = item.getSweep(); - break; - } - } - Point p = new Point(mSliceCenter); - p.y -= level * mTouchOffset; - Path path = makeSlice(getDegrees(0) - gap, getDegrees(sweep) + gap, - outer, inner, p); + layoutItems(0, getRoot().getItems()); + } + + private void layoutItems(int level, List<PieItem> items) { + int extend = 1; + Path path = makeSlice(getDegrees(0) + extend, getDegrees(SWEEP_ARC) - extend, + mArcRadius, mArcRadius + mRadiusInc + mRadiusInc / 4, + mPieCenterX, mArcCenterY - level * mRadiusInc); for (PieItem item : items) { // shared between items item.setPath(path); - if (item.getCenter() >= 0) { - angle = item.getCenter(); - } + float angle = getArcCenter(item); int w = item.getIntrinsicWidth(); int h = item.getIntrinsicHeight(); // move views to outer border - int r = inner + (outer - inner) * 2 / 3; + int r = mArcRadius + mRadiusInc * 2 / 3; int x = (int) (r * Math.cos(angle)); - int y = mSliceCenter.y - (level * mTouchOffset) - (int) (r * Math.sin(angle)) - h / 2; - x = mSliceCenter.x + x - w / 2; + int y = mArcCenterY - (level * mRadiusInc) - (int) (r * Math.sin(angle)) - h / 2; + x = mPieCenterX + x - w / 2; item.setBounds(x, y, x + w, y + h); - float itemstart = angle - sweep / 2; - item.setGeometry(itemstart, sweep, inner, outer); + item.setLevel(level); if (item.hasItems()) { - layoutItems(level + 1, item.getItems(), MATH_PI_2, inner, - outer, gap); + layoutItems(level + 1, item.getItems()); } - angle += sweep; } } - private Path makeSlice(float start, float end, int outer, int inner, Point center) { + private Path makeSlice(float start, float end, int inner, int outer, int cx, int cy) { RectF bb = - new RectF(center.x - outer, center.y - outer, center.x + outer, - center.y + outer); + new RectF(cx - outer, cy - outer, cx + outer, + cy + outer); RectF bbi = - new RectF(center.x - inner, center.y - inner, center.x + inner, - center.y + inner); + new RectF(cx - inner, cy - inner, cx + inner, + cy + inner); Path path = new Path(); path.arcTo(bb, start, end - start, true); path.arcTo(bbi, end, start - end); @@ -386,6 +375,18 @@ public class PieRenderer extends OverlayRenderer return path; } + private float getArcCenter(PieItem item) { + return getCenter(item.getPosition(), item.getCount(), SWEEP_ARC); + } + + private float getSliceCenter(PieItem item) { + return getCenter(item.getPosition(), item.getCount(), SWEEP_SLICE); + } + + private float getCenter(int pos, int count, float sweep) { + return CENTER + (count - 1) * sweep / 2f - pos * sweep; + } + /** * converts a * @param angle from 0..PI to Android degrees (clockwise starting at 3 o'clock) @@ -475,14 +476,14 @@ public class PieRenderer extends OverlayRenderer } if (!hasOpenItem() || (mXFade != null)) { // draw base menu - drawArc(canvas, getLevel()); + drawArc(canvas, getLevel(), getParent()); for (PieItem item : getParent().getItems()) { drawItem(Math.max(0, mOpen.size() - 2), canvas, item, alpha); } } if (hasOpenItem()) { int level = getLevel(); - drawArc(canvas, level); + drawArc(canvas, level, getOpenItem()); for (PieItem inner : getOpenItem().getItems()) { if (mFadeOut != null) { drawItem(level, canvas, inner, alpha); @@ -494,25 +495,37 @@ public class PieRenderer extends OverlayRenderer canvas.restoreToCount(state); } - private void drawArc(Canvas canvas, int level) { + private void drawArc(Canvas canvas, int level, PieItem item) { // arc if (mState == STATE_PIE) { - int nr = mArcRadius; - int cy = mPieCenterY - mArcOffset + mArcRadius - level * mTouchOffset; - canvas.drawArc(new RectF(mPieCenterX - nr, cy - mArcRadius, - mPieCenterX + nr, cy + mArcRadius), - 252, 36, false, mMenuArcPaint); + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + int count = 0; + for (PieItem child : item.getItems()) { + final int p = child.getPosition(); + count = child.getCount(); + if (p < min) min = p; + if (p > max) max = p; + } + float start = CENTER + (count - 1) * SWEEP_ARC / 2f - min * SWEEP_ARC + SWEEP_ARC / 2f; + float end = CENTER + (count - 1) * SWEEP_ARC / 2f - max * SWEEP_ARC - SWEEP_ARC / 2f; + int cy = mArcCenterY - level * mRadiusInc; + canvas.drawArc(new RectF(mPieCenterX - mArcRadius, cy - mArcRadius, + mPieCenterX + mArcRadius, cy + mArcRadius), + getDegrees(end), getDegrees(start) - getDegrees(end), false, mMenuArcPaint); } } + private void drawItem(int level, Canvas canvas, PieItem item, float alpha) { if (mState == STATE_PIE) { if (item.getPath() != null) { - int y = mSliceCenter.y - level * mTouchOffset; + int y = mArcCenterY - level * mRadiusInc; if (item.isSelected()) { Paint p = mSelectedPaint; int state = canvas.save(); - float r = getDegrees(item.getStartAngle()); - canvas.rotate(r, mSliceCenter.x, y); + float angle = getArcCenter(item) - SWEEP_ARC / 2f; + angle = getDegrees(angle); + canvas.rotate(angle, mPieCenterX, y); if (mFadeOut != null) { p.setAlpha((int)(255 * alpha)); } @@ -537,13 +550,13 @@ public class PieRenderer extends OverlayRenderer float x = evt.getX(); float y = evt.getY(); int action = evt.getActionMasked(); - PointF polar = getPolar(x, y, !mTapMode); + getPolar(x, y, !mTapMode, mPolar); if (MotionEvent.ACTION_DOWN == action) { mDown.x = (int) evt.getX(); mDown.y = (int) evt.getY(); mOpening = false; if (mTapMode) { - PieItem item = findItem(polar); + PieItem item = findItem(mPolar); if ((item != null) && (mCurrentItem != item)) { mState = STATE_PIE; onEnter(item); @@ -557,7 +570,7 @@ public class PieRenderer extends OverlayRenderer if (isVisible()) { PieItem item = mCurrentItem; if (mTapMode) { - item = findItem(polar); + item = findItem(mPolar); if (mOpening) { mOpening = false; return true; @@ -582,7 +595,7 @@ public class PieRenderer extends OverlayRenderer mHandler.removeMessages(MSG_OPENSUBMENU); return false; } else if (MotionEvent.ACTION_MOVE == action) { - if (pulledToCenter(polar)) { + if (pulledToCenter(mPolar)) { mHandler.removeMessages(MSG_OPENSUBMENU); if (hasOpenItem()) { if (mCurrentItem != null) { @@ -595,7 +608,7 @@ public class PieRenderer extends OverlayRenderer } return false; } - PieItem item = findItem(polar); + PieItem item = findItem(mPolar); boolean moved = hasMoved(evt); if ((item != null) && (mCurrentItem != item) && (!mOpening || moved)) { mHandler.removeMessages(MSG_OPENSUBMENU); @@ -612,24 +625,32 @@ public class PieRenderer extends OverlayRenderer } private boolean pulledToCenter(PointF polarCoords) { - return polarCoords.y < mIconRadius - mArcOffset; + return polarCoords.y < mArcRadius - mRadiusInc; } - private PointF getPolar(float x, float y, boolean useOffset) { - PointF res = new PointF(); + private boolean inside(PointF polar, PieItem item) { + float start = getSliceCenter(item) - SWEEP_SLICE / 2f; + boolean res = (mArcRadius < polar.y) + && (start < polar.x) + && (start + SWEEP_SLICE > polar.x) + && (!mTapMode || (mArcRadius + mRadiusInc > polar.y)); + return res; + } + + private void getPolar(float x, float y, boolean useOffset, PointF res) { // get angle and radius from x/y res.x = (float) Math.PI / 2; - x = x - mSliceCenter.x; - y = mSliceCenter.y - getLevel() * mTouchOffset - y; - res.y = (float) Math.sqrt(x * x + y * y); + x = x - mPieCenterX; + float y1 = mSliceCenterY - getLevel() * mRadiusInc - y; + float y2 = mArcCenterY - getLevel() * mRadiusInc - y; + res.y = (float) Math.sqrt(x * x + y2 * y2); if (x != 0) { - res.x = (float) Math.atan2(y, x); + res.x = (float) Math.atan2(y1, x); if (res.x < 0) { res.x = (float) (2 * Math.PI + res.x); } } res.y = res.y + (useOffset ? mTouchOffset : 0); - return res; } private boolean hasMoved(MotionEvent e) { @@ -733,12 +754,6 @@ public class PieRenderer extends OverlayRenderer return null; } - private boolean inside(PointF polar, PieItem item) { - return (item.getInnerRadius() < polar.y) - && (item.getStartAngle() < polar.x) - && (item.getStartAngle() + item.getSweep() > polar.x) - && (!mTapMode || (item.getOuterRadius() > polar.y)); - } @Override public boolean handlesTouch() { diff --git a/src/com/android/camera/ui/RotatableLayout.java b/src/com/android/camera/ui/RotatableLayout.java index 4edec5dd7..6836b39b2 100644 --- a/src/com/android/camera/ui/RotatableLayout.java +++ b/src/com/android/camera/ui/RotatableLayout.java @@ -39,6 +39,10 @@ public class RotatableLayout extends FrameLayout { private static final String TAG = "RotatableLayout"; private int mPrevRotation; + private RotationListener mListener = null; + public interface RotationListener { + public void onRotation(int rotation); + } public RotatableLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @@ -53,12 +57,15 @@ public class RotatableLayout extends FrameLayout { @Override public void onFinishInflate() { // get initial orientation + super.onFinishInflate(); mPrevRotation = Util.getDisplayRotation((Activity) getContext()); } @Override public void onConfigurationChanged(Configuration config) { super.onConfigurationChanged(config); + int rotation = Util.getDisplayRotation((Activity) getContext()); + boolean clockwise = isClockWiseRotation(mPrevRotation, rotation); // Change the size of the layout ViewGroup.LayoutParams lp = getLayoutParams(); int width = lp.width; @@ -66,15 +73,33 @@ public class RotatableLayout extends FrameLayout { lp.height = width; lp.width = height; setLayoutParams(lp); + // rotate all the children - int rotation = Util.getDisplayRotation((Activity) getContext()); - boolean clockwise = isClockWiseRotation(mPrevRotation, rotation); mPrevRotation = rotation; + rotateChildren(clockwise); + } + + protected void rotateChildren(boolean clockwise) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); rotate(child, clockwise); } + if (mListener != null) mListener.onRotation(clockwise ? 90 : 270); + } + + protected void flipChildren() { + mPrevRotation = Util.getDisplayRotation((Activity) getContext()); + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + flip(child); + } + if (mListener != null) mListener.onRotation(180); + } + + public void setRotationListener(RotationListener listener) { + mListener = listener; } public static boolean isClockWiseRotation(int prevRotation, int currentRotation) { @@ -181,4 +206,10 @@ public class RotatableLayout extends FrameLayout { lp.height = width; view.setLayoutParams(lp); } + + // Rotate a given view 180 degrees + public static void flip(View view) { + rotateClockwise(view); + rotateClockwise(view); + } }
\ No newline at end of file diff --git a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java index 8c312a92b..055309f22 100644 --- a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java @@ -283,6 +283,13 @@ public class CachingPipeline { || request.getType() == RenderingRequest.ICON_RENDERING || request.getType() == RenderingRequest.PARTIAL_RENDERING || request.getType() == RenderingRequest.HIGHRES_RENDERING) { + + if (request.getType() == RenderingRequest.ICON_RENDERING) { + mEnvironment.setQuality(ImagePreset.QUALITY_ICON); + } else { + mEnvironment.setQuality(ImagePreset.QUALITY_PREVIEW); + } + Bitmap bmp = preset.apply(bitmap, mEnvironment); request.setBitmap(bmp); mFiltersManager.freeFilterResources(preset); @@ -393,7 +400,9 @@ public class CachingPipeline { mOutPixelsAllocation.getType()); needsUpdate = true; } - mInPixelsAllocation.copyFrom(bitmap); + if (RS != null) { + mInPixelsAllocation.copyFrom(bitmap); + } if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { mWidth = bitmap.getWidth(); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java index 2aeaed877..a0523c14e 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java @@ -16,7 +16,6 @@ package com.android.gallery3d.filtershow.filters; -import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v8.renderscript.*; @@ -28,6 +27,8 @@ import com.android.gallery3d.filtershow.cache.CachingPipeline; public abstract class ImageFilterRS extends ImageFilter { private static final String LOGTAG = "ImageFilterRS"; private boolean DEBUG = false; + private int mLastInputWidth = 0; + private int mLastInputHeight = 0; private volatile boolean mResourcesLoaded = false; @@ -65,11 +66,19 @@ public abstract class ImageFilterRS extends ImageFilter { Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName()); } Resources rsc = pipeline.getResources(); + boolean sizeChanged = false; + if (getInPixelsAllocation() != null + && ((getInPixelsAllocation().getType().getX() != mLastInputWidth) + || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) { + sizeChanged = true; + } if (pipeline.prepareRenderscriptAllocations(bitmap) - || !isResourcesLoaded()) { + || !isResourcesLoaded() || sizeChanged) { freeResources(); createFilter(rsc, scaleFactor, quality); setResourcesLoaded(true); + mLastInputWidth = getInPixelsAllocation().getType().getX(); + mLastInputHeight = getInPixelsAllocation().getType().getY(); } bindScriptValues(); runFilter(); diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java index 6c3417ad3..8fcc028af 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java @@ -83,8 +83,8 @@ public class ImageDraw extends ImageShow { float[] mTmpPoint = new float[2]; // so we do not malloc @Override public boolean onTouchEvent(MotionEvent event) { - boolean ret = super.onTouchEvent(event); if (event.getPointerCount() > 1) { + boolean ret = super.onTouchEvent(event); if (mFRep.getCurrentDrawing() != null) { mFRep.clearCurrentSection(); mEditorDraw.commitLocalRepresentation(); @@ -93,7 +93,7 @@ public class ImageDraw extends ImageShow { } if (event.getAction() != MotionEvent.ACTION_DOWN) { if (mFRep.getCurrentDrawing() == null) { - return ret; + return super.onTouchEvent(event); } } diff --git a/src_pd/com/android/gallery3d/util/UsageStatistics.java b/src_pd/com/android/gallery3d/util/UsageStatistics.java index cf27ac58f..9246ab10a 100644 --- a/src_pd/com/android/gallery3d/util/UsageStatistics.java +++ b/src_pd/com/android/gallery3d/util/UsageStatistics.java @@ -36,6 +36,10 @@ public class UsageStatistics { public static final String TRANSITION_BUTTON_TAP = "ButtonTap"; public static final String TRANSITION_SWIPE = "Swipe"; + public static final String ACTION_CAPTURE_START = "CaptureStart"; + public static final String ACTION_CAPTURE_FAIL = "CaptureFail"; + public static final String ACTION_CAPTURE_DONE = "CaptureDone"; + public static void initialize(Context context) {} public static void showOptInDialogIfNeeded(Activity activity) {} public static void setPendingTransitionCause(String cause) {} diff --git a/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java b/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java index 8c4fc3dea..1286c5801 100644 --- a/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java +++ b/tests/src/com/android/gallery3d/exif/ExifOutputStreamTest.java @@ -18,6 +18,7 @@ package com.android.gallery3d.exif; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.util.Log; import java.io.ByteArrayInputStream; import java.io.File; @@ -131,6 +132,60 @@ public class ExifOutputStreamTest extends ExifXmlDataTestCase { } } + public void testOutputSpeed() throws Exception { + final String LOGTAG = "testOutputSpeed"; + InputStream imageInputStream = null; + OutputStream imageOutputStream = null; + try { + try { + imageInputStream = getImageInputStream(); + // Read the image data + Bitmap bmp = BitmapFactory.decodeStream(imageInputStream); + // The image is invalid + if (bmp == null) { + return; + } + imageInputStream.close(); + int nLoops = 20; + long totalReadDuration = 0; + long totalWriteDuration = 0; + for (int i = 0; i < nLoops; i++) { + imageInputStream = reopenFileStream(); + // Read exif data + long startTime = System.nanoTime(); + ExifData exifData = new ExifReader(mInterface).read(imageInputStream); + long endTime = System.nanoTime(); + long duration = endTime - startTime; + totalReadDuration += duration; + Log.v(LOGTAG, " read time: " + duration); + imageInputStream.close(); + + // Encode the image with the exif data + imageOutputStream = (OutputStream) new FileOutputStream(mTmpFile); + ExifOutputStream exifOutputStream = new ExifOutputStream(imageOutputStream, + mInterface); + exifOutputStream.setExifData(exifData); + startTime = System.nanoTime(); + bmp.compress(Bitmap.CompressFormat.JPEG, 90, exifOutputStream); + endTime = System.nanoTime(); + duration = endTime - startTime; + totalWriteDuration += duration; + Log.v(LOGTAG, " write time: " + duration); + exifOutputStream.close(); + } + Log.v(LOGTAG, "======================= normal"); + Log.v(LOGTAG, "avg read time: " + totalReadDuration / nLoops); + Log.v(LOGTAG, "avg write time: " + totalWriteDuration / nLoops); + Log.v(LOGTAG, "======================="); + } finally { + Util.closeSilently(imageInputStream); + Util.closeSilently(imageOutputStream); + } + } catch (Exception e) { + throw new Exception(getImageTitle(), e); + } + } + @Override public void tearDown() throws Exception { super.tearDown(); diff --git a/tests/src/com/android/gallery3d/exif/ExifXmlDataTestCase.java b/tests/src/com/android/gallery3d/exif/ExifXmlDataTestCase.java index 5f200ea92..da860208b 100644 --- a/tests/src/com/android/gallery3d/exif/ExifXmlDataTestCase.java +++ b/tests/src/com/android/gallery3d/exif/ExifXmlDataTestCase.java @@ -92,4 +92,17 @@ public class ExifXmlDataTestCase extends InstrumentationTestCase { return String.format(RES_ID_TITLE, mImageResourceId); } } + + protected InputStream reopenFileStream() throws Exception { + try { + if (mImagePath != null) { + return new FileInputStream(mImagePath); + } else { + Resources res = getInstrumentation().getContext().getResources(); + return res.openRawResource(mImageResourceId); + } + } catch (Exception e) { + throw new Exception(getImageTitle(), e); + } + } } |