Merge "Disable Thumbnailview when Panorama capture is inProgress." into ics-mr0
diff --git a/res/layout/effect_setting_popup.xml b/res/layout/effect_setting_popup.xml
index 5fa4ad2..3ef7baf 100644
--- a/res/layout/effect_setting_popup.xml
+++ b/res/layout/effect_setting_popup.xml
@@ -44,8 +44,9 @@
android:minHeight="@dimen/effect_setting_clear_text_min_height"
android:background="@drawable/bg_pressed"/>
<View style="@style/EffectTitleSeparator"/>
- <TextView
+ <TextView android:id="@+id/effect_silly_faces_title"
android:text="@string/effect_silly_faces"
+ android:visibility="gone"
style="@style/EffectSettingTypeTitle"/>
<com.android.camera.ui.ExpandedGridView android:id="@+id/effect_silly_faces"
style="@style/EffectSettingGrid"/>
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index f4ab623..685319f 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -122,6 +122,9 @@
private Parameters mInitialParams;
private boolean mFocusAreaSupported;
private boolean mMeteringAreaSupported;
+ private boolean mAeLockSupported;
+ private boolean mAwbLockSupported;
+ private boolean mAeAwbLock;
private MyOrientationEventListener mOrientationListener;
// The degrees of the device rotated clockwise from its natural orientation.
@@ -1359,7 +1362,19 @@
// Do not do focus if there is not enough storage.
if (pressed && !canTakePicture()) return;
+ // Lock AE and AWB so users can half-press shutter and recompose.
+ mAeAwbLock = pressed;
+ if (mAeAwbLock && (mAeLockSupported || mAwbLockSupported)) {
+ setCameraParameters(UPDATE_PARAM_PREFERENCE);
+ }
+
mFocusManager.doFocus(pressed);
+
+ // Unlock AE and AWB after cancelAutoFocus. Camera API does not
+ // guarantee setParameters can be called during autofocus.
+ if (!mAeAwbLock && (mAeLockSupported || mAwbLockSupported)) {
+ setCameraParameters(UPDATE_PARAM_PREFERENCE);
+ }
}
@Override
@@ -1503,7 +1518,7 @@
unregisterReceiver(mReceiver);
mDidRegister = false;
}
- mLocationManager.recordLocation(false);
+ if (mLocationManager != null) mLocationManager.recordLocation(false);
updateExposureOnScreenIndicator(0);
mFocusManager.releaseSoundPlayer();
@@ -1745,6 +1760,7 @@
setPreviewDisplay(mSurfaceHolder);
setDisplayOrientation();
+ mAeAwbLock = false; // Unlock AE and AWB.
setCameraParameters(UPDATE_PARAM_ALL);
// If the focus mode is continuous autofocus, call cancelAutoFocus to
// resume it because it may have been paused by autoFocus call.
@@ -1818,6 +1834,14 @@
}
private void updateCameraParametersPreference() {
+ if (mAeLockSupported) {
+ mParameters.setAutoExposureLock(mAeAwbLock);
+ }
+
+ if (mAwbLockSupported) {
+ mParameters.setAutoWhiteBalanceLock(mAeAwbLock);
+ }
+
if (mFocusAreaSupported) {
mParameters.setFocusAreas(mFocusManager.getFocusAreas());
}
@@ -2080,7 +2104,7 @@
private boolean switchToOtherMode(int mode) {
if (isFinishing()) return false;
- mImageSaver.waitDone();
+ if (mImageSaver != null) mImageSaver.waitDone();
MenuHelper.gotoMode(mode, Camera.this);
mHandler.removeMessages(FIRST_TIME_INIT);
finish();
@@ -2215,5 +2239,7 @@
&& isSupported(Parameters.FOCUS_MODE_AUTO,
mInitialParams.getSupportedFocusModes()));
mMeteringAreaSupported = (mInitialParams.getMaxNumMeteringAreas() > 0);
+ mAeLockSupported = mInitialParams.isAutoExposureLockSupported();
+ mAwbLockSupported = mInitialParams.isAutoWhiteBalanceLockSupported();
}
}
diff --git a/src/com/android/camera/panorama/MosaicFrameProcessor.java b/src/com/android/camera/panorama/MosaicFrameProcessor.java
index 7660f5e..300e4e3 100644
--- a/src/com/android/camera/panorama/MosaicFrameProcessor.java
+++ b/src/com/android/camera/panorama/MosaicFrameProcessor.java
@@ -65,7 +65,8 @@
private int mPreviewBufferSize;
public interface ProgressListener {
- public void onProgress(boolean isFinished, float panningRateX, float panningRateY);
+ public void onProgress(boolean isFinished, float panningRateX, float panningRateY,
+ float progressX, float progressY);
}
public MosaicFrameProcessor(int previewWidth, int previewHeight, int bufSize) {
@@ -173,11 +174,15 @@
// Publish progress of the ongoing processing
if (mProgressListener != null) {
- mProgressListener.onProgress(false, mPanningRateX, mPanningRateY);
+ mProgressListener.onProgress(false, mPanningRateX, mPanningRateY,
+ mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth,
+ mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight);
}
} else {
if (mProgressListener != null) {
- mProgressListener.onProgress(true, mPanningRateX, mPanningRateY);
+ mProgressListener.onProgress(true, mPanningRateX, mPanningRateY,
+ mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth,
+ mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight);
}
}
}
@@ -211,20 +216,20 @@
mTotalTranslationY += mDeltaY[idx];
mTotalDeltaTime += mDeltaTime[idx];
- mTranslationLastX = translationCurrX;
- mTranslationLastY = translationCurrY;
- mLastProcessedFrameTimestamp = now;
- mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE;
-
// The panning rate is measured as the rate of the translation percentage in
// image width/height. Take the horizontal panning rate for example, the image width
// used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR).
// To get the horizontal translation percentage, the horizontal translation,
// (translationCurrX - mTranslationLastX), is divided by the
// image width. We then get the rate by dividing the translation percentage with deltaTime.
- mPanningRateX = mTotalTranslationX / (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR)
- / mTotalDeltaTime;
- mPanningRateY = mTotalTranslationY / (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR)
- / mTotalDeltaTime;
+ mPanningRateX = mTotalTranslationX /
+ (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime;
+ mPanningRateY = mTotalTranslationY /
+ (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / mTotalDeltaTime;
+
+ mTranslationLastX = translationCurrX;
+ mTranslationLastY = translationCurrY;
+ mLastProcessedFrameTimestamp = now;
+ mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE;
}
}
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index 06ed3ea..25c565f 100755
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -49,8 +49,6 @@
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Bundle;
@@ -555,13 +553,14 @@
mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
@Override
- public void onProgress(boolean isFinished, float panningRateX, float panningRateY) {
+ public void onProgress(boolean isFinished, float panningRateX, float panningRateY,
+ float progressX, float progressY) {
if (isFinished
|| (mMaxAngleX - mMinAngleX >= DEFAULT_SWEEP_ANGLE)
|| (mMaxAngleY - mMinAngleY >= DEFAULT_SWEEP_ANGLE)) {
stopCapture(false);
} else {
- updateProgress(panningRateX);
+ updateProgress(panningRateX, progressX, progressY);
}
}
});
@@ -627,7 +626,7 @@
mRightIndicator.setEnabled(false);
}
- private void updateProgress(float panningRate) {
+ private void updateProgress(float panningRate, float progressX, float progressY) {
mMosaicView.setReady();
mMosaicView.requestRender();
@@ -639,6 +638,7 @@
} else {
hideTooFastIndication();
}
+ mPanoProgressBar.setProgress((int) (progressX * mHorizontalViewAngle));
}
private void createContentView() {
@@ -912,7 +912,6 @@
releaseCamera();
mMosaicView.onPause();
clearMosaicFrameProcessorIfNeeded();
- mSensorManager.unregisterListener(mListener);
mOrientationEventListener.disable();
System.gc();
}
@@ -923,14 +922,6 @@
mPausing = false;
mOrientationEventListener.enable();
- /*
- * It is not necessary to get accelerometer events at a very high rate,
- * by using a game rate (SENSOR_DELAY_UI), we get an automatic
- * low-pass filter, which "extracts" the gravity component of the
- * acceleration. As an added benefit, we use less power and CPU
- * resources.
- */
- mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI);
mCaptureState = CAPTURE_STATE_VIEWFINDER;
setupCamera();
@@ -941,55 +932,6 @@
mMosaicView.onResume();
}
- private void updateCompassValue() {
- if (mCaptureState == CAPTURE_STATE_VIEWFINDER) return;
- // By what angle has the camera moved since start of capture?
- mTraversedAngleX = (int) (mCompassValueX - mCompassValueXStart);
- mTraversedAngleY = (int) (mCompassValueY - mCompassValueYStart);
- mMinAngleX = Math.min(mMinAngleX, mTraversedAngleX);
- mMaxAngleX = Math.max(mMaxAngleX, mTraversedAngleX);
- mMinAngleY = Math.min(mMinAngleY, mTraversedAngleY);
- mMaxAngleY = Math.max(mMaxAngleY, mTraversedAngleY);
-
- // Use orientation to identify if the user is panning to the right or the left.
- switch (mDeviceOrientation) {
- case 0:
- mPanoProgressBar.setProgress(-mTraversedAngleX);
- break;
- case 90:
- mPanoProgressBar.setProgress(mTraversedAngleY);
- break;
- case 180:
- mPanoProgressBar.setProgress(mTraversedAngleX);
- break;
- case 270:
- mPanoProgressBar.setProgress(-mTraversedAngleY);
- break;
- }
- mPanoProgressBar.invalidate();
- }
-
- private final SensorEventListener mListener = new SensorEventListener() {
- public void onSensorChanged(SensorEvent event) {
- if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
- if (mTimestamp != 0) {
- final float dT = (event.timestamp - mTimestamp) * NS2S;
- mCompassValueX += event.values[1] * dT * 180.0f / Math.PI;
- mCompassValueY += event.values[0] * dT * 180.0f / Math.PI;
- mCompassValueXStartBuffer = mCompassValueX;
- mCompassValueYStartBuffer = mCompassValueY;
- updateCompassValue();
- }
- mTimestamp = event.timestamp;
-
- }
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
- };
-
public MosaicJpeg generateFinalMosaic(boolean highRes) {
if (mMosaicFrameProcessor.createMosaic(highRes) == Mosaic.MOSAIC_RET_CANCELLED) {
return null;
diff --git a/src/com/android/camera/ui/EffectSettingPopup.java b/src/com/android/camera/ui/EffectSettingPopup.java
index 606524b..c4a4d49 100644
--- a/src/com/android/camera/ui/EffectSettingPopup.java
+++ b/src/com/android/camera/ui/EffectSettingPopup.java
@@ -36,19 +36,30 @@
// effects.
public class EffectSettingPopup extends AbstractSettingPopup implements
AdapterView.OnItemClickListener, View.OnClickListener {
- private final String TAG = "EffectSettingPopup";
+ private static final String TAG = "EffectSettingPopup";
+ private String mNoEffect;
private IconListPreference mPreference;
private Listener mListener;
private View mClearEffects;
private GridView mSillyFacesGrid;
private GridView mBackgroundGrid;
+ // Data for silly face items. (text, image, and preference value)
+ ArrayList<HashMap<String, Object>> mSillyFacesItem =
+ new ArrayList<HashMap<String, Object>>();
+
+ // Data for background replacer items. (text, image, and preference value)
+ ArrayList<HashMap<String, Object>> mBackgroundItem =
+ new ArrayList<HashMap<String, Object>>();
+
+
static public interface Listener {
public void onSettingChanged();
}
public EffectSettingPopup(Context context, AttributeSet attrs) {
super(context, attrs);
+ mNoEffect = context.getString(R.string.pref_video_effect_default);
}
@Override
@@ -64,6 +75,7 @@
mPreference = preference;
Context context = getContext();
CharSequence[] entries = mPreference.getEntries();
+ CharSequence[] entryValues = mPreference.getEntryValues();
int[] iconIds = mPreference.getImageIds();
if (iconIds == null) {
iconIds = mPreference.getLargeIconIds();
@@ -72,39 +84,45 @@
// Set title.
mTitle.setText(mPreference.getTitle());
- // Prepare goofy face GridView.
- ArrayList<HashMap<String, Object>> sillyFacesItem =
- new ArrayList<HashMap<String, Object>>();
- // The first is clear effect. Skip it.
- for(int i = 1; i < EffectsRecorder.NUM_OF_GF_EFFECTS + 1; ++i) {
+ for(int i = 0; i < entries.length; ++i) {
+ String value = entryValues[i].toString();
+ if (value.equals(mNoEffect)) continue; // no effect, skip it.
HashMap<String, Object> map = new HashMap<String, Object>();
+ map.put("value", value);
map.put("text", entries[i].toString());
if (iconIds != null) map.put("image", iconIds[i]);
- sillyFacesItem.add(map);
+ if (value.startsWith("goofy_face")) {
+ mSillyFacesItem.add(map);
+ } else if (value.startsWith("backdropper")) {
+ mBackgroundItem.add(map);
+ }
}
- SimpleAdapter sillyFacesItemAdapter = new SimpleAdapter(context,
- sillyFacesItem, R.layout.effect_setting_item,
- new String[] {"text", "image"},
- new int[] {R.id.text, R.id.image});
- mSillyFacesGrid.setAdapter(sillyFacesItemAdapter);
- mSillyFacesGrid.setOnItemClickListener(this);
- // Prepare background replacer GridView.
- ArrayList<HashMap<String, Object>> backgroundItem =
- new ArrayList<HashMap<String, Object>>();
- for(int i = EffectsRecorder.NUM_OF_GF_EFFECTS + 1; i < entries.length; ++i) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("text", entries[i].toString());
- if (iconIds != null) map.put("image", iconIds[i]);
- backgroundItem.add(map);
+ boolean hasSillyFaces = mSillyFacesItem.size() > 0;
+ boolean hasBackground = mBackgroundItem.size() > 0;
+
+ // Initialize goofy face if it is supported.
+ if (hasSillyFaces) {
+ findViewById(R.id.effect_silly_faces_title).setVisibility(View.VISIBLE);
+ mSillyFacesGrid.setVisibility(View.VISIBLE);
+ SimpleAdapter sillyFacesItemAdapter = new SimpleAdapter(context,
+ mSillyFacesItem, R.layout.effect_setting_item,
+ new String[] {"text", "image"},
+ new int[] {R.id.text, R.id.image});
+ mSillyFacesGrid.setAdapter(sillyFacesItemAdapter);
+ mSillyFacesGrid.setOnItemClickListener(this);
}
- // Initialize background replacer if it is supported.
- if (backgroundItem.size() > 0) {
+
+ if (hasSillyFaces && hasBackground) {
findViewById(R.id.effect_background_separator).setVisibility(View.VISIBLE);
+ }
+
+ // Initialize background replacer if it is supported.
+ if (hasBackground) {
findViewById(R.id.effect_background_title).setVisibility(View.VISIBLE);
mBackgroundGrid.setVisibility(View.VISIBLE);
SimpleAdapter backgroundItemAdapter = new SimpleAdapter(context,
- backgroundItem, R.layout.effect_setting_item,
+ mBackgroundItem, R.layout.effect_setting_item,
new String[] {"text", "image"},
new int[] {R.id.text, R.id.image});
mBackgroundGrid.setAdapter(backgroundItemAdapter);
@@ -120,8 +138,8 @@
if (getVisibility() != View.VISIBLE) {
// Do not show or hide "Clear effects" button when the popup
// is already visible. Otherwise it looks strange.
- int index = mPreference.findIndexOfValue(mPreference.getValue());
- mClearEffects.setVisibility((index <= 0) ? View.GONE : View.VISIBLE);
+ boolean noEffect = mPreference.getValue().equals(mNoEffect);
+ mClearEffects.setVisibility(noEffect ? View.GONE : View.VISIBLE);
}
reloadPreference();
}
@@ -131,19 +149,28 @@
// The value of the preference may have changed. Update the UI.
@Override
public void reloadPreference() {
- int index = mPreference.findIndexOfValue(mPreference.getValue());
- if (index >= 0) {
- mBackgroundGrid.setItemChecked(mBackgroundGrid.getCheckedItemPosition(), false);
- mSillyFacesGrid.setItemChecked(mSillyFacesGrid.getCheckedItemPosition(), false);
- if (index >= 1 && index < EffectsRecorder.NUM_OF_GF_EFFECTS + 1) {
- mSillyFacesGrid.setItemChecked(index - 1, true);
- } else if (index >= EffectsRecorder.NUM_OF_GF_EFFECTS + 1) {
- mBackgroundGrid.setItemChecked(index - EffectsRecorder.NUM_OF_GF_EFFECTS - 1, true);
+ mBackgroundGrid.setItemChecked(mBackgroundGrid.getCheckedItemPosition(), false);
+ mSillyFacesGrid.setItemChecked(mSillyFacesGrid.getCheckedItemPosition(), false);
+
+ String value = mPreference.getValue();
+ if (value.equals(mNoEffect)) return;
+
+ for (int i = 0; i < mSillyFacesItem.size(); i++) {
+ if (value.equals(mSillyFacesItem.get(i).get("value"))) {
+ mSillyFacesGrid.setItemChecked(i, true);
+ return;
}
- } else {
- Log.e(TAG, "Invalid preference value.");
- mPreference.print();
}
+
+ for (int i = 0; i < mBackgroundItem.size(); i++) {
+ if (value.equals(mBackgroundItem.get(i).get("value"))) {
+ mBackgroundGrid.setItemChecked(i, true);
+ return;
+ }
+ }
+
+ Log.e(TAG, "Invalid preference value: " + value);
+ mPreference.print();
}
public void setSettingChangedListener(Listener listener) {
@@ -154,10 +181,11 @@
public void onItemClick(AdapterView<?> parent, View view,
int index, long id) {
if (parent == mSillyFacesGrid) {
- // The first one is clear effect.
- mPreference.setValueIndex(index + 1);
- } else { // Background replace grid.
- mPreference.setValueIndex(index + EffectsRecorder.NUM_OF_GF_EFFECTS + 1);
+ String value = (String) mSillyFacesItem.get(index).get("value");
+ mPreference.setValue(value);
+ } else if (parent == mBackgroundGrid) {
+ String value = (String) mBackgroundItem.get(index).get("value");
+ mPreference.setValue(value);
}
reloadPreference();
if (mListener != null) mListener.onSettingChanged();
@@ -166,7 +194,7 @@
@Override
public void onClick(View v) {
// Clear the effect.
- mPreference.setValueIndex(0);
+ mPreference.setValue(mNoEffect);
reloadPreference();
if (mListener != null) mListener.onSettingChanged();
}