summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/camera/CameraSettings.java8
-rw-r--r--src/com/android/camera/Exif.java45
-rw-r--r--src/com/android/camera/PanoramaModule.java51
-rw-r--r--src/com/android/camera/VideoController.java36
-rw-r--r--src/com/android/camera/VideoMenu.java31
-rw-r--r--src/com/android/camera/VideoModule.java700
-rw-r--r--src/com/android/camera/VideoUI.java510
-rw-r--r--src/com/android/gallery3d/data/Exif.java44
-rw-r--r--src/com/android/gallery3d/data/LocalImage.java74
-rw-r--r--src/com/android/gallery3d/data/MediaDetails.java74
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java2
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java50
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java6
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java181
-rw-r--r--src/com/android/gallery3d/filtershow/ui/FilterIconButton.java73
-rw-r--r--src/com/android/gallery3d/filtershow/ui/IconButton.java45
-rw-r--r--src/com/android/photos/canvas/CanvasProvider.java4
-rw-r--r--src/com/android/photos/data/PhotoProvider.java4
18 files changed, 965 insertions, 973 deletions
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 64f3681de..7c7ed389e 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -235,8 +235,8 @@ public class CameraSettings {
private void buildExposureCompensation(
PreferenceGroup group, IconListPreference exposure) {
- int max = Math.min(3, mParameters.getMaxExposureCompensation());
- int min = Math.max(-3, mParameters.getMinExposureCompensation());
+ int max = mParameters.getMaxExposureCompensation();
+ int min = mParameters.getMinExposureCompensation();
if (max == 0 && min == 0) {
removePreference(group, exposure.getKey());
return;
@@ -244,8 +244,8 @@ public class CameraSettings {
float step = mParameters.getExposureCompensationStep();
// show only integer values for exposure compensation
- int maxValue = (int) FloatMath.floor(max * step);
- int minValue = (int) FloatMath.ceil(min * step);
+ int maxValue = Math.min(3, (int) FloatMath.floor(max * step));
+ int minValue = Math.max(-3, (int) FloatMath.ceil(min * step));
CharSequence entries[] = new CharSequence[maxValue - minValue + 1];
CharSequence entryValues[] = new CharSequence[maxValue - minValue + 1];
int[] icons = new int[maxValue - minValue + 1];
diff --git a/src/com/android/camera/Exif.java b/src/com/android/camera/Exif.java
index 605556599..ee39d675e 100644
--- a/src/com/android/camera/Exif.java
+++ b/src/com/android/camera/Exif.java
@@ -18,9 +18,7 @@ package com.android.camera;
import android.util.Log;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifParser;
-import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.exif.ExifInterface;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -31,44 +29,23 @@ public class Exif {
// Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
public static int getOrientation(byte[] jpeg) {
- if (jpeg == null) return 0;
+ if (jpeg == null) {
+ return 0;
+ }
+ ExifInterface exif = new ExifInterface();
InputStream is = new ByteArrayInputStream(jpeg);
-
try {
- ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
- int event = parser.next();
- while(event != ExifParser.EVENT_END) {
- if (event == ExifParser.EVENT_NEW_TAG) {
- ExifTag tag = parser.getTag();
- if (tag.getTagId() == ExifTag.TAG_ORIENTATION &&
- tag.hasValue()) {
- int orient = (int) tag.getValueAt(0);
- switch (orient) {
- case ExifTag.Orientation.TOP_LEFT:
- return 0;
- case ExifTag.Orientation.BOTTOM_LEFT:
- return 180;
- case ExifTag.Orientation.RIGHT_TOP:
- return 90;
- case ExifTag.Orientation.RIGHT_BOTTOM:
- return 270;
- default:
- Log.i(TAG, "Unsupported orientation");
- return 0;
- }
- }
- }
- event = parser.next();
+ exif.readExif(is);
+ Integer val = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+ if (val == null) {
+ return 0;
+ } else {
+ return ExifInterface.getRotationForOrientationValue(val.shortValue());
}
- Log.i(TAG, "Orientation not found");
- return 0;
} catch (IOException e) {
Log.w(TAG, "Failed to read EXIF orientation", e);
return 0;
- } catch (ExifInvalidFormatException e) {
- Log.w(TAG, "Failed to read EXIF orientation", e);
- return 0;
}
}
}
diff --git a/src/com/android/camera/PanoramaModule.java b/src/com/android/camera/PanoramaModule.java
index 623d96dc6..dc27f56f1 100644
--- a/src/com/android/camera/PanoramaModule.java
+++ b/src/com/android/camera/PanoramaModule.java
@@ -60,10 +60,7 @@ 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;
-import com.android.gallery3d.exif.ExifOutputStream;
-import com.android.gallery3d.exif.ExifReader;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.exif.ExifTag;
import com.android.gallery3d.ui.GLRootView;
import com.android.gallery3d.util.UsageStatistics;
@@ -913,31 +910,18 @@ public class PanoramaModule implements CameraModule,
mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken);
String filepath = Storage.generateFilepath(filename);
- ExifOutputStream out = null;
- InputStream is = null;
+ ExifInterface exif = new ExifInterface();
try {
- is = new ByteArrayInputStream(jpegData);
- ExifReader reader = new ExifReader();
- ExifData data = reader.read(is);
-
- // Add Exif tags.
- data.addGpsDateTimeStampTag(mTimeTaken);
- data.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, mTimeTaken, TimeZone.getDefault());
- data.addTag(ExifTag.TAG_ORIENTATION).
- setValue(getExifOrientation(orientation));
-
- out = new ExifOutputStream(new FileOutputStream(filepath));
- out.setExifData(data);
- out.write(jpegData);
+ exif.readExif(jpegData);
+ exif.addGpsDateTimeStampTag(mTimeTaken);
+ exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, mTimeTaken,
+ TimeZone.getDefault());
+ exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION,
+ ExifInterface.getOrientationValueForRotation(orientation)));
+ exif.writeExif(jpegData, filepath);
} catch (IOException e) {
- Log.e(TAG, "Cannot set EXIF for " + filepath, e);
+ Log.e(TAG, "Cannot set exif for " + filepath, e);
Storage.writeFile(filepath, jpegData);
- } catch (ExifInvalidFormatException e) {
- Log.e(TAG, "Cannot set EXIF for " + filepath, e);
- Storage.writeFile(filepath, jpegData);
- } finally {
- Util.closeSilently(out);
- Util.closeSilently(is);
}
int jpegLength = (int) (new File(filepath).length());
@@ -947,21 +931,6 @@ public class PanoramaModule implements CameraModule,
return null;
}
- private static int getExifOrientation(int orientation) {
- switch (orientation) {
- case 0:
- return ExifTag.Orientation.TOP_LEFT;
- case 90:
- return ExifTag.Orientation.RIGHT_TOP;
- case 180:
- return ExifTag.Orientation.BOTTOM_LEFT;
- case 270:
- return ExifTag.Orientation.RIGHT_BOTTOM;
- default:
- throw new AssertionError("invalid: " + orientation);
- }
- }
-
private void clearMosaicFrameProcessorIfNeeded() {
if (!mPaused || mThreadRunning) return;
// Only clear the processor if it is initialized by this activity
diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java
new file mode 100644
index 000000000..8bde8090f
--- /dev/null
+++ b/src/com/android/camera/VideoController.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import android.view.View;
+
+import com.android.camera.ShutterButton.OnShutterButtonListener;
+
+public interface VideoController extends OnShutterButtonListener {
+
+ public void onReviewDoneClicked(View view);
+ public void onReviewCancelClicked(View viwe);
+ public void onReviewPlayClicked(View view);
+
+ public boolean isVideoCaptureIntent();
+
+ public int onZoomChanged(int index);
+
+ public void onSingleTapUp(View view, int x, int y);
+
+ public void stopPreview();
+}
diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java
index ab53e1546..aa3a80716 100644
--- a/src/com/android/camera/VideoMenu.java
+++ b/src/com/android/camera/VideoMenu.java
@@ -33,11 +33,10 @@ public class VideoMenu extends PieController
ListPrefSettingPopup.Listener,
TimeIntervalPopup.Listener {
-
- private static String TAG = "CAM_videocontrol";
+ private static String TAG = "CAM_VideoMenu";
private static float FLOAT_PI_DIVIDED_BY_TWO = (float) Math.PI / 2;
- private VideoModule mModule;
+ private VideoUI mUI;
private String[] mOtherKeys;
private AbstractSettingPopup mPopup;
@@ -46,9 +45,9 @@ public class VideoMenu extends PieController
private static final int POPUP_SECOND_LEVEL = 2;
private int mPopupStatus;
- public VideoMenu(CameraActivity activity, VideoModule module, PieRenderer pie) {
+ public VideoMenu(CameraActivity activity, VideoUI ui, PieRenderer pie) {
super(activity, pie);
- mModule = module;
+ mUI = ui;
}
public void initialize(PreferenceGroup group) {
@@ -60,7 +59,7 @@ public class VideoMenu extends PieController
addItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, FLOAT_PI_DIVIDED_BY_TWO - sweep, sweep);
addItem(CameraSettings.KEY_WHITE_BALANCE, 3 * FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep);
PieItem item = makeItem(R.drawable.ic_switch_video_facing_holo_light);
- item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep);
+ item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO + sweep, sweep);
item.setOnClickListener(new OnClickListener() {
@Override
@@ -81,7 +80,8 @@ public class VideoMenu extends PieController
CameraSettings.KEY_VIDEO_EFFECT,
CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
CameraSettings.KEY_VIDEO_QUALITY,
- CameraSettings.KEY_RECORD_LOCATION};
+ CameraSettings.KEY_RECORD_LOCATION
+ };
item = makeItem(R.drawable.ic_settings_holo_light);
item.setFixedSlice(FLOAT_PI_DIVIDED_BY_TWO * 3, sweep);
@@ -92,17 +92,12 @@ public class VideoMenu extends PieController
initializePopup();
mPopupStatus = POPUP_FIRST_LEVEL;
}
- mModule.showPopup(mPopup);
+ mUI.showPopup(mPopup);
}
});
mRenderer.addItem(item);
}
- protected void setCameraId(int cameraId) {
- ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
- pref.setValue("" + cameraId);
- }
-
@Override
public void reloadPreferences() {
super.reloadPreferences();
@@ -126,7 +121,7 @@ public class VideoMenu extends PieController
public void onListPrefChanged(ListPreference pref) {
if (mPopup != null) {
if (mPopupStatus == POPUP_SECOND_LEVEL) {
- mModule.dismissPopup(true);
+ mUI.dismissPopup(true);
}
}
super.onSettingChanged(pref);
@@ -152,7 +147,7 @@ public class VideoMenu extends PieController
if (mPopupStatus == POPUP_SECOND_LEVEL) {
initializePopup();
mPopupStatus = POPUP_FIRST_LEVEL;
- if (topPopupOnly) mModule.showPopup(mPopup);
+ if (topPopupOnly) mUI.showPopup(mPopup);
}
}
@@ -170,17 +165,17 @@ public class VideoMenu extends PieController
R.layout.time_interval_popup, null, false);
timeInterval.initialize((IconListPreference) pref);
timeInterval.setSettingChangedListener(this);
- mModule.dismissPopup(true);
+ mUI.dismissPopup(true);
mPopup = timeInterval;
} else {
ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate(
R.layout.list_pref_setting_popup, null, false);
basic.initialize(pref);
basic.setSettingChangedListener(this);
- mModule.dismissPopup(true);
+ mUI.dismissPopup(true);
mPopup = basic;
}
- mModule.showPopup(mPopup);
+ mUI.showPopup(mPopup);
mPopupStatus = POPUP_SECOND_LEVEL;
}
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 4ae46a897..115b7d0a7 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -47,33 +47,15 @@ import android.os.SystemClock;
import android.provider.MediaStore;
import android.provider.MediaStore.Video;
import android.util.Log;
-import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
-import android.view.SurfaceHolder;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import android.widget.Toast;
-import com.android.camera.ui.AbstractSettingPopup;
-import com.android.camera.ui.PieRenderer;
import com.android.camera.ui.PopupManager;
-import com.android.camera.ui.PreviewSurfaceView;
-import com.android.camera.ui.RenderOverlay;
-import com.android.camera.ui.Rotatable;
-import com.android.camera.ui.RotateImageView;
-import com.android.camera.ui.RotateLayout;
import com.android.camera.ui.RotateTextToast;
-import com.android.camera.ui.ZoomRenderer;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.util.AccessibilityUtils;
@@ -87,13 +69,12 @@ import java.util.Iterator;
import java.util.List;
public class VideoModule implements CameraModule,
+ VideoController,
CameraPreference.OnPreferenceChangedListener,
ShutterButton.OnShutterButtonListener,
MediaRecorder.OnErrorListener,
MediaRecorder.OnInfoListener,
- EffectsRecorder.EffectsListener,
- PieRenderer.PieListener,
- PreviewGestures.SingleTapListener {
+ EffectsRecorder.EffectsListener {
private static final String TAG = "CAM_VideoModule";
@@ -124,7 +105,6 @@ public class VideoModule implements CameraModule,
private static final int MIN_THUMB_SIZE = 64;
// module fields
private CameraActivity mActivity;
- private View mRootView;
private boolean mPaused;
private int mCameraId;
private Parameters mParameters;
@@ -140,24 +120,8 @@ public class VideoModule implements CameraModule,
private ComboPreferences mPreferences;
private PreferenceGroup mPreferenceGroup;
- private PreviewFrameLayout mPreviewFrameLayout;
- private boolean mSurfaceViewReady;
- private SurfaceHolder.Callback mSurfaceViewCallback;
- private PreviewSurfaceView mPreviewSurfaceView;
private CameraScreenNail.OnFrameDrawnListener mFrameDrawnListener;
- // An review image having same size as preview. It is displayed when
- // recording is stopped in capture intent.
- private ImageView mReviewImage;
- private View mReviewCancelButton;
- private View mReviewDoneButton;
- private View mReviewPlayButton;
- private ShutterButton mShutterButton;
- private TextView mRecordingTimeView;
- private RotateLayout mBgLearningMessageRotater;
- private View mBgLearningMessageFrame;
- private LinearLayout mLabelsLinearLayout;
-
private boolean mIsVideoCaptureIntent;
private boolean mQuickCapture;
@@ -175,7 +139,6 @@ public class VideoModule implements CameraModule,
private boolean mMediaRecorderRecording = false;
private long mRecordingStartTime;
private boolean mRecordingTimeCountsDown = false;
- private RotateLayout mRecordingTimeRect;
private long mOnResumeTime;
// The video file that the hardware camera is about to record into
// (or is recording into.)
@@ -197,10 +160,6 @@ public class VideoModule implements CameraModule,
private boolean mCaptureTimeLapse = false;
// Default 0. If it is larger than 0, the camcorder is in time lapse mode.
private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
- private View mTimeLapseLabel;
-
- private int mDesiredPreviewWidth;
- private int mDesiredPreviewHeight;
boolean mPreviewing = false; // True if preview is started.
// The display rotation in degrees. This is only valid when mPreviewing is
@@ -208,35 +167,23 @@ public class VideoModule implements CameraModule,
private int mDisplayRotation;
private int mCameraDisplayOrientation;
+ private int mDesiredPreviewWidth;
+ private int mDesiredPreviewHeight;
private ContentResolver mContentResolver;
private LocationManager mLocationManager;
private VideoNamer mVideoNamer;
- private RenderOverlay mRenderOverlay;
- private PieRenderer mPieRenderer;
-
- private VideoMenu mVideoControl;
- private AbstractSettingPopup mPopup;
private int mPendingSwitchCameraId;
- private ZoomRenderer mZoomRenderer;
-
- private PreviewGestures mGestures;
- private View mMenu;
- private View mBlocker;
- private View mOnScreenIndicators;
- private ImageView mFlashIndicator;
-
private final Handler mHandler = new MainHandler();
-
+ private VideoUI mUI;
// The degrees of the device rotated clockwise from its natural orientation.
private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
private int mZoomValue; // The current zoom value.
- private int mZoomMax;
- private List<Integer> mZoomRatios;
+
private boolean mRestoreFlash; // This is used to check if we need to restore the flash
// status when going back from gallery.
@@ -282,7 +229,7 @@ public class VideoModule implements CameraModule,
switch (msg.what) {
case ENABLE_SHUTTER_BUTTON:
- mShutterButton.setEnabled(true);
+ mUI.enableShutter(true);
break;
case CLEAR_SCREEN_DELAY: {
@@ -331,7 +278,7 @@ public class VideoModule implements CameraModule,
}
case HIDE_SURFACE_VIEW: {
- mPreviewSurfaceView.setVisibility(View.GONE);
+ mUI.hideSurfaceView();
break;
}
@@ -377,65 +324,21 @@ public class VideoModule implements CameraModule,
}
private void initializeSurfaceView() {
- mPreviewSurfaceView = (PreviewSurfaceView) mRootView.findViewById(R.id.preview_surface_view);
- if (!ApiHelper.HAS_SURFACE_TEXTURE) { // API level < 11
- if (mSurfaceViewCallback == null) {
- mSurfaceViewCallback = new SurfaceViewCallback();
- }
- mPreviewSurfaceView.getHolder().addCallback(mSurfaceViewCallback);
- mPreviewSurfaceView.setVisibility(View.VISIBLE);
- } else if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16
- if (mSurfaceViewCallback == null) {
- mSurfaceViewCallback = new SurfaceViewCallback();
+ if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16
mFrameDrawnListener = new CameraScreenNail.OnFrameDrawnListener() {
@Override
public void onFrameDrawn(CameraScreenNail c) {
mHandler.sendEmptyMessage(HIDE_SURFACE_VIEW);
}
};
- }
- mPreviewSurfaceView.getHolder().addCallback(mSurfaceViewCallback);
- }
- }
-
- private void initializeOverlay() {
- mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
- if (mPieRenderer == null) {
- mPieRenderer = new PieRenderer(mActivity);
- mVideoControl = new VideoMenu(mActivity, this, mPieRenderer);
- mVideoControl.setListener(this);
- mPieRenderer.setPieListener(this);
- }
- mRenderOverlay.addRenderer(mPieRenderer);
- if (mZoomRenderer == null) {
- mZoomRenderer = new ZoomRenderer(mActivity);
- }
- mRenderOverlay.addRenderer(mZoomRenderer);
- if (mGestures == null) {
- mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
- }
- mGestures.setRenderOverlay(mRenderOverlay);
- mGestures.clearTouchReceivers();
- mGestures.addTouchReceiver(mMenu);
- mGestures.addTouchReceiver(mBlocker);
-
- if (isVideoCaptureIntent()) {
- if (mReviewCancelButton != null) {
- mGestures.addTouchReceiver(mReviewCancelButton);
- }
- if (mReviewDoneButton != null) {
- mGestures.addTouchReceiver(mReviewDoneButton);
- }
- if (mReviewPlayButton != null) {
- mGestures.addTouchReceiver(mReviewPlayButton);
- }
+ mUI.getSurfaceHolder().addCallback(mUI);
}
}
@Override
public void init(CameraActivity activity, View root, boolean reuseScreenNail) {
mActivity = activity;
- mRootView = root;
+ mUI = new VideoUI(activity, this, root);
mPreferences = new ComboPreferences(mActivity);
CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
mCameraId = getPreferredCameraId(mPreferences);
@@ -456,8 +359,6 @@ public class VideoModule implements CameraModule,
mContentResolver = mActivity.getContentResolver();
- mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
-
// Surface texture is from camera screen nail and startPreview needs it.
// This must be done before startPreview.
mIsVideoCaptureIntent = isVideoCaptureIntent();
@@ -483,6 +384,7 @@ public class VideoModule implements CameraModule,
}
readVideoPreferences();
+ mUI.setPrefChangedListener(this);
new Thread(new Runnable() {
@Override
public void run() {
@@ -490,23 +392,63 @@ public class VideoModule implements CameraModule,
}
}).start();
- initializeControlByIntent();
- initializeOverlay();
- initializeMiscControls();
-
mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
mLocationManager = new LocationManager(mActivity, null);
- setOrientationIndicator(0, false);
+ mUI.setOrientationIndicator(0, false);
setDisplayOrientation();
- showTimeLapseUI(mCaptureTimeLapse);
+ mUI.showTimeLapseUI(mCaptureTimeLapse);
initializeVideoSnapshot();
resizeForPreviewAspectRatio();
initializeVideoControl();
mPendingSwitchCameraId = -1;
- updateOnScreenIndicators();
+ mUI.updateOnScreenIndicators(mParameters);
+
+ // Disable the shutter button if effects are ON since it might take
+ // a little more time for the effects preview to be ready. We do not
+ // want to allow recording before that happens. The shutter button
+ // will be enabled when we get the message from effectsrecorder that
+ // the preview is running. This becomes critical when the camera is
+ // swapped.
+ if (effectsActive()) {
+ mUI.enableShutter(false);
+ }
+ }
+
+ // SingleTapListener
+ // Preview area is touched. Take a picture.
+ @Override
+ public void onSingleTapUp(View view, int x, int y) {
+ if (mMediaRecorderRecording && effectsActive()) {
+ new RotateTextToast(mActivity, R.string.disable_video_snapshot_hint,
+ mOrientation).show();
+ return;
+ }
+
+ MediaSaveService s = mActivity.getMediaSaveService();
+ if (mPaused || mSnapshotInProgress || effectsActive() || s == null || s.isQueueFull()) {
+ return;
+ }
+
+ if (!mMediaRecorderRecording) {
+ // check for dismissing popup
+ mUI.dismissPopup(true);
+ return;
+ }
+
+ // Set rotation and gps data.
+ int rotation = Util.getJpegRotation(mCameraId, mOrientation);
+ mParameters.setRotation(rotation);
+ Location loc = mLocationManager.getCurrentLocation();
+ Util.setGpsParameters(mParameters, loc);
+ mActivity.mCameraDevice.setParameters(mParameters);
+
+ Log.v(TAG, "Video snapshot start");
+ mActivity.mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc));
+ showVideoSnapshotUI(true);
+ mSnapshotInProgress = true;
}
@Override
@@ -520,37 +462,11 @@ public class VideoModule implements CameraModule,
settings.getPreferenceGroup(R.xml.video_preferences));
}
- public boolean collapseCameraControls() {
- boolean ret = false;
- if (mPopup != null) {
- dismissPopup(false);
- ret = true;
- }
- return ret;
- }
-
- public boolean removeTopLevelPopup() {
- if (mPopup != null) {
- dismissPopup(true);
- return true;
- }
- return false;
- }
-
- private void enableCameraControls(boolean enable) {
- if (mGestures != null) {
- mGestures.setZoomOnly(!enable);
- }
- if (mPieRenderer != null && mPieRenderer.showsItems()) {
- mPieRenderer.hide();
- }
- }
-
private void initializeVideoControl() {
loadCameraPreferences();
- mVideoControl.initialize(mPreferenceGroup);
+ mUI.initializePopup(mPreferenceGroup);
if (effectsActive()) {
- mVideoControl.overrideSettings(
+ mUI.overrideSettings(
CameraSettings.KEY_VIDEO_QUALITY,
Integer.toString(getLowVideoQuality()));
}
@@ -593,28 +509,6 @@ public class VideoModule implements CameraModule,
}
}
- private void setOrientationIndicator(int orientation, boolean animation) {
- Rotatable[] indicators = {
- mBgLearningMessageRotater};
- for (Rotatable indicator : indicators) {
- if (indicator != null) indicator.setOrientation(orientation, animation);
- }
- if (mGestures != null) {
- mGestures.setOrientation(orientation);
- }
-
- // We change the orientation of the linearlayout only for phone UI because when in portrait
- // the width is not enough.
- if (mLabelsLinearLayout != null) {
- if (((orientation / 90) & 1) == 0) {
- mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
- } else {
- mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
- }
- }
- mRecordingTimeRect.setOrientation(0, animation);
- }
-
private void startPlayVideoActivity() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(mCurrentVideoUri, convertOutputFormatToMimeType(mProfile.fileFormat));
@@ -671,7 +565,7 @@ public class VideoModule implements CameraModule,
@Override
public void onShutterButtonClick() {
- if (collapseCameraControls() || mSwitchingCamera) return;
+ if (mUI.collapseCameraControls() || mSwitchingCamera) return;
boolean stop = mMediaRecorderRecording;
@@ -680,7 +574,7 @@ public class VideoModule implements CameraModule,
} else {
startVideoRecording();
}
- mShutterButton.setEnabled(false);
+ mUI.enableShutter(false);
// Keep the shutter button disabled when in video capture intent
// mode and recording is stopped. It'll be re-enabled when
@@ -794,7 +688,7 @@ public class VideoModule implements CameraModule,
}
private void resizeForPreviewAspectRatio() {
- mPreviewFrameLayout.setAspectRatio(
+ mUI.setAspectRatio(
(double) mProfile.videoFrameWidth / mProfile.videoFrameHeight);
}
@@ -818,18 +712,13 @@ public class VideoModule implements CameraModule,
public void onResumeAfterSuper() {
if (mActivity.mOpenCameraFail || mActivity.mCameraDisabled)
return;
- if (mShutterButton != null) {
- mShutterButton.setEnabled(false);
- }
+ mUI.enableShutter(false);
mZoomValue = 0;
showVideoSnapshotUI(false);
-
if (!mPreviewing) {
- if (resetEffect()) {
- mBgLearningMessageFrame.setVisibility(View.GONE);
- }
+ resetEffect();
openCamera();
if (mActivity.mOpenCameraFail) {
Util.showErrorAndFinish(mActivity,
@@ -850,7 +739,7 @@ public class VideoModule implements CameraModule,
}
// Initializing it here after the preview is started.
- initializeZoom();
+ mUI.initializeZoom(mParameters);
keepScreenOnAwhile();
@@ -884,6 +773,19 @@ public class VideoModule implements CameraModule,
mActivity.getGLRoot().requestLayoutContentPane();
}
+ @Override
+ public int onZoomChanged(int index) {
+ // Not useful to change zoom value when the activity is paused.
+ if (mPaused) return index;
+ mZoomValue = index;
+ if (mParameters == null || mActivity.mCameraDevice == null) return index;
+ // Set zoom parameters asynchronously
+ mParameters.setZoom(mZoomValue);
+ mActivity.mCameraDevice.setParametersAsync(mParameters);
+ Parameters p = mActivity.mCameraDevice.getParameters();
+ if (p != null) return p.getZoom();
+ return index;
+ }
private void startPreview() {
Log.v(TAG, "startPreview");
@@ -896,7 +798,6 @@ public class VideoModule implements CameraModule,
}
}
-
setDisplayOrientation();
mActivity.mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
setCameraParameters();
@@ -911,7 +812,7 @@ public class VideoModule implements CameraModule,
}
mActivity.mCameraDevice.setPreviewTextureAsync(surfaceTexture);
} else {
- mActivity.mCameraDevice.setPreviewDisplayAsync(mPreviewSurfaceView.getHolder());
+ mActivity.mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder());
}
mActivity.mCameraDevice.startPreviewAsync();
mPreviewing = true;
@@ -941,12 +842,11 @@ public class VideoModule implements CameraModule,
}
private void onPreviewStarted() {
- if (mShutterButton != null) {
- mShutterButton.setEnabled(true);
- }
+ mUI.enableShutter(true);
}
- private void stopPreview() {
+ @Override
+ public void stopPreview() {
mActivity.mCameraDevice.stopPreview();
mPreviewing = false;
}
@@ -1013,7 +913,7 @@ public class VideoModule implements CameraModule,
screenNail.releaseSurfaceTexture();
if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
mHandler.removeMessages(HIDE_SURFACE_VIEW);
- mPreviewSurfaceView.setVisibility(View.GONE);
+ mUI.hideSurfaceView();
}
}
}
@@ -1083,11 +983,10 @@ public class VideoModule implements CameraModule,
if (mMediaRecorderRecording) {
onStopVideoRecording();
return true;
- } else if (mPieRenderer != null && mPieRenderer.showsItems()) {
- mPieRenderer.hide();
+ } else if (mUI.hidePieRenderer()) {
return true;
} else {
- return removeTopLevelPopup();
+ return mUI.removeTopLevelPopup();
}
}
@@ -1101,13 +1000,13 @@ public class VideoModule implements CameraModule,
switch (keyCode) {
case KeyEvent.KEYCODE_CAMERA:
if (event.getRepeatCount() == 0) {
- mShutterButton.performClick();
+ mUI.clickShutter();
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.getRepeatCount() == 0) {
- mShutterButton.performClick();
+ mUI.clickShutter();
return true;
}
break;
@@ -1122,13 +1021,14 @@ public class VideoModule implements CameraModule,
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CAMERA:
- mShutterButton.setPressed(false);
+ mUI.pressShutter(false);
return true;
}
return false;
}
- private boolean isVideoCaptureIntent() {
+ @Override
+ public boolean isVideoCaptureIntent() {
String action = mActivity.getIntent().getAction();
return (MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
}
@@ -1159,12 +1059,12 @@ public class VideoModule implements CameraModule,
private void setupMediaRecorderPreviewDisplay() {
// Nothing to do here if using SurfaceTexture.
if (!ApiHelper.HAS_SURFACE_TEXTURE) {
- mMediaRecorder.setPreviewDisplay(mPreviewSurfaceView.getHolder().getSurface());
+ mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface());
} else if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
// We stop the preview here before unlocking the device because we
// need to change the SurfaceTexture to SurfaceView for preview.
stopPreview();
- mActivity.mCameraDevice.setPreviewDisplayAsync(mPreviewSurfaceView.getHolder());
+ mActivity.mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder());
// The orientation for SurfaceTexture is different from that for
// SurfaceView. For SurfaceTexture we don't need to consider the
// display rotation. Just consider the sensor's orientation and we
@@ -1176,7 +1076,7 @@ public class VideoModule implements CameraModule,
Util.getDisplayOrientation(mDisplayRotation, mCameraId));
mActivity.mCameraDevice.startPreviewAsync();
mPreviewing = true;
- mMediaRecorder.setPreviewDisplay(mPreviewSurfaceView.getHolder().getSurface());
+ mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface());
}
}
@@ -1191,8 +1091,8 @@ public class VideoModule implements CameraModule,
// surfaceCreated() is called immediately when the visibility is
// changed to visible. Thus, mSurfaceViewReady should become true
// right after calling setVisibility().
- mPreviewSurfaceView.setVisibility(View.VISIBLE);
- if (!mSurfaceViewReady) return;
+ mUI.showSurfaceView();
+ if (!mUI.isSurfaceViewReady()) return;
}
Intent intent = mActivity.getIntent();
@@ -1622,7 +1522,7 @@ public class VideoModule implements CameraModule,
// Make sure the video recording has started before announcing
// this in accessibility.
- AccessibilityUtils.makeAnnouncement(mShutterButton,
+ AccessibilityUtils.makeAnnouncement(mActivity.getShutterButton(),
mActivity.getString(R.string.video_recording_started));
// The parameters may have been changed by MediaRecorder upon starting
@@ -1633,45 +1533,17 @@ public class VideoModule implements CameraModule,
mParameters = mActivity.mCameraDevice.getParameters();
}
- enableCameraControls(false);
+ mUI.enableCameraControls(false);
mMediaRecorderRecording = true;
mActivity.getOrientationManager().lockOrientation();
mRecordingStartTime = SystemClock.uptimeMillis();
- showRecordingUI(true);
+ mUI.showRecordingUI(true, mParameters.isZoomSupported());
updateRecordingTime();
keepScreenOn();
}
- private void showRecordingUI(boolean recording) {
- mMenu.setVisibility(recording ? View.GONE : View.VISIBLE);
- mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
- if (recording) {
- mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
- mActivity.hideSwitcher();
- mRecordingTimeView.setText("");
- mRecordingTimeView.setVisibility(View.VISIBLE);
- // The camera is not allowed to be accessed in older api levels during
- // recording. It is therefore necessary to hide the zoom UI on older
- // platforms.
- // See the documentation of android.media.MediaRecorder.start() for
- // further explanation.
- if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING
- && mParameters.isZoomSupported()) {
- // TODO: disable zoom UI here.
- }
- } else {
- mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
- mActivity.showSwitcher();
- mRecordingTimeView.setVisibility(View.GONE);
- if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING
- && mParameters.isZoomSupported()) {
- // TODO: enable zoom UI here.
- }
- }
- }
-
private void showCaptureResult() {
Bitmap bitmap = null;
if (mVideoFileDescriptor != null) {
@@ -1687,35 +1559,19 @@ public class VideoModule implements CameraModule,
CameraInfo[] info = CameraHolder.instance().getCameraInfo();
boolean mirror = (info[mCameraId].facing == CameraInfo.CAMERA_FACING_FRONT);
bitmap = Util.rotateAndMirror(bitmap, 0, mirror);
- mReviewImage.setImageBitmap(bitmap);
- mReviewImage.setVisibility(View.VISIBLE);
+ mUI.showReviewImage(bitmap);
}
- Util.fadeOut(mShutterButton);
-
- Util.fadeIn(mReviewDoneButton);
- Util.fadeIn(mReviewPlayButton);
- mMenu.setVisibility(View.GONE);
- mOnScreenIndicators.setVisibility(View.GONE);
- enableCameraControls(false);
-
- showTimeLapseUI(false);
+ mUI.showReviewControls();
+ mUI.enableCameraControls(false);
+ mUI.showTimeLapseUI(false);
}
private void hideAlert() {
- mReviewImage.setVisibility(View.GONE);
- mShutterButton.setEnabled(true);
- mMenu.setVisibility(View.VISIBLE);
- mOnScreenIndicators.setVisibility(View.VISIBLE);
- enableCameraControls(true);
-
- Util.fadeOut(mReviewDoneButton);
- Util.fadeOut(mReviewPlayButton);
-
- Util.fadeIn(mShutterButton);
-
+ mUI.enableCameraControls(true);
+ mUI.hideReviewUI();
if (mCaptureTimeLapse) {
- showTimeLapseUI(true);
+ mUI.showTimeLapseUI(true);
}
}
@@ -1744,7 +1600,7 @@ public class VideoModule implements CameraModule,
mCurrentVideoFilename = mVideoFilename;
Log.v(TAG, "stopVideoRecording: Setting current video filename: "
+ mCurrentVideoFilename);
- AccessibilityUtils.makeAnnouncement(mShutterButton,
+ AccessibilityUtils.makeAnnouncement(mActivity.getShutterButton(),
mActivity.getString(R.string.video_recording_stopped));
} catch (RuntimeException e) {
Log.e(TAG, "stop fail", e);
@@ -1770,13 +1626,13 @@ public class VideoModule implements CameraModule,
closeCamera(closeEffects);
}
- showRecordingUI(false);
+ mUI.showRecordingUI(false, mParameters.isZoomSupported());
if (!mIsVideoCaptureIntent) {
- enableCameraControls(true);
+ mUI.enableCameraControls(true);
}
// The orientation was fixed during video recording. Now make it
// reflect the device orientation as video recording is stopped.
- setOrientationIndicator(0, true);
+ mUI.setOrientationIndicator(0, true);
keepScreenOnAwhile();
if (shouldAddToMediaStoreNow) {
if (addVideoToMediaStore()) fail = true;
@@ -1901,7 +1757,7 @@ public class VideoModule implements CameraModule,
targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
}
- mRecordingTimeView.setText(text);
+ mUI.setRecordingTime(text);
if (mRecordingTimeCountsDown != countdownRemainingTime) {
// Avoid setting the color on every update, do it only
@@ -1912,7 +1768,7 @@ public class VideoModule implements CameraModule,
? R.color.recording_time_remaining_text
: R.color.recording_time_elapsed_text);
- mRecordingTimeView.setTextColor(color);
+ mUI.setRecordingTimeTextColor(color);
}
long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
@@ -2058,7 +1914,6 @@ public class VideoModule implements CameraModule,
if (effectMsg == EffectsRecorder.EFFECT_MSG_EFFECTS_STOPPED) {
// Effects have shut down. Hide learning message if any,
// and restart regular preview.
- mBgLearningMessageFrame.setVisibility(View.GONE);
checkQualityAndStartPreview();
} else if (effectMsg == EffectsRecorder.EFFECT_MSG_RECORDING_DONE) {
// This follows the codepath from onStopVideoRecording.
@@ -2080,17 +1935,7 @@ public class VideoModule implements CameraModule,
}
} else if (effectMsg == EffectsRecorder.EFFECT_MSG_PREVIEW_RUNNING) {
// Enable the shutter button once the preview is complete.
- mShutterButton.setEnabled(true);
- } else if (effectId == EffectsRecorder.EFFECT_BACKDROPPER) {
- switch (effectMsg) {
- case EffectsRecorder.EFFECT_MSG_STARTED_LEARNING:
- mBgLearningMessageFrame.setVisibility(View.VISIBLE);
- break;
- case EffectsRecorder.EFFECT_MSG_DONE_LEARNING:
- case EffectsRecorder.EFFECT_MSG_SWITCHING_EFFECT:
- mBgLearningMessageFrame.setVisibility(View.GONE);
- break;
- }
+ mUI.enableShutter(true);
}
// In onPause, this was not called if the effects were active. We had to
// wait till the effects completed to do this.
@@ -2101,8 +1946,6 @@ public class VideoModule implements CameraModule,
}
public void onCancelBgTraining(View v) {
- // Remove training message
- mBgLearningMessageFrame.setVisibility(View.GONE);
// Write default effect out to shared prefs
writeDefaultEffectToPrefs();
// Tell VideoCamer to re-init based on new shared pref values.
@@ -2128,87 +1971,6 @@ public class VideoModule implements CameraModule,
throw new RuntimeException("Error during recording!", exception);
}
- private void initializeControlByIntent() {
- mBlocker = mActivity.findViewById(R.id.blocker);
- mMenu = mActivity.findViewById(R.id.menu);
- mMenu.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mPieRenderer != null) {
- mPieRenderer.showInCenter();
- }
- }
- });
- mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators);
- mFlashIndicator = (ImageView) mActivity.findViewById(R.id.menu_flash_indicator);
- if (mIsVideoCaptureIntent) {
- mActivity.hideSwitcher();
- ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls);
- mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
- // Cannot use RotateImageView for "done" and "cancel" button because
- // the tablet layout uses RotateLayout, which cannot be cast to
- // RotateImageView.
- mReviewDoneButton = mActivity.findViewById(R.id.btn_done);
- mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel);
- mReviewPlayButton = mActivity.findViewById(R.id.btn_play);
-
- mReviewCancelButton.setVisibility(View.VISIBLE);
-
- mReviewDoneButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onReviewDoneClicked(v);
- }
- });
- mReviewCancelButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onReviewCancelClicked(v);
- }
- });
-
- mReviewPlayButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onReviewPlayClicked(v);
- }
- });
- }
- }
-
- private void initializeMiscControls() {
- mPreviewFrameLayout = (PreviewFrameLayout) mRootView.findViewById(R.id.frame);
- mPreviewFrameLayout.setOnLayoutChangeListener(mActivity);
- mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
-
- mShutterButton = mActivity.getShutterButton();
- mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
- mShutterButton.setOnShutterButtonListener(this);
- mShutterButton.setVisibility(View.VISIBLE);
- mShutterButton.requestFocus();
- mShutterButton.enableTouch(true);
-
- // Disable the shutter button if effects are ON since it might take
- // a little more time for the effects preview to be ready. We do not
- // want to allow recording before that happens. The shutter button
- // will be enabled when we get the message from effectsrecorder that
- // the preview is running. This becomes critical when the camera is
- // swapped.
- if (effectsActive()) {
- mShutterButton.setEnabled(false);
- }
-
- mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
- mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
- mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
- // The R.id.labels can only be found in phone layout.
- // That is, mLabelsLinearLayout should be null in tablet layout.
- mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
-
- mBgLearningMessageRotater = (RotateLayout) mRootView.findViewById(R.id.bg_replace_message);
- mBgLearningMessageFrame = mRootView.findViewById(R.id.bg_replace_message_frame);
- }
-
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.v(TAG, "onConfigurationChanged");
@@ -2245,7 +2007,7 @@ public class VideoModule implements CameraModule,
if (updateEffectSelection()) return;
readVideoPreferences();
- showTimeLapseUI(mCaptureTimeLapse);
+ mUI.showTimeLapseUI(mCaptureTimeLapse);
// We need to restart the preview if preview size is changed.
Size size = mParameters.getPreviewSize();
if (size.width != mDesiredPreviewWidth
@@ -2261,31 +2023,13 @@ public class VideoModule implements CameraModule,
} else {
setCameraParameters();
}
- updateOnScreenIndicators();
+ mUI.updateOnScreenIndicators(mParameters);
}
}
- private void updateOnScreenIndicators() {
- if (mParameters == null) return;
- updateFlashOnScreenIndicator(mParameters.getFlashMode());
- }
-
- private void updateFlashOnScreenIndicator(String value) {
- if (mFlashIndicator == null) {
- return;
- }
- if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) {
- mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
- } else {
- if (Parameters.FLASH_MODE_AUTO.equals(value)) {
- mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_auto);
- } else if (Parameters.FLASH_MODE_ON.equals(value) ||
- Parameters.FLASH_MODE_TORCH.equals(value)) {
- mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_on);
- } else {
- mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
- }
- }
+ protected void setCameraId(int cameraId) {
+ ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID);
+ pref.setValue("" + cameraId);
}
private void switchCamera() {
@@ -2294,10 +2038,10 @@ public class VideoModule implements CameraModule,
Log.d(TAG, "Start to switch camera.");
mCameraId = mPendingSwitchCameraId;
mPendingSwitchCameraId = -1;
- mVideoControl.setCameraId(mCameraId);
+ setCameraId(mCameraId);
closeCamera();
-
+ mUI.collapseCameraControls();
// Restart the camera and initialize the UI. From onCreate.
mPreferences.setLocalId(mActivity, mCameraId);
CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
@@ -2309,15 +2053,15 @@ public class VideoModule implements CameraModule,
initializeVideoControl();
// From onResume
- initializeZoom();
- setOrientationIndicator(0, false);
+ mUI.initializeZoom(mParameters);
+ mUI.setOrientationIndicator(0, false);
if (ApiHelper.HAS_SURFACE_TEXTURE) {
// Start switch camera animation. Post a message because
// onFrameAvailable from the old camera may already exist.
mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
}
- updateOnScreenIndicators();
+ mUI.updateOnScreenIndicators(mParameters);
}
// Preview texture has been copied. Now camera can be released and the
@@ -2375,7 +2119,7 @@ public class VideoModule implements CameraModule,
// preview. If not, resets the surface texture and resizes the view.
private void checkQualityAndStartPreview() {
readVideoPreferences();
- showTimeLapseUI(mCaptureTimeLapse);
+ mUI.showTimeLapseUI(mCaptureTimeLapse);
Size size = mParameters.getPreviewSize();
if (size.width != mDesiredPreviewWidth
|| size.height != mDesiredPreviewHeight) {
@@ -2385,60 +2129,16 @@ public class VideoModule implements CameraModule,
startPreview();
}
- private void showTimeLapseUI(boolean enable) {
- if (mTimeLapseLabel != null) {
- mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
- }
- }
-
@Override
public boolean dispatchTouchEvent(MotionEvent m) {
if (mSwitchingCamera) return true;
- if (mPopup == null && mGestures != null && mRenderOverlay != null) {
- return mGestures.dispatchTouch(m);
- } else if (mPopup != null) {
- return mActivity.superDispatchTouchEvent(m);
- }
- return false;
- }
-
- private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
- @Override
- public void onZoomValueChanged(int value) {
- // Not useful to change zoom value when the activity is paused.
- if (mPaused) return;
- mZoomValue = value;
- // Set zoom parameters asynchronously
- mParameters.setZoom(mZoomValue);
- mActivity.mCameraDevice.setParametersAsync(mParameters);
- Parameters p = mActivity.mCameraDevice.getParameters();
- mZoomRenderer.setZoomValue(mZoomRatios.get(p.getZoom()));
- }
-
- @Override
- public void onZoomStart() {
- }
- @Override
- public void onZoomEnd() {
- }
- }
-
- private void initializeZoom() {
- if (mParameters == null || !mParameters.isZoomSupported()) return;
- mZoomMax = mParameters.getMaxZoom();
- mZoomRatios = mParameters.getZoomRatios();
- // Currently we use immediate zoom for fast zooming to get better UX and
- // there is no plan to take advantage of the smooth zoom.
- mZoomRenderer.setZoomMax(mZoomMax);
- mZoomRenderer.setZoom(mParameters.getZoom());
- mZoomRenderer.setZoomValue(mZoomRatios.get(mParameters.getZoom()));
- mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
+ return mUI.dispatchTouchEvent(m);
}
private void initializeVideoSnapshot() {
if (mParameters == null) return;
if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
- mActivity.setSingleTapUpListener(mPreviewFrameLayout);
+ mActivity.setSingleTapUpListener(mUI.getPreview());
// Show the tap to focus toast if this is the first start.
if (mPreferences.getBoolean(
CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, true)) {
@@ -2456,47 +2156,12 @@ public class VideoModule implements CameraModule,
if (ApiHelper.HAS_SURFACE_TEXTURE && enabled) {
((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation);
} else {
- mPreviewFrameLayout.showBorder(enabled);
+ mUI.showPreviewBorder(enabled);
}
- mShutterButton.setEnabled(!enabled);
+ mUI.enableShutter(!enabled);
}
}
- // Preview area is touched. Take a picture.
- @Override
- public void onSingleTapUp(View view, int x, int y) {
- if (mMediaRecorderRecording && effectsActive()) {
- new RotateTextToast(mActivity, R.string.disable_video_snapshot_hint,
- mOrientation).show();
- return;
- }
-
- MediaSaveService s = mActivity.getMediaSaveService();
- if (mPaused || mSnapshotInProgress || effectsActive() || s == null || s.isQueueFull()) {
- return;
- }
-
- if (!mMediaRecorderRecording) {
- // check for dismissing popup
- if (mPopup != null) {
- dismissPopup(true);
- }
- return;
- }
-
- // Set rotation and gps data.
- int rotation = Util.getJpegRotation(mCameraId, mOrientation);
- mParameters.setRotation(rotation);
- Location loc = mLocationManager.getCurrentLocation();
- Util.setGpsParameters(mParameters, loc);
- mActivity.mCameraDevice.setParameters(mParameters);
-
- Log.v(TAG, "Video snapshot start");
- mActivity.mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc));
- showVideoSnapshotUI(true);
- mSnapshotInProgress = true;
- }
-
@Override
public void updateCameraAppView() {
if (!mPreviewing || mParameters.getFlashMode() == null) return;
@@ -2515,43 +2180,15 @@ public class VideoModule implements CameraModule,
}
}
- private void setShowMenu(boolean show) {
- if (mOnScreenIndicators != null) {
- mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
- }
- if (mMenu != null) {
- mMenu.setVisibility(show ? View.VISIBLE : View.GONE);
- }
- }
-
@Override
public void onFullScreenChanged(boolean full) {
- if (mGestures != null) {
- mGestures.setEnabled(full);
- }
- if (mPopup != null) {
- dismissPopup(false, full);
- }
- if (mRenderOverlay != null) {
- // this can not happen in capture mode
- mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE);
- }
- setShowMenu(full);
- if (mBlocker != null) {
- // this can not happen in capture mode
- mBlocker.setVisibility(full ? View.VISIBLE : View.GONE);
- }
+ mUI.onFullScreenChanged(full);
if (ApiHelper.HAS_SURFACE_TEXTURE) {
if (mActivity.mCameraScreenNail != null) {
((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full);
}
return;
}
- if (full) {
- mPreviewSurfaceView.expand();
- } else {
- mPreviewSurfaceView.shrink();
- }
}
private final class JpegPictureCallback implements PictureCallback {
@@ -2711,39 +2348,6 @@ public class VideoModule implements CameraModule,
}
}
- private class SurfaceViewCallback implements SurfaceHolder.Callback {
- public SurfaceViewCallback() {}
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v(TAG, "Surface created");
- mSurfaceViewReady = true;
- if (mPaused) return;
- if (!ApiHelper.HAS_SURFACE_TEXTURE) {
- mActivity.mCameraDevice.setPreviewDisplayAsync(mPreviewSurfaceView.getHolder());
- if (!mPreviewing) {
- startPreview();
- }
- }
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v(TAG, "Surface destroyed");
- mSurfaceViewReady = false;
- if (mPaused) return;
- if (!ApiHelper.HAS_SURFACE_TEXTURE) {
- stopVideoRecording();
- stopPreview();
- }
- }
- }
-
@Override
public boolean updateStorageHintOnResume() {
return true;
@@ -2778,50 +2382,8 @@ public class VideoModule implements CameraModule,
}
@Override
- public void onPieOpened(int centerX, int centerY) {
- mActivity.cancelActivityTouchHandling();
- mActivity.setSwipingEnabled(false);
- }
-
- @Override
- public void onPieClosed() {
- mActivity.setSwipingEnabled(true);
- }
-
- public void showPopup(AbstractSettingPopup popup) {
- mActivity.hideUI();
- mBlocker.setVisibility(View.INVISIBLE);
- setShowMenu(false);
- mPopup = popup;
- mPopup.setVisibility(View.VISIBLE);
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER;
- ((FrameLayout) mRootView).addView(mPopup, lp);
- }
-
- public void dismissPopup(boolean topLevelOnly) {
- dismissPopup(topLevelOnly, true);
- }
-
- public void dismissPopup(boolean topLevelPopupOnly, boolean fullScreen) {
- if (fullScreen) {
- mActivity.showUI();
- mBlocker.setVisibility(View.VISIBLE);
- }
- setShowMenu(fullScreen);
- if (mPopup != null) {
- ((FrameLayout) mRootView).removeView(mPopup);
- mPopup = null;
- }
- mVideoControl.popupDismissed(topLevelPopupOnly);
- }
-
- @Override
public void onShowSwitcherPopup() {
- if (mPieRenderer.showsItems()) {
- mPieRenderer.hide();
- }
+ mUI.onShowSwitcherPopup();
}
@Override
diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java
new file mode 100644
index 000000000..63c190984
--- /dev/null
+++ b/src/com/android/camera/VideoUI.java
@@ -0,0 +1,510 @@
+/*
+ * 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;
+
+import android.graphics.Bitmap;
+import android.hardware.Camera.Parameters;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.camera.CameraPreference.OnPreferenceChangedListener;
+import com.android.camera.ui.AbstractSettingPopup;
+import com.android.camera.ui.PieRenderer;
+import com.android.camera.ui.PreviewSurfaceView;
+import com.android.camera.ui.RenderOverlay;
+import com.android.camera.ui.RotateLayout;
+import com.android.camera.ui.ZoomRenderer;
+import com.android.gallery3d.R;
+import com.android.gallery3d.common.ApiHelper;
+
+import java.util.List;
+
+public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener,
+ PreviewGestures.SingleTapListener {
+ private final static String TAG = "CAM_VideoUI";
+ // module fields
+ private CameraActivity mActivity;
+ private View mRootView;
+ private PreviewFrameLayout mPreviewFrameLayout;
+ private boolean mSurfaceViewReady;
+ private SurfaceHolder.Callback mSurfaceViewCallback;
+ private PreviewSurfaceView mPreviewSurfaceView;
+ // An review image having same size as preview. It is displayed when
+ // recording is stopped in capture intent.
+ private ImageView mReviewImage;
+ private View mReviewCancelButton;
+ private View mReviewDoneButton;
+ private View mReviewPlayButton;
+ private ShutterButton mShutterButton;
+ private TextView mRecordingTimeView;
+ private LinearLayout mLabelsLinearLayout;
+ private View mTimeLapseLabel;
+ private RenderOverlay mRenderOverlay;
+ private PieRenderer mPieRenderer;
+ private VideoMenu mVideoMenu;
+ private AbstractSettingPopup mPopup;
+ private ZoomRenderer mZoomRenderer;
+ private PreviewGestures mGestures;
+ private View mMenu;
+ private View mBlocker;
+ private View mOnScreenIndicators;
+ private ImageView mFlashIndicator;
+ private RotateLayout mRecordingTimeRect;
+ private VideoController mController;
+ private int mZoomMax;
+ private List<Integer> mZoomRatios;
+
+ public VideoUI(CameraActivity activity, VideoController controller, View parent) {
+ mActivity = activity;
+ mController = controller;
+ mRootView = parent;
+ mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
+ mPreviewSurfaceView = (PreviewSurfaceView) mRootView
+ .findViewById(R.id.preview_surface_view);
+ initializeMiscControls();
+ initializeControlByIntent();
+ initializeOverlay();
+ }
+
+ private void initializeControlByIntent() {
+ mBlocker = mActivity.findViewById(R.id.blocker);
+ mMenu = mActivity.findViewById(R.id.menu);
+ mMenu.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mPieRenderer != null) {
+ mPieRenderer.showInCenter();
+ }
+ }
+ });
+ mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators);
+ mFlashIndicator = (ImageView) mActivity.findViewById(R.id.menu_flash_indicator);
+ if (mController.isVideoCaptureIntent()) {
+ mActivity.hideSwitcher();
+ ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls);
+ mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
+ // Cannot use RotateImageView for "done" and "cancel" button because
+ // the tablet layout uses RotateLayout, which cannot be cast to
+ // RotateImageView.
+ mReviewDoneButton = mActivity.findViewById(R.id.btn_done);
+ mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel);
+ mReviewPlayButton = mActivity.findViewById(R.id.btn_play);
+ mReviewCancelButton.setVisibility(View.VISIBLE);
+ mReviewDoneButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mController.onReviewDoneClicked(v);
+ }
+ });
+ mReviewCancelButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mController.onReviewCancelClicked(v);
+ }
+ });
+ mReviewPlayButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mController.onReviewPlayClicked(v);
+ }
+ });
+ }
+ }
+
+ public boolean collapseCameraControls() {
+ boolean ret = false;
+ if (mPopup != null) {
+ dismissPopup(false);
+ ret = true;
+ }
+ return ret;
+ }
+
+ public boolean removeTopLevelPopup() {
+ if (mPopup != null) {
+ dismissPopup(true);
+ return true;
+ }
+ return false;
+ }
+
+ public void enableCameraControls(boolean enable) {
+ if (mGestures != null) {
+ mGestures.setZoomOnly(!enable);
+ }
+ if (mPieRenderer != null && mPieRenderer.showsItems()) {
+ mPieRenderer.hide();
+ }
+ }
+
+ public void overrideSettings(final String... keyvalues) {
+ mVideoMenu.overrideSettings(keyvalues);
+ }
+
+ public View getPreview() {
+ return mPreviewFrameLayout;
+ }
+
+ public void setOrientationIndicator(int orientation, boolean animation) {
+ if (mGestures != null) {
+ mGestures.setOrientation(orientation);
+ }
+ // We change the orientation of the linearlayout only for phone UI
+ // because when in portrait the width is not enough.
+ if (mLabelsLinearLayout != null) {
+ if (((orientation / 90) & 1) == 0) {
+ mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
+ } else {
+ mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ }
+ }
+ mRecordingTimeRect.setOrientation(0, animation);
+ }
+
+ public SurfaceHolder getSurfaceHolder() {
+ return mPreviewSurfaceView.getHolder();
+ }
+
+ public void hideSurfaceView() {
+ mPreviewSurfaceView.setVisibility(View.GONE);
+ }
+
+ public void showSurfaceView() {
+ mPreviewSurfaceView.setVisibility(View.VISIBLE);
+ }
+
+ private void initializeOverlay() {
+ mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
+ if (mPieRenderer == null) {
+ mPieRenderer = new PieRenderer(mActivity);
+ mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
+ mPieRenderer.setPieListener(this);
+ }
+ mRenderOverlay.addRenderer(mPieRenderer);
+ if (mZoomRenderer == null) {
+ mZoomRenderer = new ZoomRenderer(mActivity);
+ }
+ mRenderOverlay.addRenderer(mZoomRenderer);
+ if (mGestures == null) {
+ mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
+ }
+ mGestures.setRenderOverlay(mRenderOverlay);
+ mGestures.clearTouchReceivers();
+ mGestures.addTouchReceiver(mMenu);
+ mGestures.addTouchReceiver(mBlocker);
+ if (mController.isVideoCaptureIntent()) {
+ if (mReviewCancelButton != null) {
+ mGestures.addTouchReceiver(mReviewCancelButton);
+ }
+ if (mReviewDoneButton != null) {
+ mGestures.addTouchReceiver(mReviewDoneButton);
+ }
+ if (mReviewPlayButton != null) {
+ mGestures.addTouchReceiver(mReviewPlayButton);
+ }
+ }
+ }
+
+ public void setPrefChangedListener(OnPreferenceChangedListener listener) {
+ mVideoMenu.setListener(listener);
+ }
+
+ private void initializeMiscControls() {
+ mPreviewFrameLayout = (PreviewFrameLayout) mRootView.findViewById(R.id.frame);
+ mPreviewFrameLayout.setOnLayoutChangeListener(mActivity);
+ mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
+ mShutterButton = mActivity.getShutterButton();
+ mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
+ mShutterButton.setOnShutterButtonListener(mController);
+ mShutterButton.setVisibility(View.VISIBLE);
+ mShutterButton.requestFocus();
+ mShutterButton.enableTouch(true);
+ mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
+ mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
+ mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
+ // The R.id.labels can only be found in phone layout.
+ // That is, mLabelsLinearLayout should be null in tablet layout.
+ mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
+ }
+
+ public void updateOnScreenIndicators(Parameters param) {
+ if (param == null) return;
+ String value = param.getFlashMode();
+ if (mFlashIndicator == null) return;
+ if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) {
+ mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
+ } else {
+ if (Parameters.FLASH_MODE_AUTO.equals(value)) {
+ mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_auto);
+ } else if (Parameters.FLASH_MODE_ON.equals(value)
+ || Parameters.FLASH_MODE_TORCH.equals(value)) {
+ mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_on);
+ } else {
+ mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
+ }
+ }
+ }
+
+ public void setAspectRatio(double ratio) {
+ mPreviewFrameLayout.setAspectRatio(ratio);
+ }
+
+ public void showTimeLapseUI(boolean enable) {
+ if (mTimeLapseLabel != null) {
+ mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void showPopup(AbstractSettingPopup popup) {
+ mActivity.hideUI();
+ mBlocker.setVisibility(View.INVISIBLE);
+ setShowMenu(false);
+ mPopup = popup;
+ mPopup.setVisibility(View.VISIBLE);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER;
+ ((FrameLayout) mRootView).addView(mPopup, lp);
+ }
+
+ public void dismissPopup(boolean topLevelOnly) {
+ dismissPopup(topLevelOnly, true);
+ }
+
+ public void dismissPopup(boolean topLevelPopupOnly, boolean fullScreen) {
+ if (fullScreen) {
+ mActivity.showUI();
+ mBlocker.setVisibility(View.VISIBLE);
+ }
+ setShowMenu(fullScreen);
+ if (mPopup != null) {
+ ((FrameLayout) mRootView).removeView(mPopup);
+ mPopup = null;
+ }
+ mVideoMenu.popupDismissed(topLevelPopupOnly);
+ }
+
+ public void onShowSwitcherPopup() {
+ hidePieRenderer();
+ }
+
+ public boolean hidePieRenderer() {
+ if (mPieRenderer != null && mPieRenderer.showsItems()) {
+ mPieRenderer.hide();
+ return true;
+ }
+ return false;
+ }
+
+ public void enableShutter(boolean enable) {
+ if (mShutterButton != null) {
+ mShutterButton.setEnabled(enable);
+ }
+ }
+
+ // PieListener
+ @Override
+ public void onPieOpened(int centerX, int centerY) {
+ mActivity.cancelActivityTouchHandling();
+ mActivity.setSwipingEnabled(false);
+ }
+
+ @Override
+ public void onPieClosed() {
+ mActivity.setSwipingEnabled(true);
+ }
+
+ public void showPreviewBorder(boolean enable) {
+ mPreviewFrameLayout.showBorder(enable);
+ }
+
+ // SingleTapListener
+ // Preview area is touched. Take a picture.
+ @Override
+ public void onSingleTapUp(View view, int x, int y) {
+ mController.onSingleTapUp(view, x, y);
+ }
+
+ // SurfaceView callback
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(TAG, "Surface created");
+ mSurfaceViewReady = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(TAG, "Surface destroyed");
+ mSurfaceViewReady = false;
+ mController.stopPreview();
+ }
+
+ public boolean isSurfaceViewReady() {
+ return mSurfaceViewReady;
+ }
+
+ public void showRecordingUI(boolean recording, boolean zoomSupported) {
+ mMenu.setVisibility(recording ? View.GONE : View.VISIBLE);
+ mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
+ if (recording) {
+ mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
+ mActivity.hideSwitcher();
+ mRecordingTimeView.setText("");
+ mRecordingTimeView.setVisibility(View.VISIBLE);
+ // The camera is not allowed to be accessed in older api levels during
+ // recording. It is therefore necessary to hide the zoom UI on older
+ // platforms.
+ // See the documentation of android.media.MediaRecorder.start() for
+ // further explanation.
+ if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
+ // TODO: disable zoom UI here.
+ }
+ } else {
+ mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
+ mActivity.showSwitcher();
+ mRecordingTimeView.setVisibility(View.GONE);
+ if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
+ // TODO: enable zoom UI here.
+ }
+ }
+ }
+
+ public void showReviewImage(Bitmap bitmap) {
+ mReviewImage.setImageBitmap(bitmap);
+ mReviewImage.setVisibility(View.VISIBLE);
+ }
+
+ public void showReviewControls() {
+ Util.fadeOut(mShutterButton);
+ Util.fadeIn(mReviewDoneButton);
+ Util.fadeIn(mReviewPlayButton);
+ mReviewImage.setVisibility(View.VISIBLE);
+ mMenu.setVisibility(View.GONE);
+ mOnScreenIndicators.setVisibility(View.GONE);
+ }
+
+ public void hideReviewUI() {
+ mReviewImage.setVisibility(View.GONE);
+ mShutterButton.setEnabled(true);
+ mMenu.setVisibility(View.VISIBLE);
+ mOnScreenIndicators.setVisibility(View.VISIBLE);
+ Util.fadeOut(mReviewDoneButton);
+ Util.fadeOut(mReviewPlayButton);
+ Util.fadeIn(mShutterButton);
+ }
+
+ private void setShowMenu(boolean show) {
+ if (mOnScreenIndicators != null) {
+ mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ if (mMenu != null) {
+ mMenu.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void onFullScreenChanged(boolean full) {
+ if (mGestures != null) {
+ mGestures.setEnabled(full);
+ }
+ if (mPopup != null) {
+ dismissPopup(false, full);
+ }
+ if (mRenderOverlay != null) {
+ // this can not happen in capture mode
+ mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE);
+ }
+ setShowMenu(full);
+ if (mBlocker != null) {
+ // this can not happen in capture mode
+ mBlocker.setVisibility(full ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public void initializePopup(PreferenceGroup pref) {
+ mVideoMenu.initialize(pref);
+ }
+
+ public void initializeZoom(Parameters param) {
+ if (param == null || !param.isZoomSupported()) return;
+ mZoomMax = param.getMaxZoom();
+ mZoomRatios = param.getZoomRatios();
+ // Currently we use immediate zoom for fast zooming to get better UX and
+ // there is no plan to take advantage of the smooth zoom.
+ mZoomRenderer.setZoomMax(mZoomMax);
+ mZoomRenderer.setZoom(param.getZoom());
+ mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
+ mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
+ }
+
+ public void clickShutter() {
+ mShutterButton.performClick();
+ }
+
+ public void pressShutter(boolean pressed) {
+ mShutterButton.setPressed(pressed);
+ }
+
+ public boolean dispatchTouchEvent(MotionEvent m) {
+ if (mPopup == null && mGestures != null && mRenderOverlay != null) {
+ return mGestures.dispatchTouch(m);
+ } else if (mPopup != null) {
+ return mActivity.superDispatchTouchEvent(m);
+ }
+ return false;
+ }
+
+ public void setRecordingTime(String text) {
+ mRecordingTimeView.setText(text);
+ }
+
+ public void setRecordingTimeTextColor(int color) {
+ mRecordingTimeView.setTextColor(color);
+ }
+
+ private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
+ @Override
+ public void onZoomValueChanged(int index) {
+ int newZoom = mController.onZoomChanged(index);
+ if (mZoomRenderer != null) {
+ mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
+ }
+ }
+
+ @Override
+ public void onZoomStart() {
+ }
+
+ @Override
+ public void onZoomEnd() {
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/data/Exif.java b/src/com/android/gallery3d/data/Exif.java
index 30aba7e97..950e7de18 100644
--- a/src/com/android/gallery3d/data/Exif.java
+++ b/src/com/android/gallery3d/data/Exif.java
@@ -18,55 +18,31 @@ package com.android.gallery3d.data;
import android.util.Log;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifParser;
-import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.exif.ExifInterface;
import java.io.IOException;
import java.io.InputStream;
public class Exif {
- private static final String TAG = "GalleryExif";
+ private static final String TAG = "CameraExif";
+ // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
public static int getOrientation(InputStream is) {
if (is == null) {
return 0;
}
-
+ ExifInterface exif = new ExifInterface();
try {
- ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
- int event = parser.next();
- while (event != ExifParser.EVENT_END) {
- if (event == ExifParser.EVENT_NEW_TAG) {
- ExifTag tag = parser.getTag();
- if (tag.getTagId() == ExifTag.TAG_ORIENTATION &&
- tag.hasValue()) {
- int orient = (int) tag.getValueAt(0);
- switch (orient) {
- case ExifTag.Orientation.TOP_LEFT:
- return 0;
- case ExifTag.Orientation.BOTTOM_LEFT:
- return 180;
- case ExifTag.Orientation.RIGHT_TOP:
- return 90;
- case ExifTag.Orientation.RIGHT_BOTTOM:
- return 270;
- default:
- Log.i(TAG, "Unsupported orientation");
- return 0;
- }
- }
- }
- event = parser.next();
+ exif.readExif(is);
+ Integer val = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+ if (val == null) {
+ return 0;
+ } else {
+ return ExifInterface.getRotationForOrientationValue(val.shortValue());
}
- Log.i(TAG, "Orientation not found");
- return 0;
} catch (IOException e) {
Log.w(TAG, "Failed to read EXIF orientation", e);
return 0;
- } catch (ExifInvalidFormatException e) {
- Log.w(TAG, "Failed to read EXIF orientation", e);
- return 0;
}
}
}
diff --git a/src/com/android/gallery3d/data/LocalImage.java b/src/com/android/gallery3d/data/LocalImage.java
index d5fad5483..1ed67ecf4 100644
--- a/src/com/android/gallery3d/data/LocalImage.java
+++ b/src/com/android/gallery3d/data/LocalImage.java
@@ -23,7 +23,6 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
-import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore.Images;
@@ -37,8 +36,7 @@ import com.android.gallery3d.app.StitchingProgressManager;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.BitmapUtils;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifModifier;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.exif.ExifTag;
import com.android.gallery3d.util.GalleryUtils;
import com.android.gallery3d.util.ThreadPool.Job;
@@ -46,6 +44,7 @@ import com.android.gallery3d.util.ThreadPool.JobContext;
import com.android.gallery3d.util.UpdateHelper;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel.MapMode;
@@ -196,15 +195,15 @@ public class LocalImage extends LocalMediaItem {
// try to decode from JPEG EXIF
if (type == MediaItem.TYPE_MICROTHUMBNAIL) {
- ExifInterface exif = null;
- byte [] thumbData = null;
+ ExifInterface exif = new ExifInterface();
+ byte[] thumbData = null;
try {
- exif = new ExifInterface(mLocalFilePath);
- if (exif != null) {
- thumbData = exif.getThumbnail();
- }
- } catch (Throwable t) {
- Log.w(TAG, "fail to get exif thumb", t);
+ exif.readExif(mLocalFilePath);
+ thumbData = exif.getThumbnail();
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "failed to find file to read thumbnail: " + mLocalFilePath);
+ } catch (IOException e) {
+ Log.w(TAG, "failed to get thumbnail from: " + mLocalFilePath);
}
if (thumbData != null) {
Bitmap bitmap = DecodeUtils.decodeIfBigEnough(
@@ -276,21 +275,6 @@ public class LocalImage extends LocalMediaItem {
new String[]{String.valueOf(id)});
}
- private static int getExifOrientation(int orientation) {
- switch (orientation) {
- case 0:
- return ExifInterface.ORIENTATION_NORMAL;
- case 90:
- return ExifInterface.ORIENTATION_ROTATE_90;
- case 180:
- return ExifInterface.ORIENTATION_ROTATE_180;
- case 270:
- return ExifInterface.ORIENTATION_ROTATE_270;
- default:
- throw new AssertionError("invalid: " + orientation);
- }
- }
-
@Override
public void rotate(int degrees) {
GalleryUtils.assertNotInRenderThread();
@@ -300,34 +284,22 @@ public class LocalImage extends LocalMediaItem {
if (rotation < 0) rotation += 360;
if (mimeType.equalsIgnoreCase("image/jpeg")) {
- RandomAccessFile file = null;
- try {
- // Because most of the images contain the orientation tag, we
- // use ExifModifier to modify the tag for better efficiency.
- // If the tag doesn't exist, ExifInterface will be used to replace the entire
- // header.
- file = new RandomAccessFile(filePath, "rw");
- ExifModifier modifier = new ExifModifier(
- file.getChannel().map(MapMode.READ_WRITE, 0, file.length()));
- ExifTag tag = ExifTag.buildTag(ExifTag.TAG_ORIENTATION);
- tag.setValue(getExifOrientation(rotation));
- modifier.modifyTag(tag);
- if (!modifier.commit()) {
- // Need to change the file size, use ExifInterface instead.
- ExifInterface exif = new ExifInterface(filePath);
- exif.setAttribute(ExifInterface.TAG_ORIENTATION,
- String.valueOf(getExifOrientation(rotation)));
- exif.saveAttributes();
- // We need to update the filesize as well
+ ExifInterface exifInterface = new ExifInterface();
+ ExifTag tag = exifInterface.buildTag(ExifInterface.TAG_ORIENTATION,
+ ExifInterface.getOrientationValueForRotation(rotation));
+ if(tag != null) {
+ exifInterface.setTag(tag);
+ try {
+ exifInterface.forceRewriteExif(filePath);
fileSize = new File(filePath).length();
values.put(Images.Media.SIZE, fileSize);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "cannot find file to set exif: " + filePath);
+ } catch (IOException e) {
+ Log.w(TAG, "cannot set exif data: " + filePath);
}
- } catch (IOException e) {
- Log.w(TAG, "cannot set exif data: " + filePath);
- } catch (ExifInvalidFormatException e) {
- Log.w(TAG, "cannot set exif data: " + filePath);
- } finally {
- Utils.closeSilently(file);
+ } else {
+ Log.w(TAG, "Could not build tag: " + ExifInterface.TAG_ORIENTATION);
}
}
diff --git a/src/com/android/gallery3d/data/MediaDetails.java b/src/com/android/gallery3d/data/MediaDetails.java
index 662bd141c..cac524b88 100644
--- a/src/com/android/gallery3d/data/MediaDetails.java
+++ b/src/com/android/gallery3d/data/MediaDetails.java
@@ -18,12 +18,12 @@ package com.android.gallery3d.data;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifData;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifReader;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.exif.Rational;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
@@ -115,11 +115,11 @@ public class MediaDetails implements Iterable<Entry<Integer, Object>> {
String value = null;
int type = tag.getDataType();
if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) {
- value = String.valueOf(tag.getRational(0).toDouble());
+ value = String.valueOf(tag.getValueAsRational(0).toDouble());
} else if (type == ExifTag.TYPE_ASCII) {
- value = tag.getString();
+ value = tag.getValueAsString();
} else {
- value = String.valueOf(tag.getValueAt(0));
+ value = String.valueOf(tag.forceGetValueAsLong(0));
}
if (key == MediaDetails.INDEX_FLASH) {
MediaDetails.FlashState state = new MediaDetails.FlashState(
@@ -132,37 +132,39 @@ public class MediaDetails implements Iterable<Entry<Integer, Object>> {
}
public static void extractExifInfo(MediaDetails details, String filePath) {
- InputStream is = null;
+
+ ExifInterface exif = new ExifInterface();
try {
- is = new FileInputStream(filePath);
- ExifData data = new ExifReader().read(is);
- setExifData(details, data.getTag(ExifTag.TAG_FLASH), MediaDetails.INDEX_FLASH);
- setExifData(details, data.getTag(ExifTag.TAG_IMAGE_WIDTH), MediaDetails.INDEX_WIDTH);
- setExifData(details, data.getTag(ExifTag.TAG_IMAGE_LENGTH), MediaDetails.INDEX_HEIGHT);
- setExifData(details, data.getTag(ExifTag.TAG_MAKE), MediaDetails.INDEX_MAKE);
- setExifData(details, data.getTag(ExifTag.TAG_MODEL),MediaDetails.INDEX_MODEL);
- setExifData(details, data.getTag(ExifTag.TAG_APERTURE_VALUE),
- MediaDetails.INDEX_APERTURE);
- setExifData(details, data.getTag(ExifTag.TAG_ISO_SPEED_RATINGS),
- MediaDetails.INDEX_ISO);
- setExifData(details, data.getTag(ExifTag.TAG_WHITE_BALANCE),
- MediaDetails.INDEX_WHITE_BALANCE);
- setExifData(details, data.getTag(ExifTag.TAG_EXPOSURE_TIME),
- MediaDetails.INDEX_EXPOSURE_TIME);
- ExifTag focalTag = data.getTag(ExifTag.TAG_FOCAL_LENGTH);
- if (focalTag != null) {
- details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH,
- focalTag.getRational(0).toDouble());
- details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
- }
- } catch (IOException ex) {
- // ignore it.
- Log.w(TAG, "", ex);
- } catch (ExifInvalidFormatException ex) {
- // ignore it.
- Log.w(TAG, "", ex);
- } finally {
- Utils.closeSilently(is);
+ exif.readExif(filePath);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Could not find file to read exif: " + filePath, e);
+ } catch (IOException e) {
+ Log.w(TAG, "Could not read exif from file: " + filePath, e);
+ }
+
+ setExifData(details, exif.getTag(ExifInterface.TAG_FLASH),
+ MediaDetails.INDEX_FLASH);
+ setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH),
+ MediaDetails.INDEX_WIDTH);
+ setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH),
+ MediaDetails.INDEX_HEIGHT);
+ setExifData(details, exif.getTag(ExifInterface.TAG_MAKE),
+ MediaDetails.INDEX_MAKE);
+ setExifData(details, exif.getTag(ExifInterface.TAG_MODEL),
+ MediaDetails.INDEX_MODEL);
+ setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE),
+ MediaDetails.INDEX_APERTURE);
+ setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS),
+ MediaDetails.INDEX_ISO);
+ setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE),
+ MediaDetails.INDEX_WHITE_BALANCE);
+ setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME),
+ MediaDetails.INDEX_EXPOSURE_TIME);
+ ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH);
+ if (focalTag != null) {
+ details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH,
+ focalTag.getValueAsRational(0).toDouble());
+ details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 37b2cd9da..081cf5d9a 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -138,6 +138,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
clearGalleryBitmapPool();
setupMasterImage();
+ ImageFilterRS.createRenderscriptContext(this);
setDefaultValues();
fillEditors();
@@ -343,7 +344,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private void setDefaultValues() {
ImageFilter.setActivityForMemoryToasts(this);
- ImageFilterRS.setRenderScriptContext(this);
Resources res = getResources();
// TODO: add a mechanism to set the resources in FiltersManagmer
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 6cf462269..2c1a847f8 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -27,7 +27,7 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Matrix;
import android.graphics.Rect;
-import android.media.ExifInterface;
+import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
@@ -36,9 +36,8 @@ import com.adobe.xmp.XMPException;
import com.adobe.xmp.XMPMeta;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifParser;
import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
@@ -48,6 +47,8 @@ import com.android.gallery3d.filtershow.tools.SaveCopyTask;
import com.android.gallery3d.util.InterruptableOutputStream;
import com.android.gallery3d.util.XmpUtilHelper;
+import java.io.ByteArrayInputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -79,14 +80,14 @@ public class ImageLoader {
public static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
public static final int DEFAULT_COMPRESS_QUALITY = 95;
- public static final int ORI_NORMAL = ExifInterface.ORIENTATION_NORMAL;
- public static final int ORI_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
- public static final int ORI_ROTATE_180 = ExifInterface.ORIENTATION_ROTATE_180;
- public static final int ORI_ROTATE_270 = ExifInterface.ORIENTATION_ROTATE_270;
- public static final int ORI_FLIP_HOR = ExifInterface.ORIENTATION_FLIP_HORIZONTAL;
- public static final int ORI_FLIP_VERT = ExifInterface.ORIENTATION_FLIP_VERTICAL;
- public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
- public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
+ public static final int ORI_NORMAL = ExifInterface.Orientation.TOP_LEFT;
+ public static final int ORI_ROTATE_90 = ExifInterface.Orientation.RIGHT_TOP;
+ public static final int ORI_ROTATE_180 = ExifInterface.Orientation.BOTTOM_LEFT;
+ public static final int ORI_ROTATE_270 = ExifInterface.Orientation.RIGHT_BOTTOM;
+ public static final int ORI_FLIP_HOR = ExifInterface.Orientation.TOP_RIGHT;
+ public static final int ORI_FLIP_VERT = ExifInterface.Orientation.BOTTOM_RIGHT;
+ public static final int ORI_TRANSPOSE = ExifInterface.Orientation.LEFT_TOP;
+ public static final int ORI_TRANSVERSE = ExifInterface.Orientation.LEFT_BOTTOM;
private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5;
private Context mContext = null;
@@ -147,26 +148,13 @@ public class ImageLoader {
String path = uri.getPath();
int orientation = -1;
InputStream is = null;
+ ExifInterface exif = new ExifInterface();
try {
- is = new FileInputStream(path);
- ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
- int event = parser.next();
- while (event != ExifParser.EVENT_END) {
- if (event == ExifParser.EVENT_NEW_TAG) {
- ExifTag tag = parser.getTag();
- if (tag.getTagId() == ExifTag.TAG_ORIENTATION) {
- orientation = (int) tag.getValueAt(0);
- break;
- }
- }
- event = parser.next();
- }
+ exif.readExif(path);
+ orientation = ExifInterface.getRotationForOrientationValue(
+ exif.getTagIntValue(ExifInterface.TAG_ORIENTATION).shortValue());
} catch (IOException e) {
- e.printStackTrace();
- } catch (ExifInvalidFormatException e) {
- e.printStackTrace();
- } finally {
- Utils.closeSilently(is);
+ Log.w(LOGTAG, "Failed to read EXIF orientation", e);
}
return orientation;
}
@@ -196,9 +184,9 @@ public class ImageLoader {
return -1;
}
} catch (SQLiteException e) {
- return ExifInterface.ORIENTATION_UNDEFINED;
+ return -1;
} catch (IllegalArgumentException e) {
- return ExifInterface.ORIENTATION_UNDEFINED;
+ return -1;
} finally {
Utils.closeSilently(cursor);
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
index 595aa9b30..2ebd61f3d 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
@@ -108,7 +108,7 @@ public abstract class ImageFilterRS extends ImageFilter {
return sRS;
}
- public static synchronized void setRenderScriptContext(Activity context) {
+ public static synchronized void createRenderscriptContext(Activity context) {
if( sRS != null) {
Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
destroyRenderScriptContext();
@@ -144,12 +144,12 @@ public abstract class ImageFilterRS extends ImageFilter {
}
private static synchronized Allocation convertRGBAtoA(Bitmap bitmap) {
- Type.Builder tb_a8 = new Type.Builder(sRS, Element.U8(sRS));
+ Type.Builder tb_a8 = new Type.Builder(sRS, Element.A_8(sRS));
ScriptC_grey greyConvert = new ScriptC_grey(sRS,
sRS.getApplicationContext().getResources(), R.raw.grey);
Allocation bitmapTemp = convertBitmap(bitmap);
- if (bitmapTemp.getType().getElement().isCompatible(Element.U8(sRS))) {
+ if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(sRS))) {
return bitmapTemp;
}
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
index b88dbbc47..aa7e70065 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
@@ -21,7 +21,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
@@ -31,21 +30,15 @@ import android.provider.MediaStore.Images.ImageColumns;
import android.util.Log;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifData;
-import com.android.gallery3d.exif.ExifInvalidFormatException;
-import com.android.gallery3d.exif.ExifOutputStream;
-import com.android.gallery3d.exif.ExifReader;
-import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.presets.ImagePreset;
import com.android.gallery3d.util.XmpUtilHelper;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
@@ -55,35 +48,7 @@ import java.util.TimeZone;
*/
public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
-
private static final String LOGTAG = "SaveCopyTask";
- /**
- * Saves the bitmap in the final destination
- */
- public static void saveBitmap(Bitmap bitmap, File destination, Object xmp) {
- saveBitmap(bitmap, destination, xmp, null);
- }
-
- private static void saveBitmap(Bitmap bitmap, File destination, Object xmp, ExifData exif) {
- OutputStream os = null;
- try {
- os = new FileOutputStream(destination);
- if (exif != null) {
- ExifOutputStream eos = new ExifOutputStream(os);
- eos.setExifData(exif);
- bitmap.compress(CompressFormat.JPEG, ImageLoader.DEFAULT_COMPRESS_QUALITY, eos);
- } else {
- bitmap.compress(CompressFormat.JPEG, ImageLoader.DEFAULT_COMPRESS_QUALITY, os);
- }
- } catch (FileNotFoundException e) {
- Log.v(LOGTAG,"Error in writing "+destination.getAbsolutePath());
- } finally {
- Utils.closeSilently(os);;
- }
- if (xmp != null) {
- XmpUtilHelper.writeXMPMeta(destination.getAbsolutePath(), xmp);
- }
- }
/**
* Callback for the completed asynchronous task.
@@ -128,7 +93,8 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
ImageLoader.DEFAULT_SAVE_DIRECTORY);
}
// Create the directory if it doesn't exist
- if (!saveDirectory.exists()) saveDirectory.mkdirs();
+ if (!saveDirectory.exists())
+ saveDirectory.mkdirs();
return saveDirectory;
}
@@ -139,28 +105,59 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
return new File(saveDirectory, filename + ".JPG");
}
- private ExifData getExifData(Uri sourceUri) {
+ public Object getPanoramaXMPData(Uri source, ImagePreset preset) {
+ Object xmp = null;
+ if (preset.isPanoramaSafe()) {
+ InputStream is = null;
+ try {
+ is = context.getContentResolver().openInputStream(source);
+ xmp = XmpUtilHelper.extractXMPMeta(is);
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "Failed to get XMP data from image: ", e);
+ } finally {
+ Utils.closeSilently(is);
+ }
+ }
+ return xmp;
+ }
+
+ public boolean putPanoramaXMPData(File file, Object xmp) {
+ if (xmp != null) {
+ return XmpUtilHelper.writeXMPMeta(file.getAbsolutePath(), xmp);
+ }
+ return false;
+ }
+
+ public ExifInterface getExifData(Uri source) {
+ ExifInterface exif = new ExifInterface();
String mimeType = context.getContentResolver().getType(sourceUri);
- if (mimeType != ImageLoader.JPEG_MIME_TYPE) {
- return null;
+ if (mimeType == ImageLoader.JPEG_MIME_TYPE) {
+ InputStream inStream = null;
+ try {
+ inStream = context.getContentResolver().openInputStream(source);
+ exif.readExif(inStream);
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "Cannot find file: " + source, e);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "Cannot read exif for: " + source, e);
+ } finally {
+ Utils.closeSilently(inStream);
+ }
}
- InputStream is = null;
+ return exif;
+ }
+
+ public boolean putExifData(File file, ExifInterface exif, Bitmap image) {
+ boolean ret = false;
try {
- is = context.getContentResolver().openInputStream(sourceUri);
- ExifReader reader = new ExifReader();
- return reader.read(is);
+ exif.writeExif(image, file.getAbsolutePath());
+ ret = true;
} catch (FileNotFoundException e) {
- Log.w(LOGTAG, "Failed to find file", e);
- return null;
- } catch (ExifInvalidFormatException e) {
- Log.w(LOGTAG, "Invalid EXIF data", e);
- return null;
+ Log.w(LOGTAG, "File not found: " + file.getAbsolutePath(), e);
} catch (IOException e) {
- Log.w(LOGTAG, "Failed to read original file", e);
- return null;
- } finally {
- Utils.closeSilently(is);
+ Log.w(LOGTAG, "Could not write exif: ", e);
}
+ return ret;
}
/**
@@ -173,12 +170,12 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
return null;
}
ImagePreset preset = params[0];
- InputStream is = null;
BitmapFactory.Options options = new BitmapFactory.Options();
+ Uri uri = null;
boolean noBitmap = true;
int num_tries = 0;
// Stopgap fix for low-memory devices.
- while(noBitmap) {
+ while (noBitmap) {
try {
// Try to do bitmap operations, downsample if low-memory
Bitmap bitmap = ImageLoader.loadMutableBitmap(context, sourceUri, options);
@@ -189,24 +186,23 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
bitmap = preset.applyGeometry(bitmap);
bitmap = preset.apply(bitmap);
- Object xmp = null;
- if (preset.isPanoramaSafe()) {
- is = context.getContentResolver().openInputStream(sourceUri);
- xmp = XmpUtilHelper.extractXMPMeta(is);
- }
- ExifData exif = getExifData(sourceUri);
- if (exif != null) {
- exif.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, System.currentTimeMillis(),
- TimeZone.getDefault());
- // Since the image has been modified, set the orientation to normal.
- exif.addTag(ExifTag.TAG_ORIENTATION).setValue(ExifTag.Orientation.TOP_LEFT);
+ Object xmp = getPanoramaXMPData(sourceUri, preset);
+ ExifInterface exif = getExifData(sourceUri);
+
+ // Set tags
+ long time = System.currentTimeMillis();
+ exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, time,
+ TimeZone.getDefault());
+ exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION,
+ ExifInterface.Orientation.TOP_LEFT));
+
+ // If we succeed in writing the bitmap as a jpeg, return a uri.
+ if (putExifData(this.destinationFile, exif, bitmap)) {
+ putPanoramaXMPData(this.destinationFile, xmp);
+ uri = insertContent(context, sourceUri, this.destinationFile, saveFileName,
+ time);
}
- saveBitmap(bitmap, this.destinationFile, xmp, exif);
- bitmap.recycle();
noBitmap = false;
- } catch (FileNotFoundException ex) {
- Log.w(LOGTAG, "Failed to save image!", ex);
- return null;
} catch (java.lang.OutOfMemoryError e) {
// Try 5 times before failing for good.
if (++num_tries >= 5) {
@@ -214,13 +210,9 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
}
System.gc();
options.inSampleSize *= 2;
- } finally {
- Utils.closeSilently(is);
}
}
- Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
return uri;
-
}
@Override
@@ -267,16 +259,17 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
/**
* Insert the content (saved file) with proper source photo properties.
*/
- public static Uri insertContent(Context context, Uri sourceUri, File file, String saveFileName) {
- long now = System.currentTimeMillis() / 1000;
+ public static Uri insertContent(Context context, Uri sourceUri, File file, String saveFileName,
+ long time) {
+ time /= 1000;
final ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, saveFileName);
values.put(Images.Media.DISPLAY_NAME, file.getName());
values.put(Images.Media.MIME_TYPE, "image/jpeg");
- values.put(Images.Media.DATE_TAKEN, now);
- values.put(Images.Media.DATE_MODIFIED, now);
- values.put(Images.Media.DATE_ADDED, now);
+ values.put(Images.Media.DATE_TAKEN, time);
+ values.put(Images.Media.DATE_MODIFIED, time);
+ values.put(Images.Media.DATE_ADDED, time);
values.put(Images.Media.ORIENTATION, 0);
values.put(Images.Media.DATA, file.getAbsolutePath());
values.put(Images.Media.SIZE, file.length());
@@ -288,20 +281,20 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
querySource(context, sourceUri, projection,
new ContentResolverQueryCallback() {
- @Override
- public void onCursorResult(Cursor cursor) {
- values.put(Images.Media.DATE_TAKEN, cursor.getLong(0));
-
- double latitude = cursor.getDouble(1);
- double longitude = cursor.getDouble(2);
- // TODO: Change || to && after the default location issue is
- // fixed.
- if ((latitude != 0f) || (longitude != 0f)) {
- values.put(Images.Media.LATITUDE, latitude);
- values.put(Images.Media.LONGITUDE, longitude);
- }
- }
- });
+ @Override
+ public void onCursorResult(Cursor cursor) {
+ values.put(Images.Media.DATE_TAKEN, cursor.getLong(0));
+
+ double latitude = cursor.getDouble(1);
+ double longitude = cursor.getDouble(2);
+ // TODO: Change || to && after the default location
+ // issue is fixed.
+ if ((latitude != 0f) || (longitude != 0f)) {
+ values.put(Images.Media.LATITUDE, latitude);
+ values.put(Images.Media.LONGITUDE, longitude);
+ }
+ }
+ });
return context.getContentResolver().insert(
Images.Media.EXTERNAL_CONTENT_URI, values);
diff --git a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
index 9d50d5ac0..59c18e0f4 100644
--- a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
+++ b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java
@@ -19,13 +19,13 @@ package com.android.gallery3d.filtershow.ui;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import com.android.gallery3d.filtershow.PanelController;
-import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.cache.RenderingRequest;
import com.android.gallery3d.filtershow.cache.RenderingRequestCaller;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
@@ -33,6 +33,7 @@ import com.android.gallery3d.filtershow.imageshow.GeometryListener;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.presets.ImagePreset;
+// TODO: merge back IconButton and FilterIconButton?
public class FilterIconButton extends IconButton implements View.OnClickListener,
RenderingRequestCaller, GeometryListener {
private static final String LOGTAG = "FilterIconButton";
@@ -43,9 +44,6 @@ public class FilterIconButton extends IconButton implements View.OnClickListener
private LinearLayout mParentContainer = null;
private View.OnClickListener mListener = null;
private Bitmap mIconBitmap = null;
- private ImagePreset mPreset = null;
- private Rect mDestination = null;
-
public FilterIconButton(Context context) {
super(context);
}
@@ -68,27 +66,6 @@ public class FilterIconButton extends IconButton implements View.OnClickListener
}
@Override
- protected Bitmap drawImage(Bitmap dst, Bitmap image, Rect destination) {
- if (mOverlayOnly) {
- // TODO: merge back IconButton and FilterIconButton
- return super.drawImage(dst, image, destination);
- }
- if (mIconBitmap == null && mPreset == null) {
- dst = MasterImage.getImage().getThumbnailBitmap();
- if (dst != null) {
- ImagePreset mPreset = new ImagePreset();
- mPreset.addFilter(mFilterRepresentation);
- mPreset.setDoApplyGeometry(false);
- mDestination = destination;
- RenderingRequest.post(dst.copy(Bitmap.Config.ARGB_8888, true), mPreset, RenderingRequest.ICON_RENDERING, this);
- }
- return dst;
- } else {
- return mIconBitmap;
- }
- }
-
- @Override
public void setOnClickListener(View.OnClickListener listener) {
mListener = listener;
}
@@ -117,31 +94,55 @@ public class FilterIconButton extends IconButton implements View.OnClickListener
}
mOverlayOnly = mFilterRepresentation.getOverlayOnly();
if (mOverlayOnly) {
+ assert(mOverlayBitmap != null);
setIcon(mOverlayBitmap);
}
- stale_icon = true;
invalidate();
}
@Override
+ protected void onDraw(Canvas canvas) {
+ if (mIconBitmap == null && !mOverlayOnly) {
+ postNewIconRenderRequest();
+ }
+ super.onDraw(canvas);
+ }
+
+ @Override
public void available(RenderingRequest request) {
- if (request.getBitmap() == null) {
+ Bitmap bmap = request.getBitmap();
+ if (bmap == null) {
return;
}
- mIconBitmap = request.getBitmap();
- if (mOverlayBitmap != null) {
- mIconBitmap = super.drawImage(mIconBitmap, mOverlayBitmap, mDestination);
+ if (mOverlayOnly) {
+ setIcon(mOverlayBitmap);
+ } else {
+ mIconBitmap = bmap;
+ if (mOverlayBitmap != null) {
+ Rect destination = new Rect(0, 0, mIconBitmap.getWidth(), mIconBitmap.getHeight());
+ drawImage(mIconBitmap, mOverlayBitmap, destination);
+ }
+ setIcon(mIconBitmap);
}
- stale_icon = true;
- invalidate();
}
@Override
public void geometryChanged() {
- stale_icon = true;
-
+ if (mOverlayOnly) {
+ return;
+ }
mIconBitmap = null;
- mPreset = null;
- invalidate();
+ postNewIconRenderRequest();
+ }
+
+ private void postNewIconRenderRequest() {
+ Bitmap dst = MasterImage.getImage().getThumbnailBitmap();
+ if (dst != null) {
+ ImagePreset mPreset = new ImagePreset();
+ mPreset.addFilter(mFilterRepresentation);
+ mPreset.setDoApplyGeometry(false);
+ RenderingRequest.post(dst.copy(Bitmap.Config.ARGB_8888, true),
+ mPreset, RenderingRequest.ICON_RENDERING, this);
+ }
}
}
diff --git a/src/com/android/gallery3d/filtershow/ui/IconButton.java b/src/com/android/gallery3d/filtershow/ui/IconButton.java
index ed10be301..2484d5feb 100644
--- a/src/com/android/gallery3d/filtershow/ui/IconButton.java
+++ b/src/com/android/gallery3d/filtershow/ui/IconButton.java
@@ -30,10 +30,10 @@ import android.widget.Button;
*/
public class IconButton extends Button {
- protected Bitmap mImageMirror = null;
- protected Bitmap mIcon = null;
+ private Bitmap mImageMirror = null;
+ private Bitmap mIcon = null;
- protected boolean stale_icon = true;
+ private boolean stale_icon = true;
public IconButton(Context context) {
this(context, null);
@@ -53,7 +53,9 @@ public class IconButton extends Button {
}
/**
- * Set the image that the button icon will use.
+ * Set the image that the button icon will use. The image bitmap will be scaled
+ * and cropped into the largest square bitmap that will fit cleanly within the
+ * IconButton's layout.
*
* @param image image that icon will be set to before next draw.
*/
@@ -68,7 +70,7 @@ public class IconButton extends Button {
*
* @param image bitmap to use as icon
*/
- protected boolean makeAndSetIcon(Bitmap image) {
+ private boolean makeAndSetIcon(Bitmap image) {
int size = getGoodIconSideSize();
if (size > 0) {
return setImageIcon(makeImageIcon(image, size, size));
@@ -81,7 +83,7 @@ public class IconButton extends Button {
*
* @param image bitmap to set the icon to.
*/
- protected boolean setImageIcon(Bitmap image) {
+ private boolean setImageIcon(Bitmap image) {
if (image == null) {
return false;
}
@@ -99,11 +101,11 @@ public class IconButton extends Button {
* @param height icon height
* @return the scaled/cropped icon bitmap
*/
- protected Bitmap makeImageIcon(Bitmap image, int width, int height) {
+ private Bitmap makeImageIcon(Bitmap image, int width, int height) {
Rect destination = new Rect(0, 0, width, height);
Bitmap bmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
- bmap = drawImage(bmap, image, destination);
+ drawImage(bmap, image, destination);
return bmap;
}
@@ -113,7 +115,7 @@ public class IconButton extends Button {
*
* @return icon side length
*/
- protected int getGoodIconSideSize() {
+ private int getGoodIconSideSize() {
Paint p = getPaint();
Rect bounds = new Rect();
String s = getText().toString();
@@ -128,7 +130,9 @@ public class IconButton extends Button {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- stale_icon = true;
+ if (w != oldw || h != oldh) {
+ stale_icon = true;
+ }
}
@Override
@@ -140,12 +144,20 @@ public class IconButton extends Button {
super.onDraw(canvas);
}
- // Override this for custom icon generation
- protected Bitmap drawImage(Bitmap dst, Bitmap image, Rect destination) {
- if (image != null) {
+ /**
+ * Draws the src image into the destination rectangle within the dst bitmap.
+ * If src is a non-square image, clips to be a square before drawing into dst.
+ *
+ * @param dst bitmap being drawn on.
+ * @param src bitmap to draw into dst.
+ * @param destination square in dst in which to draw src.
+ */
+ protected static void drawImage(Bitmap dst, Bitmap src, Rect destination) {
+ if (src != null && dst != null && src.getWidth() > 0 && dst.getWidth() > 0
+ && src.getHeight() > 0 && dst.getHeight() > 0) {
Canvas canvas = new Canvas(dst);
- int iw = image.getWidth();
- int ih = image.getHeight();
+ int iw = src.getWidth();
+ int ih = src.getHeight();
int x = 0;
int y = 0;
int size = 0;
@@ -160,9 +172,8 @@ public class IconButton extends Button {
y = (int) ((ih - size) / 2.0f);
}
source = new Rect(x, y, x + size, y + size);
- canvas.drawBitmap(image, source, destination, new Paint());
+ canvas.drawBitmap(src, source, destination, new Paint());
}
- return dst;
}
}
diff --git a/src/com/android/photos/canvas/CanvasProvider.java b/src/com/android/photos/canvas/CanvasProvider.java
index 1bc55669a..92ca33c2c 100644
--- a/src/com/android/photos/canvas/CanvasProvider.java
+++ b/src/com/android/photos/canvas/CanvasProvider.java
@@ -318,8 +318,8 @@ public class CanvasProvider extends CanvasProviderBase {
break;
case BROWSE_HEADER_CASE_DEFAULT_ITEM_WIDTH:
case BROWSE_HEADER_CASE_DEFAULT_ITEM_HEIGHT:
- obj = MediaItem
- .getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL);
+ int px = MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL);
+ obj = px / getContext().getResources().getDisplayMetrics().density;
break;
}
header[j] = obj;
diff --git a/src/com/android/photos/data/PhotoProvider.java b/src/com/android/photos/data/PhotoProvider.java
index 084401d16..8413206b1 100644
--- a/src/com/android/photos/data/PhotoProvider.java
+++ b/src/com/android/photos/data/PhotoProvider.java
@@ -84,7 +84,7 @@ public class PhotoProvider extends SQLiteContentProvider {
*/
public static interface Photos extends BaseColumns {
/** Internal database table used for basic photo information. */
- public static final String TABLE = "photo";
+ public static final String TABLE = "photos";
/** Content URI for basic photo and video information. */
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);
@@ -123,7 +123,7 @@ public class PhotoProvider extends SQLiteContentProvider {
*/
public static interface Albums extends BaseColumns {
/** Internal database table used album information. */
- public static final String TABLE = "album";
+ public static final String TABLE = "albums";
/** Content URI for album information. */
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE);