summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:54 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:54 -0800
commit0eaec58e292ce4eaa6baadecf643f0f65e48d278 (patch)
tree78ef71512fa619ca4befa57b239be433f6aae74e /src/com/android
parent1d4c75065966c4f6f56900e31f655bfd1b334435 (diff)
downloadLegacyCamera-0eaec58e292ce4eaa6baadecf643f0f65e48d278.zip
LegacyCamera-0eaec58e292ce4eaa6baadecf643f0f65e48d278.tar.gz
LegacyCamera-0eaec58e292ce4eaa6baadecf643f0f65e48d278.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/camera/ActionMenuButton.java83
-rw-r--r--src/com/android/camera/BufferedInputStream.java231
-rw-r--r--src/com/android/camera/Camera.java685
-rw-r--r--src/com/android/camera/CameraButtonIntentReceiver.java4
-rw-r--r--src/com/android/camera/CameraSettings.java29
-rw-r--r--src/com/android/camera/ExifInterface.java2
-rw-r--r--src/com/android/camera/GalleryPicker.java437
-rw-r--r--src/com/android/camera/GallerySettings.java2
-rw-r--r--src/com/android/camera/HighlightView.java50
-rw-r--r--src/com/android/camera/ImageGallery2.java206
-rwxr-xr-xsrc/com/android/camera/ImageManager.java905
-rw-r--r--src/com/android/camera/ImageViewTouchBase.java12
-rw-r--r--src/com/android/camera/MenuHelper.java394
-rw-r--r--src/com/android/camera/MovieView.java124
-rw-r--r--src/com/android/camera/PwaUpload.java56
-rw-r--r--src/com/android/camera/SlideShow.java68
-rw-r--r--src/com/android/camera/UploadAction.java34
-rw-r--r--src/com/android/camera/UploadService.java1181
-rw-r--r--src/com/android/camera/VideoCamera.java810
-rw-r--r--src/com/android/camera/VideoPreview.java99
-rw-r--r--src/com/android/camera/ViewImage.java114
-rw-r--r--src/com/android/camera/ViewVideo.java210
-rw-r--r--src/com/android/camera/YouTubeUpload.java145
23 files changed, 2876 insertions, 3005 deletions
diff --git a/src/com/android/camera/ActionMenuButton.java b/src/com/android/camera/ActionMenuButton.java
new file mode 100644
index 0000000..65e1f0e
--- /dev/null
+++ b/src/com/android/camera/ActionMenuButton.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
+ * because we want to make the bubble taller than the text and TextView's clip is
+ * too aggressive.
+ */
+public class ActionMenuButton extends TextView {
+ private static final float CORNER_RADIUS = 8.0f;
+ private static final float PADDING_H = 5.0f;
+ private static final float PADDING_V = 1.0f;
+
+ private final RectF mRect = new RectF();
+ private Paint mPaint;
+
+ public ActionMenuButton(Context context) {
+ super(context);
+ init();
+ }
+
+ public ActionMenuButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public ActionMenuButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ setFocusable(true);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background));
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ invalidate();
+ super.drawableStateChanged();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final Layout layout = getLayout();
+ final RectF rect = mRect;
+ final int left = getCompoundPaddingLeft();
+ final int top = getExtendedPaddingTop();
+
+ rect.set(left + layout.getLineLeft(0) - PADDING_H,
+ top + layout.getLineTop(0) - PADDING_V,
+ Math.min(left + layout.getLineRight(0) + PADDING_H, mScrollX + mRight - mLeft),
+ top + layout.getLineBottom(0) + PADDING_V);
+ canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, mPaint);
+
+ super.draw(canvas);
+ }
+}
diff --git a/src/com/android/camera/BufferedInputStream.java b/src/com/android/camera/BufferedInputStream.java
deleted file mode 100644
index 1505e87..0000000
--- a/src/com/android/camera/BufferedInputStream.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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;
-/*
-* This file derives from the Apache version of the BufferedInputStream.
-* Mods to support passing in the buffer rather than creating one directly.
-*/
-import java.io.InputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-
-public class BufferedInputStream extends FilterInputStream {
- protected byte[] buf;
- protected int count;
- protected int marklimit;
- protected int markpos = -1;
- protected int pos;
-
- private boolean closed = false;
-
- public BufferedInputStream(InputStream in, byte [] buffer) {
- super(in);
- buf = buffer;
- if (buf == null) {
- throw new java.security.InvalidParameterException();
- }
- }
-
- @Override
- public synchronized int available() throws IOException {
- return count - pos + in.available();
- }
-
- @Override
- public synchronized void close() throws IOException {
- if (null != in) {
- super.close();
- in = null;
- }
- buf = null;
- closed = true;
- }
-
- private int fillbuf() throws IOException {
- if (markpos == -1 || (pos - markpos >= marklimit)) {
- /* Mark position not set or exceeded readlimit */
- int result = in.read(buf);
- if (result > 0) {
- markpos = -1;
- pos = 0;
- count = result == -1 ? 0 : result;
- }
- return result;
- }
- if (markpos == 0 && marklimit > buf.length) {
- /* Increase buffer size to accomodate the readlimit */
- int newLength = buf.length * 2;
- if (newLength > marklimit) {
- newLength = marklimit;
- }
- byte[] newbuf = new byte[newLength];
- System.arraycopy(buf, 0, newbuf, 0, buf.length);
- buf = newbuf;
- } else if (markpos > 0) {
- System.arraycopy(buf, markpos, buf, 0, buf.length - markpos);
- }
- /* Set the new position and mark position */
- pos -= markpos;
- count = markpos = 0;
- int bytesread = in.read(buf, pos, buf.length - pos);
- count = bytesread <= 0 ? pos : pos + bytesread;
- return bytesread;
- }
-
- @Override
- public synchronized void mark(int readlimit) {
- marklimit = readlimit;
- markpos = pos;
- }
-
- @Override
- public boolean markSupported() {
- return true;
- }
-
- @Override
- public synchronized int read() throws IOException {
- if (in == null) {
- // K0059=Stream is closed
- throw new IOException(); //$NON-NLS-1$
- }
-
- /* Are there buffered bytes available? */
- if (pos >= count && fillbuf() == -1) {
- return -1; /* no, fill buffer */
- }
-
- /* Did filling the buffer fail with -1 (EOF)? */
- if (count - pos > 0) {
- return buf[pos++] & 0xFF;
- }
- return -1;
- }
-
- @Override
- public synchronized int read(byte[] buffer, int offset, int length)
- throws IOException {
- if (closed) {
- // K0059=Stream is closed
- throw new IOException(); //$NON-NLS-1$
- }
- // avoid int overflow
- if (offset > buffer.length - length || offset < 0 || length < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (length == 0) {
- return 0;
- }
- if (null == buf) {
- throw new IOException(); //$NON-NLS-1$
- }
-
- int required;
- if (pos < count) {
- /* There are bytes available in the buffer. */
- int copylength = count - pos >= length ? length : count - pos;
- System.arraycopy(buf, pos, buffer, offset, copylength);
- pos += copylength;
- if (copylength == length || in.available() == 0) {
- return copylength;
- }
- offset += copylength;
- required = length - copylength;
- } else {
- required = length;
- }
-
- while (true) {
- int read;
- /*
- * If we're not marked and the required size is greater than the
- * buffer, simply read the bytes directly bypassing the buffer.
- */
- if (markpos == -1 && required >= buf.length) {
- read = in.read(buffer, offset, required);
- if (read == -1) {
- return required == length ? -1 : length - required;
- }
- } else {
- if (fillbuf() == -1) {
- return required == length ? -1 : length - required;
- }
- read = count - pos >= required ? required : count - pos;
- System.arraycopy(buf, pos, buffer, offset, read);
- pos += read;
- }
- required -= read;
- if (required == 0) {
- return length;
- }
- if (in.available() == 0) {
- return length - required;
- }
- offset += read;
- }
- }
-
- @Override
- public synchronized void reset() throws IOException {
- if (closed) {
- // K0059=Stream is closed
- throw new IOException(); //$NON-NLS-1$
- }
- if (-1 == markpos) {
- // K005a=Mark has been invalidated.
- throw new IOException(); //$NON-NLS-1$
- }
- pos = markpos;
- }
-
- @Override
- public synchronized long skip(long amount) throws IOException {
- if (null == in) {
- // K0059=Stream is closed
- throw new IOException(); //$NON-NLS-1$
- }
- if (amount < 1) {
- return 0;
- }
-
- if (count - pos >= amount) {
- pos += amount;
- return amount;
- }
- long read = count - pos;
- pos = count;
-
- if (markpos != -1) {
- if (amount <= marklimit) {
- if (fillbuf() == -1) {
- return read;
- }
- if (count - pos >= amount - read) {
- pos += amount - read;
- return amount;
- }
- // Couldn't get all the bytes, skip what we read
- read += (count - pos);
- pos = count;
- return read;
- }
- markpos = -1;
- }
- return read + in.skip(amount - read);
- }
-}
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index ef99842..b79e7d1 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -16,8 +16,16 @@
package com.android.camera;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
import android.app.Activity;
import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -46,11 +54,10 @@ import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.os.SystemClock;
-import android.pim.DateFormat;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
+import android.text.format.DateFormat;
import android.util.Config;
import android.util.Log;
import android.view.KeyEvent;
@@ -69,57 +76,60 @@ import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.Toast;
-import java.util.ArrayList;
-
public class Camera extends Activity implements View.OnClickListener, SurfaceHolder.Callback {
-
+
private static final String TAG = "camera";
-
+
private static final boolean DEBUG = false;
-
+
private static final int CROP_MSG = 1;
private static final int KEEP = 2;
private static final int RESTART_PREVIEW = 3;
private static final int CLEAR_SCREEN_DELAY = 4;
-
+
private static final int SCREEN_DELAY = 2 * 60 * 1000;
+ private static final int POST_PICTURE_ALERT_TIMEOUT = 6 * 1000;
private static final int FOCUS_BEEP_VOLUME = 100;
private static final int NO_STORAGE_ERROR = -1;
private static final int CANNOT_STAT_ERROR = -2;
-
+
public static final int MENU_SWITCH_TO_VIDEO = 0;
- public static final int MENU_FLASH_SETTING = 1;
- public static final int MENU_FLASH_AUTO = 2;
- public static final int MENU_FLASH_ON = 3;
- public static final int MENU_FLASH_OFF = 4;
- public static final int MENU_SETTINGS = 5;
- public static final int MENU_GALLERY_PHOTOS = 6;
+ public static final int MENU_SWITCH_TO_CAMERA = 1;
+ public static final int MENU_FLASH_SETTING = 2;
+ public static final int MENU_FLASH_AUTO = 3;
+ public static final int MENU_FLASH_ON = 4;
+ public static final int MENU_FLASH_OFF = 5;
+ public static final int MENU_SETTINGS = 6;
+ public static final int MENU_GALLERY_PHOTOS = 7;
+ public static final int MENU_GALLERY_VIDEOS = 8;
public static final int MENU_SAVE_SELECT_PHOTOS = 30;
public static final int MENU_SAVE_NEW_PHOTO = 31;
public static final int MENU_SAVE_SELECTVIDEO = 32;
public static final int MENU_SAVE_TAKE_NEW_VIDEO = 33;
public static final int MENU_SAVE_GALLERY_PHOTO = 34;
- public static final int MENU_SAVE_GALLERY_VIDEO_PHOTO = 35;
- public static final int MENU_SAVE_CAMERA_DONE = 36;
+ public static final int MENU_SAVE_GALLERY_VIDEO_PHOTO = 35;
+ public static final int MENU_SAVE_CAMERA_DONE = 36;
public static final int MENU_SAVE_CAMERA_VIDEO_DONE = 37;
-
+
Toast mToast;
OrientationListener mOrientationListener;
int mLastOrientation = OrientationListener.ORIENTATION_UNKNOWN;
SharedPreferences mPreferences;
-
+
static final int IDLE = 1;
static final int SNAPSHOT_IN_PROGRESS = 2;
static final int SNAPSHOT_COMPLETED = 3;
-
+
int mStatus = IDLE;
+ static final String sTempCropFilename = "crop-temp";
android.hardware.Camera mCameraDevice;
- SurfaceView mSurfaceView;
+ VideoPreview mSurfaceView;
SurfaceHolder mSurfaceHolder = null;
ImageView mBlackout = null;
+ int mOriginalViewFinderWidth, mOriginalViewFinderHeight;
int mViewFinderWidth, mViewFinderHeight;
boolean mPreviewing = false;
@@ -127,7 +137,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
Capturer mCaptureObject;
ImageCapture mImageCapture = null;
-
+
boolean mPausing = false;
boolean mIsFocusing = false;
@@ -139,43 +149,39 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
boolean mDidRegister = false;
int mCurrentZoomIndex = 0;
-
- private static final int STILL_MODE = 1;
- private static final int VIDEO_MODE = 2;
- private int mMode = STILL_MODE;
ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
-
+
boolean mMenuSelectionMade;
-
+
View mPostPictureAlert;
LocationManager mLocationManager = null;
private Animation mFocusBlinkAnimation;
private View mFocusIndicator;
private ToneGenerator mFocusToneGenerator;
-
+
+
private ShutterCallback mShutterCallback = new ShutterCallback();
private RawPictureCallback mRawPictureCallback = new RawPictureCallback();
- private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback();
private AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback();
private long mShutterPressTime;
private int mPicturesRemaining;
private boolean mKeepAndRestartPreview;
- private Handler mHandler = new MainHandler();
+ private Handler mHandler = new MainHandler();
private ProgressDialog mSavingProgress;
-
+
interface Capturer {
- Uri getLastCaptureUri();
- void onSnap();
+ Uri getLastCaptureUri();
+ void onSnap();
void dismissFreezeFrame(boolean keep);
- void cancelSave();
- void cancelAutoDismiss();
- void setDone(boolean wait);
+ void cancelSave();
+ void cancelAutoDismiss();
+ void setDone(boolean wait);
}
-
+
private void cancelSavingNotification() {
if (mToast != null) {
mToast.cancel();
@@ -194,15 +200,15 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mSavingProgress.cancel();
mSavingProgress = null;
}
-
+
mKeepAndRestartPreview = true;
-
+
if (msg.obj != null) {
mHandler.post((Runnable)msg.obj);
}
break;
}
-
+
case RESTART_PREVIEW: {
if (mStatus == SNAPSHOT_IN_PROGRESS) {
// We are still in the processing of taking the picture, wait.
@@ -210,11 +216,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
// TODO remove polling
mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 100);
} else if (mStatus == SNAPSHOT_COMPLETED){
+ hidePostPictureAlert();
mCaptureObject.dismissFreezeFrame(true);
}
break;
}
-
+
case CLEAR_SCREEN_DELAY: {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
break;
@@ -222,13 +229,13 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
};
-
+
LocationListener [] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
-
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -248,17 +255,17 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
};
-
+
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
boolean mValid = false;
String mProvider;
-
+
public LocationListener(String provider) {
mProvider = provider;
mLastLocation = new Location(mProvider);
}
-
+
public void onLocationChanged(Location newLocation) {
if (newLocation.getLatitude() == 0.0 && newLocation.getLongitude() == 0.0) {
// Hack to filter out 0.0,0.0 locations
@@ -267,7 +274,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mLastLocation.set(newLocation);
mValid = true;
}
-
+
public void onProviderEnabled(String provider) {
}
@@ -280,12 +287,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mValid = false;
}
}
-
+
public Location current() {
return mValid ? mLastLocation : null;
}
};
-
+
private long mRawPictureCallbackTime;
private boolean mImageSavingItem = false;
@@ -302,25 +309,31 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
};
-
- private final class RawPictureCallback implements PictureCallback {
+
+ private final class RawPictureCallback implements PictureCallback {
public void onPictureTaken(byte [] rawData, android.hardware.Camera camera) {
if (Config.LOGV)
Log.v(TAG, "got RawPictureCallback...");
mRawPictureCallbackTime = System.currentTimeMillis();
mBlackout.setVisibility(View.INVISIBLE);
if (!isPickIntent() && mPreferences.getBoolean("pref_camera_postpicturemenu_key", true)) {
- mPostPictureAlert.setVisibility(View.VISIBLE);
+ showPostPictureAlert();
}
}
};
-
+
private final class JpegPictureCallback implements PictureCallback {
+ Location mLocation;
+
+ public JpegPictureCallback(Location loc) {
+ mLocation = loc;
+ }
+
public void onPictureTaken(byte [] jpegData, android.hardware.Camera camera) {
if (Config.LOGV)
Log.v(TAG, "got JpegPictureCallback...");
- mImageCapture.storeImage(jpegData, camera);
+ mImageCapture.storeImage(jpegData, camera, mLocation);
mStatus = SNAPSHOT_COMPLETED;
@@ -335,15 +348,15 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
if (mKeepAndRestartPreview) {
mKeepAndRestartPreview = false;
mPostPictureAlert.setVisibility(View.INVISIBLE);
-
+
// Post this message so that we can finish processing the request. This also
// prevents the preview from showing up before mPostPictureAlert is dismissed.
mHandler.sendEmptyMessage(RESTART_PREVIEW);
}
-
+
}
};
-
+
private final class AutoFocusCallback implements android.hardware.Camera.AutoFocusCallback {
public void onAutoFocus(boolean focused, android.hardware.Camera camera) {
mIsFocusing = false;
@@ -354,42 +367,44 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mCaptureObject.onSnap();
clearFocus();
} else {
- mFocusToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2);
+ ToneGenerator tg = mFocusToneGenerator;
+ if (tg != null)
+ tg.startTone(ToneGenerator.TONE_PROP_BEEP2);
}
mCaptureOnFocus = false;
}
updateFocusIndicator();
}
};
-
+
private class ImageCapture implements Capturer {
-
+
private boolean mCancel = false;
private boolean mCapturing = false;
-
+
private Uri mLastContentUri;
private ImageManager.IAddImage_cancelable mAddImageCancelable;
Bitmap mCaptureOnlyBitmap;
-
+
/** These member variables are used for various debug timings */
private long mThreadTimeStart;
private long mThreadTimeEnd;
private long mWallTimeStart;
private long mWallTimeEnd;
-
+
public ImageCapture() {
}
- /**
+ /**
* This method sets whether or not we are capturing a picture. This method must be called
* with the ImageCapture.this lock held.
*/
public void setCapturingLocked(boolean capturing) {
mCapturing = capturing;
}
-
+
/*
* Tell the ImageCapture thread to exit when possible.
*/
@@ -409,7 +424,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
} else {
Toast.makeText(Camera.this, R.string.camera_tossing, Toast.LENGTH_SHORT).show();
}
-
+
if (mStatus == SNAPSHOT_IN_PROGRESS) {
// If we are still in the process of taking a picture, then just post a message.
mHandler.sendEmptyMessage(RESTART_PREVIEW);
@@ -417,31 +432,31 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
restartPreview();
}
}
-
+
private void startTiming() {
mWallTimeStart = SystemClock.elapsedRealtime();
mThreadTimeStart = Debug.threadCpuTimeNanos();
}
-
+
private void stopTiming() {
mThreadTimeEnd = Debug.threadCpuTimeNanos();
mWallTimeEnd = SystemClock.elapsedRealtime();
}
-
- private void storeImage(byte[] data) {
+
+ private void storeImage(byte[] data, Location loc) {
try {
if (DEBUG) {
startTiming();
}
-
+ long dateTaken = System.currentTimeMillis();
mLastContentUri = ImageManager.instance().addImage(
Camera.this,
mContentResolver,
- DateFormat.format("yyyy-MM-dd kk.mm.ss", System.currentTimeMillis()).toString(),
+ createName(dateTaken),
"",
- System.currentTimeMillis(),
+ dateTaken,
// location for the database goes here
- null,
+ loc,
0, // the dsp will use the right orientation so don't "double set it"
ImageManager.CAMERA_IMAGE_BUCKET_NAME,
null);
@@ -456,46 +471,46 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mAddImageCancelable.get();
mAddImageCancelable = null;
}
-
+
if (DEBUG) {
stopTiming();
Log.d(TAG, "Storing image took " + (mWallTimeEnd - mWallTimeStart) + " ms. " +
- "Thread time was " + ((mThreadTimeEnd - mThreadTimeStart) / 1000000) +
+ "Thread time was " + ((mThreadTimeEnd - mThreadTimeStart) / 1000000) +
" ms.");
}
} catch (Exception ex) {
Log.e(TAG, "Exception while compressing image.", ex);
}
}
-
- public void storeImage(byte[] data, android.hardware.Camera camera) {
+
+ public void storeImage(byte[] data, android.hardware.Camera camera, Location loc) {
boolean captureOnly = isPickIntent();
-
+
if (!captureOnly) {
- storeImage(data);
+ storeImage(data, loc);
sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", mLastContentUri));
} else {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
-
+
if (DEBUG) {
startTiming();
}
-
+
mCaptureOnlyBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
-
+
if (DEBUG) {
stopTiming();
Log.d(TAG, "Decoded mCaptureOnly bitmap (" + mCaptureOnlyBitmap.getWidth() +
- "x" + mCaptureOnlyBitmap.getHeight() + " ) in " +
- (mWallTimeEnd - mWallTimeStart) + " ms. Thread time was " +
+ "x" + mCaptureOnlyBitmap.getHeight() + " ) in " +
+ (mWallTimeEnd - mWallTimeStart) + " ms. Thread time was " +
((mThreadTimeEnd - mThreadTimeStart) / 1000000) + " ms.");
}
-
+
openOptionsMenu();
}
-
-
+
+
mCapturing = false;
if (mPausing) {
closeCamera();
@@ -510,9 +525,9 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
if (!mCapturing) {
return;
}
-
+
mCancel = true;
-
+
if (mAddImageCancelable != null) {
mAddImageCancelable.cancel();
}
@@ -526,25 +541,25 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
if (mCameraDevice == null) {
return;
}
-
+
mCancel = false;
mCapturing = true;
capture(captureOnly);
}
-
+
public Uri getLastCaptureUri() {
return mLastContentUri;
}
-
+
public Bitmap getLastBitmap() {
return mCaptureOnlyBitmap;
}
-
+
private void capture(boolean captureOnly) {
mPreviewing = false;
mCaptureOnlyBitmap = null;
-
+
final int latchedOrientation = ImageManager.roundOrientation(mLastOrientation + 90);
Boolean recordLocation = mPreferences.getBoolean("pref_camera_recordlocation_key", false);
@@ -554,35 +569,38 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
// get large. 85 is a good compromise between the two.
parameters.set("jpeg-quality", 85);
parameters.set("rotation", latchedOrientation);
+
+ parameters.remove("gps-latitude");
+ parameters.remove("gps-longitude");
+ parameters.remove("gps-altitude");
+ parameters.remove("gps-timestamp");
+
if (loc != null) {
- parameters.set("gps-latitude", String.valueOf(loc.getLatitude()));
- parameters.set("gps-longitude", String.valueOf(loc.getLongitude()));
- parameters.set("gps-altitude", String.valueOf(loc.getAltitude()));
- parameters.set("gps-timestamp", String.valueOf(loc.getTime()));
- } else {
- parameters.remove("gps-latitude");
- parameters.remove("gps-longitude");
- parameters.remove("gps-altitude");
- parameters.remove("gps-timestamp");
+ double lat = loc.getLatitude();
+ double lon = loc.getLongitude();
+
+ if (lat != 0D && lon != 0d) {
+ parameters.set("gps-latitude", String.valueOf(lat));
+ parameters.set("gps-longitude", String.valueOf(lon));
+ if (loc.hasAltitude())
+ parameters.set("gps-altitude", String.valueOf(loc.getAltitude()));
+ if (loc.getTime() != 0)
+ parameters.set("gps-timestamp", String.valueOf(loc.getTime()));
+ } else {
+ loc = null;
+ }
}
Size pictureSize = parameters.getPictureSize();
- Size previewSize = parameters.getPreviewSize();
// resize the SurfaceView to the aspect-ratio of the still image
// and so that we can see the full image that was taken
- ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
- if (pictureSize.width*previewSize.height < previewSize.width*pictureSize.height) {
- lp.width = (pictureSize.width * previewSize.height) / pictureSize.height;
- } else {
- lp.height = (pictureSize.height * previewSize.width) / pictureSize.width;
- }
- mSurfaceView.requestLayout();
+ mSurfaceView.setAspectRatio(pictureSize.width, pictureSize.height);
mCameraDevice.setParameters(parameters);
-
- mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
-
+
+ mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback, new JpegPictureCallback(loc));
+
mBlackout.setVisibility(View.VISIBLE);
// Comment this out for now until we can decode the preview frame. This currently
// just animates black-on-black because the surface flinger blacks out the surface
@@ -612,7 +630,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
showStorageToast();
return;
}
-
+
mStatus = SNAPSHOT_IN_PROGRESS;
mKeepAndRestartPreview = !mPreferences.getBoolean("pref_camera_postpicturemenu_key", true);
@@ -626,6 +644,11 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
+
+ static private String createName(long dateTaken) {
+ return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
+ }
+
static public Matrix GetDisplayMatrix(Bitmap b, ImageView v) {
Matrix m = new Matrix();
float bw = (float)b.getWidth();
@@ -649,12 +672,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
private void postAfterKeep(final Runnable r) {
Resources res = getResources();
-
+
if (mSavingProgress != null) {
- mSavingProgress = ProgressDialog.show(this, res.getString(R.string.savingImage),
+ mSavingProgress = ProgressDialog.show(this, res.getString(R.string.savingImage),
res.getString(R.string.wait));
}
-
+
Message msg = mHandler.obtainMessage(KEEP);
msg.obj = r;
msg.sendToTarget();
@@ -672,38 +695,35 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
//setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
requestWindowFeature(Window.FEATURE_PROGRESS);
-
+
Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.camera);
- mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
-
+ mSurfaceView = (VideoPreview) findViewById(R.id.camera_preview);
+
// don't set mSurfaceHolder here. We have it set ONLY within
// surfaceCreated / surfaceDestroyed, other parts of the code
// assume that when it is set, the surface is also set.
SurfaceHolder holder = mSurfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-
+
mBlackout = (ImageView) findViewById(R.id.blackout);
mBlackout.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mPostPictureAlert = findViewById(R.id.post_picture_panel);
View b;
-
- b = findViewById(R.id.save);
- b.setOnClickListener(this);
-
+
b = findViewById(R.id.discard);
b.setOnClickListener(this);
-
+
b = findViewById(R.id.share);
b.setOnClickListener(this);
b = findViewById(R.id.setas);
b.setOnClickListener(this);
-
+
try {
mClickSound = new MediaPlayer();
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.camera_click);
@@ -719,27 +739,27 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
} catch (Exception ex) {
Log.w(TAG, "Couldn't create click sound", ex);
}
-
+
mOrientationListener = new OrientationListener(this) {
public void onOrientationChanged(int orientation) {
mLastOrientation = orientation;
}
};
-
+
mFocusIndicator = findViewById(R.id.focus_indicator);
mFocusBlinkAnimation = AnimationUtils.loadAnimation(this, R.anim.auto_focus_blink);
mFocusBlinkAnimation.setRepeatCount(Animation.INFINITE);
mFocusBlinkAnimation.setRepeatMode(Animation.REVERSE);
}
-
+
@Override
public void onStart() {
super.onStart();
-
+
final View hintView = findViewById(R.id.hint_toast);
if (hintView != null)
hintView.setVisibility(View.GONE);
-
+
Thread t = new Thread(new Runnable() {
public void run() {
final boolean storageOK = calculatePicturesRemaining() > 0;
@@ -761,7 +781,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
hintView.setVisibility(View.GONE);
}
}, 3000);
- } else {
+ } else {
mHandler.post(new Runnable() {
public void run() {
hintView.setVisibility(View.GONE);
@@ -773,15 +793,17 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
});
t.start();
}
-
+
public void onClick(View v) {
switch (v.getId()) {
+ /*
case R.id.save: {
- mPostPictureAlert.setVisibility(View.INVISIBLE);
+ mPostPictureAlert.setVisibility(View.GONE);
postAfterKeep(null);
break;
}
-
+ */
+
case R.id.discard: {
if (mCaptureObject != null) {
mCaptureObject.cancelSave();
@@ -791,12 +813,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
mCaptureObject.dismissFreezeFrame(true);
}
- mPostPictureAlert.setVisibility(View.INVISIBLE);
+ mPostPictureAlert.setVisibility(View.GONE);
break;
}
-
+
case R.id.share: {
- mPostPictureAlert.setVisibility(View.INVISIBLE);
+ mPostPictureAlert.setVisibility(View.GONE);
postAfterKeep(new Runnable() {
public void run() {
Uri u = mCaptureObject.getLastCaptureUri();
@@ -807,15 +829,15 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
try {
startActivity(Intent.createChooser(intent, getText(R.string.sendImage)));
} catch (android.content.ActivityNotFoundException ex) {
- Toast.makeText(Camera.this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show();
+ Toast.makeText(Camera.this, R.string.no_way_to_share_image, Toast.LENGTH_SHORT).show();
}
}
});
break;
}
-
+
case R.id.setas: {
- mPostPictureAlert.setVisibility(View.INVISIBLE);
+ mPostPictureAlert.setVisibility(View.GONE);
postAfterKeep(new Runnable() {
public void run() {
Uri u = mCaptureObject.getLastCaptureUri();
@@ -831,9 +853,6 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
}
-
- void keepVideo() {
- };
private void showStorageToast() {
String noStorageText = null;
@@ -854,14 +873,10 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
public void onResume() {
super.onResume();
mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
-
+
mPausing = false;
mOrientationListener.enable();
- if (isPickIntent()) {
- mMode = STILL_MODE;
- }
-
// install an intent filter to receive SD card related events.
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
@@ -874,14 +889,19 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mImageCapture = new ImageCapture();
restartPreview();
-
+
if (mPreferences.getBoolean("pref_camera_recordlocation_key", false))
startReceivingLocationUpdates();
-
+
updateFocusIndicator();
- mFocusToneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
-
+ try {
+ mFocusToneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Exception caught while creating local tone generator: " + e);
+ mFocusToneGenerator = null;
+ }
+
mBlackout.setVisibility(View.INVISIBLE);
}
@@ -905,7 +925,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mPausing = true;
mOrientationListener.disable();
-
+
stopPreview();
if (!mImageCapture.mCapturing) {
@@ -916,8 +936,11 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mDidRegister = false;
}
stopReceivingLocationUpdates();
- mFocusToneGenerator.release();
- mFocusToneGenerator = null;
+
+ if (mFocusToneGenerator != null) {
+ mFocusToneGenerator.release();
+ mFocusToneGenerator = null;
+ }
super.onPause();
}
@@ -935,6 +958,10 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
setResult(resultCode, intent);
finish();
+
+ File path = getFileStreamPath(sTempCropFilename);
+ path.delete();
+
break;
}
}
@@ -950,13 +977,13 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
}
-
+
private void clearFocus() {
mIsFocusing = false;
mIsFocused = false;
mIsFocusButtonPressed = false;
}
-
+
private void updateFocusIndicator() {
mHandler.post(new Runnable() {
public void run() {
@@ -976,10 +1003,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
});
}
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (mStatus == SNAPSHOT_IN_PROGRESS || mStatus == SNAPSHOT_COMPLETED) {
@@ -1049,12 +1078,10 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- if (mMode == STILL_MODE) {
- // if we're creating the surface, start the preview as well.
- boolean preview = holder.isCreating();
- setViewFinder(w, h, preview);
- mCaptureObject = mImageCapture;
- }
+ // if we're creating the surface, start the preview as well.
+ boolean preview = holder.isCreating();
+ setViewFinder(w, h, preview);
+ mCaptureObject = mImageCapture;
}
public void surfaceCreated(SurfaceHolder holder) {
@@ -1065,7 +1092,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
stopPreview();
mSurfaceHolder = null;
}
-
+
private void closeCamera() {
if (mCameraDevice != null) {
mCameraDevice.release();
@@ -1073,26 +1100,23 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mPreviewing = false;
}
}
-
+
private boolean ensureCameraDevice() {
if (mCameraDevice == null) {
mCameraDevice = android.hardware.Camera.open();
}
return mCameraDevice != null;
}
-
+
private void restartPreview() {
- SurfaceView surfaceView = mSurfaceView;
- if (surfaceView == null ||
+ VideoPreview surfaceView = mSurfaceView;
+ if (surfaceView == null ||
surfaceView.getWidth() == 0 || surfaceView.getHeight() == 0) {
return;
}
// make sure the surfaceview fills the whole screen when previewing
- ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
- lp.width = ViewGroup.LayoutParams.FILL_PARENT;
- lp.height = ViewGroup.LayoutParams.FILL_PARENT;
- surfaceView.requestLayout();
- setViewFinder(mViewFinderWidth, mViewFinderHeight, true);
+ surfaceView.setAspectRatio(VideoPreview.DONT_CARE);
+ setViewFinder(mOriginalViewFinderWidth, mOriginalViewFinderHeight, true);
mStatus = IDLE;
// Calculate this in advance of each shot so we don't add to shutter latency. It's true that
@@ -1102,37 +1126,41 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
// let the user take a picture, and delete that file if needed to save the new photo.
calculatePicturesRemaining();
}
-
+
private void setViewFinder(int w, int h, boolean startPreview) {
if (mPausing)
return;
-
- if (mPreviewing &&
- w == mViewFinderWidth &&
+
+ if (mPreviewing &&
+ w == mViewFinderWidth &&
h == mViewFinderHeight) {
return;
}
-
+
if (!ensureCameraDevice())
return;
-
+
if (mSurfaceHolder == null)
return;
-
+
if (isFinishing())
return;
-
+
if (mPausing)
return;
-
+
// remember view finder size
mViewFinderWidth = w;
mViewFinderHeight = h;
+ if (mOriginalViewFinderHeight == 0) {
+ mOriginalViewFinderWidth = w;
+ mOriginalViewFinderHeight = h;
+ }
if (startPreview == false)
return;
- /*
+ /*
* start the preview if we're asked to...
*/
@@ -1140,21 +1168,31 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
// stop the preview first (this will blank the screen).
if (mPreviewing)
stopPreview();
-
+
// this blanks the screen if the surface changed, no-op otherwise
- mCameraDevice.setPreviewDisplay(mSurfaceHolder);
-
+ try {
+ mCameraDevice.setPreviewDisplay(mSurfaceHolder);
+ } catch (IOException exception) {
+ mCameraDevice.release();
+ mCameraDevice = null;
+ // TODO: add more exception handling logic here
+ return;
+ }
// request the preview size, the hardware may not honor it,
// if we depended on it we would have to query the size again
android.hardware.Camera.Parameters p = mCameraDevice.getParameters();
p.setPreviewSize(w, h);
- mCameraDevice.setParameters(p);
-
-
+ try {
+ mCameraDevice.setParameters(p);
+ } catch (IllegalArgumentException e) {
+ // Ignore this error, it happens in the simulator.
+ }
+
+
final long wallTimeStart = SystemClock.elapsedRealtime();
final long threadTimeStart = Debug.threadCpuTimeNanos();
-
+
final Object watchDogSync = new Object();
Thread watchDog = new Thread(new Runnable() {
public void run() {
@@ -1169,7 +1207,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
if (mPreviewing)
break;
-
+
int delay = (int) (SystemClock.elapsedRealtime() - wallTimeStart) / 1000;
if (delay >= next_warning) {
if (delay < 120) {
@@ -1194,19 +1232,24 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
if (Config.LOGV)
Log.v(TAG, "calling mCameraDevice.startPreview");
- mCameraDevice.startPreview();
+ try {
+ mCameraDevice.startPreview();
+ } catch (Throwable e) {
+ // TODO: change Throwable to IOException once android.hardware.Camera.startPreview
+ // properly declares that it throws IOException.
+ }
mPreviewing = true;
-
+
synchronized (watchDogSync) {
watchDogSync.notify();
}
-
+
long threadTimeEnd = Debug.threadCpuTimeNanos();
long wallTimeEnd = SystemClock.elapsedRealtime();
if ((wallTimeEnd - wallTimeStart) > 3000) {
Log.w(TAG, "startPreview() to " + (wallTimeEnd - wallTimeStart) + " ms. Thread time was"
+ (threadTimeEnd - threadTimeStart) / 1000000 + " ms.");
- }
+ }
}
private void stopPreview() {
@@ -1217,10 +1260,13 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
void gotoGallery() {
- Uri target = mMode == STILL_MODE ? Images.Media.INTERNAL_CONTENT_URI
- : Video.Media.INTERNAL_CONTENT_URI;
+ Uri target = Images.Media.INTERNAL_CONTENT_URI;
Intent intent = new Intent(Intent.ACTION_VIEW, target);
- startActivity(intent);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Could not start gallery activity", e);
+ }
}
void keep() {
@@ -1236,27 +1282,27 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mCaptureObject.cancelSave();
}
};
-
+
private ImageManager.IImage getImageForURI(Uri uri) {
ImageManager.IImageList list = ImageManager.instance().allImages(
this,
- mContentResolver,
- dataLocation(),
- ImageManager.INCLUDE_IMAGES,
+ mContentResolver,
+ dataLocation(),
+ ImageManager.INCLUDE_IMAGES,
ImageManager.SORT_ASCENDING);
ImageManager.IImage image = list.getImageForUri(uri);
list.deactivate();
return image;
}
-
-
+
+
private void startReceivingLocationUpdates() {
if (mLocationManager != null) {
try {
mLocationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER,
- 1000,
- 0F,
+ LocationManager.NETWORK_PROVIDER,
+ 1000,
+ 0F,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
// ok
@@ -1267,9 +1313,9 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
try {
mLocationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER,
- 1000,
- 0F,
+ LocationManager.GPS_PROVIDER,
+ 1000,
+ 0F,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
// ok
@@ -1280,7 +1326,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
}
-
+
private void stopReceivingLocationUpdates() {
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
@@ -1292,18 +1338,20 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
}
}
-
+
private Location getCurrentLocation() {
Location l = null;
-
- // go in worst to best order
- for (int i = 0; i < mLocationListeners.length && l == null; i++) {
+
+ // go in best to worst order
+ for (int i = 0; i < mLocationListeners.length; i++) {
l = mLocationListeners[i].current();
+ if (l != null)
+ break;
}
-
+
return l;
}
-
+
@Override
public void onOptionsMenuClosed(Menu menu) {
super.onOptionsMenuClosed(menu);
@@ -1315,7 +1363,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
mHandler.sendEmptyMessage(RESTART_PREVIEW);
}
}
-
+
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
@@ -1327,28 +1375,25 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
return super.onMenuOpened(featureId, menu);
}
-
+
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
mMenuSelectionMade = false;
-
+
for (int i = 1; i <= MenuHelper.MENU_ITEM_MAX; i++) {
if (i != MenuHelper.GENERIC_ITEM) {
menu.setGroupVisible(i, false);
}
}
-
- if (mMode == STILL_MODE) {
- if (mStatus == SNAPSHOT_IN_PROGRESS || mStatus == SNAPSHOT_COMPLETED) {
- menu.setGroupVisible(MenuHelper.IMAGE_SAVING_ITEM, true);
- mImageSavingItem = true;
- } else {
- menu.setGroupVisible(MenuHelper.IMAGE_MODE_ITEM, true);
- mImageSavingItem = false;
- }
- } else if (mMode == VIDEO_MODE) {
+
+ if (mStatus == SNAPSHOT_IN_PROGRESS || mStatus == SNAPSHOT_COMPLETED) {
+ menu.setGroupVisible(MenuHelper.IMAGE_SAVING_ITEM, true);
+ mImageSavingItem = true;
+ } else {
+ menu.setGroupVisible(MenuHelper.IMAGE_MODE_ITEM, true);
+ mImageSavingItem = false;
}
if (mCaptureObject != null)
@@ -1361,7 +1406,7 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
String action = getIntent().getAction();
return (Intent.ACTION_PICK.equals(action) || MediaStore.ACTION_IMAGE_CAPTURE.equals(action));
}
-
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -1372,39 +1417,106 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
Bitmap bitmap = mImageCapture.getLastBitmap();
mCaptureObject.setDone(true);
- // TODO scale the image down to something ridiculous until IPC gets straightened out
- float scale = .5F;
- Matrix m = new Matrix();
- m.setScale(scale, scale);
+ String cropValue = null;
+ Uri saveUri = null;
- bitmap = Bitmap.createBitmap(bitmap, 0, 0,
- bitmap.getWidth(),
- bitmap.getHeight(),
- m, true);
-
Bundle myExtras = getIntent().getExtras();
- String cropValue = myExtras != null ? myExtras.getString("crop") : null;
- if (cropValue != null) {
+ if (myExtras != null) {
+ saveUri = (Uri) myExtras.getParcelable("output");
+ cropValue = myExtras.getString("crop");
+ }
+
+
+ if (cropValue == null) {
+ /*
+ * First handle the no crop case -- just return the value. If the caller
+ * specifies a "save uri" then write the data to it's stream. Otherwise,
+ * pass back a scaled down version of the bitmap directly in the extras.
+ */
+ if (saveUri != null) {
+ OutputStream outputStream = null;
+ try {
+ outputStream = mContentResolver.openOutputStream(saveUri);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 75, outputStream);
+ outputStream.close();
+
+ setResult(RESULT_OK);
+ finish();
+ } catch (IOException ex) {
+ //
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException ex) {
+
+ }
+ }
+ }
+ } else {
+ float scale = .5F;
+ Matrix m = new Matrix();
+ m.setScale(scale, scale);
+
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0,
+ bitmap.getWidth(),
+ bitmap.getHeight(),
+ m, true);
+
+ setResult(RESULT_OK, new Intent("inline-data").putExtra("data", bitmap));
+ finish();
+ }
+ }
+ else {
+ /*
+ * Save the image to a temp file and invoke the cropper
+ */
+ Uri tempUri = null;
+ FileOutputStream tempStream = null;
+ try {
+ File path = getFileStreamPath(sTempCropFilename);
+ path.delete();
+ tempStream = openFileOutput(sTempCropFilename, 0);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 75, tempStream);
+ tempStream.close();
+ tempUri = Uri.fromFile(path);
+ } catch (FileNotFoundException ex) {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ return true;
+ } catch (IOException ex) {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ return true;
+ } finally {
+ if (tempStream != null) {
+ try {
+ tempStream.close();
+ } catch (IOException ex) {
+
+ }
+ }
+ }
+
Bundle newExtras = new Bundle();
if (cropValue.equals("circle"))
newExtras.putString("circleCrop", "true");
- newExtras.putParcelable("data", bitmap);
+ if (saveUri != null)
+ newExtras.putParcelable("output", saveUri);
+ else
+ newExtras.putBoolean("return-data", true);
Intent cropIntent = new Intent();
cropIntent.setClass(Camera.this, CropImage.class);
+ cropIntent.setData(tempUri);
cropIntent.putExtras(newExtras);
+
startActivityForResult(cropIntent, CROP_MSG);
- } else {
- Bundle extras = new Bundle();
- extras.putParcelable("data", bitmap);
- setResult(RESULT_OK, new Intent("inline-data")
- .putExtra("data", bitmap));
- finish();
}
return true;
}
});
-
+
menu.add(MenuHelper.IMAGE_SAVING_ITEM, MENU_SAVE_NEW_PHOTO, 0, R.string.camera_takenewphoto).setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
keep();
@@ -1422,9 +1534,10 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
MenuHelper.addImageMenuItems(
menu,
MenuHelper.INCLUDE_ALL & ~MenuHelper.INCLUDE_ROTATE_MENU,
+ true,
Camera.this,
mHandler,
-
+
// Handler for deletion
new Runnable() {
public void run() {
@@ -1461,20 +1574,12 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
});
gallery.setIcon(android.R.drawable.ic_menu_gallery);
-
- mGalleryItems.add(menu.add(MenuHelper.VIDEO_SAVING_ITEM, MENU_SAVE_GALLERY_VIDEO_PHOTO, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- keepVideo();
- gotoGallery();
- return true;
- }
- }));
- }
+ }
return true;
}
-
+
SelectedImageGetter mSelectedImageGetter =
- new SelectedImageGetter() {
+ new SelectedImageGetter() {
public ImageManager.IImage getCurrentImage() {
return getImageForURI(getCurrentImageUri());
}
@@ -1502,16 +1607,29 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
}
return mPicturesRemaining;
}
-
+
private void addBaseMenuItems(Menu menu) {
- MenuItem gallery = menu.add(MenuHelper.IMAGE_MODE_ITEM, MENU_GALLERY_PHOTOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- gotoGallery();
- return true;
- }
- });
- gallery.setIcon(android.R.drawable.ic_menu_gallery);
- mGalleryItems.add(gallery);
+ MenuHelper.addSwitchModeMenuItem(menu, this, true);
+ {
+ MenuItem gallery = menu.add(MenuHelper.IMAGE_MODE_ITEM, MENU_GALLERY_PHOTOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ gotoGallery();
+ return true;
+ }
+ });
+ gallery.setIcon(android.R.drawable.ic_menu_gallery);
+ mGalleryItems.add(gallery);
+ }
+ {
+ MenuItem gallery = menu.add(MenuHelper.VIDEO_MODE_ITEM, MENU_GALLERY_VIDEOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ gotoGallery();
+ return true;
+ }
+ });
+ gallery.setIcon(android.R.drawable.ic_menu_gallery);
+ mGalleryItems.add(gallery);
+ }
MenuItem item = menu.add(MenuHelper.GENERIC_ITEM, MENU_SETTINGS, 0, R.string.settings).setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -1523,5 +1641,20 @@ public class Camera extends Activity implements View.OnClickListener, SurfaceHol
});
item.setIcon(android.R.drawable.ic_menu_preferences);
}
+
+ private void showPostPictureAlert() {
+ mPostPictureAlert.setVisibility(View.VISIBLE);
+ mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, POST_PICTURE_ALERT_TIMEOUT);
+ }
+
+ private void hidePostPictureAlert() {
+ cancelRestartPreviewTimeout();
+ mPostPictureAlert.setVisibility(View.INVISIBLE);
+ }
+
+ private void cancelRestartPreviewTimeout() {
+ mHandler.removeMessages(RESTART_PREVIEW);
+ }
+
}
diff --git a/src/com/android/camera/CameraButtonIntentReceiver.java b/src/com/android/camera/CameraButtonIntentReceiver.java
index ccf5821..5e4d3c3 100644
--- a/src/com/android/camera/CameraButtonIntentReceiver.java
+++ b/src/com/android/camera/CameraButtonIntentReceiver.java
@@ -19,11 +19,9 @@ package com.android.camera;
import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
-import android.util.Config;
-import android.util.Log;
import android.view.KeyEvent;
-class CameraButtonIntentReceiver extends BroadcastReceiver {
+public class CameraButtonIntentReceiver extends BroadcastReceiver {
public CameraButtonIntentReceiver() {
}
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index fb77e34..0c0f31b 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -16,50 +16,29 @@
package com.android.camera;
-import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.Preference;
import android.preference.PreferenceActivity;
-import android.content.Context;
/**
* CameraSettings
*/
-class CameraSettings extends PreferenceActivity
+public class CameraSettings extends PreferenceActivity
{
public CameraSettings()
{
}
-
+
protected int resourceId() {
return R.xml.camera_preferences;
}
-
+
/** Called with the activity is first created. */
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
addPreferencesFromResource(resourceId());
-
- Preference p = findPreference("pref_camera_upload_albumname_key");
- if (p != null) {
- SharedPreferences sp = p.getSharedPreferences();
- p.setSummary(
- String.format(getResources().getString(R.string.pref_camera_upload_albumname_summary),
- p.getSharedPreferences().getString(p.getKey(), UploadService.sUploadAlbumName)));
- p.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference p, Object newObjValue) {
- String newValue = (String) newObjValue;
- if (newValue == null || newValue.length() == 0)
- return false;
- if (android.util.Config.LOGV)
- android.util.Log.v("camera", "onPreferenceChange ... " + newValue);
- p.setSummary(String.format(getResources().getString(R.string.pref_camera_upload_albumname_summary), newValue));
- return true;
- }
- });
- }
+
}
}
diff --git a/src/com/android/camera/ExifInterface.java b/src/com/android/camera/ExifInterface.java
index de2fd5c..2db021a 100644
--- a/src/com/android/camera/ExifInterface.java
+++ b/src/com/android/camera/ExifInterface.java
@@ -59,7 +59,7 @@ public class ExifInterface {
private HashMap<String, String> mCachedAttributes = null;
static {
- System.loadLibrary("exif");
+ System.loadLibrary("exif");
}
public ExifInterface(String fileName) {
diff --git a/src/com/android/camera/GalleryPicker.java b/src/com/android/camera/GalleryPicker.java
index 9f1664b..da946a0 100644
--- a/src/com/android/camera/GalleryPicker.java
+++ b/src/com/android/camera/GalleryPicker.java
@@ -29,6 +29,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -56,29 +57,31 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
public class GalleryPicker extends Activity {
static private final String TAG = "GalleryPicker";
-
+
GridView mGridView;
Drawable mFrameGalleryMask;
Drawable mCellOutline;
+ Drawable mVideoOverlay;
BroadcastReceiver mReceiver;
GalleryPickerAdapter mAdapter;
-
+
Dialog mMediaScanningDialog;
-
+
MenuItem mFlipItem;
SharedPreferences mPrefs;
-
+
boolean mPausing = false;
-
+
private static long LOW_STORAGE_THRESHOLD = 1024 * 1024 * 2;
-
+
public GalleryPicker() {
}
-
+
private void rebake(boolean unmounted, boolean scanning) {
if (mMediaScanningDialog != null) {
mMediaScanningDialog.cancel();
@@ -86,16 +89,16 @@ public class GalleryPicker extends Activity {
}
if (scanning) {
mMediaScanningDialog = ProgressDialog.show(
- this,
- null,
- getResources().getString(R.string.wait),
- true,
+ this,
+ null,
+ getResources().getString(R.string.wait),
+ true,
true);
}
mAdapter.notifyDataSetChanged();
mAdapter.init(!unmounted && !scanning);
}
-
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -103,12 +106,12 @@ public class GalleryPicker extends Activity {
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
setContentView(R.layout.gallerypicker);
-
- mGridView = (GridView) findViewById(R.id.albums);
+
+ mGridView = (GridView) findViewById(R.id.albums);
mGridView.setSelector(android.R.color.transparent);
mReceiver = new BroadcastReceiver() {
-
+
@Override
public void onReceive(Context context, Intent intent) {
if (Config.LOGV) Log.v(TAG, "onReceiveIntent " + intent.getAction());
@@ -136,7 +139,7 @@ public class GalleryPicker extends Activity {
}
}
};
-
+
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
launchFolderGallery(position);
@@ -144,34 +147,35 @@ public class GalleryPicker extends Activity {
});
mGridView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
public void onCreateContextMenu(ContextMenu menu, View v, final ContextMenu.ContextMenuInfo menuInfo) {
- menu.setHeaderTitle(
- mAdapter.baseTitleForPosition(((AdapterContextMenuInfo)menuInfo).position));
- menu.add(0, 207, 0, R.string.slide_show)
- .setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
- int position = info.position;
-
- Uri targetUri;
- synchronized (mAdapter.mFirstImageUris) {
- if (position >= mAdapter.mFirstImageUris.size()) {
- // the list of ids does not include the "all" list
- targetUri = mAdapter.firstImageUri(mAdapter.mIds.get(position-1));
- } else {
+ int position = ((AdapterContextMenuInfo)menuInfo).position;
+ menu.setHeaderTitle(mAdapter.baseTitleForPosition(position));
+ if ((mAdapter.getIncludeMediaTypes(position) & ImageManager.INCLUDE_IMAGES) != 0) {
+ menu.add(0, 207, 0, R.string.slide_show)
+ .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+ int position = info.position;
+
+ Uri targetUri;
+ synchronized (mAdapter.mItems) {
+ if (position < 0 || position >= mAdapter.mItems.size()) {
+ return true;
+ }
// the mFirstImageUris list includes the "all" uri
- targetUri = mAdapter.mFirstImageUris.get(position);
+ targetUri = mAdapter.mItems.get(position).mFirstImageUri;
}
+ if (targetUri != null && position > 0) {
+ targetUri = targetUri.buildUpon().appendQueryParameter("bucketId",
+ mAdapter.mItems.get(info.position).mId).build();
+ }
+ // Log.v(TAG, "URI to launch slideshow " + targetUri);
+ Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
+ intent.putExtra("slideshow", true);
+ startActivity(intent);
+ return true;
}
- if (targetUri != null && position > 0) {
- targetUri = targetUri.buildUpon().appendQueryParameter("bucketId", mAdapter.mIds.get(info.position-1)).build();
- }
-// Log.v(TAG, "URI to launch slideshow " + targetUri);
- Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
- intent.putExtra("slideshow", true);
- startActivity(intent);
- return true;
- }
- });
+ });
+ }
menu.add(0, 208, 0, R.string.view)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -183,56 +187,118 @@ public class GalleryPicker extends Activity {
}
});
}
-
+
private void launchFolderGallery(int position) {
- android.net.Uri uri = Images.Media.INTERNAL_CONTENT_URI;
- if (position > 0) {
- uri = uri.buildUpon().appendQueryParameter("bucketId", mAdapter.mIds.get(position-1)).build();
- }
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if (position > 0) {
- intent.putExtra("windowTitle", mAdapter.mNames.get(position-1));
- }
- startActivity(intent);
+ mAdapter.mItems.get(position).launch(this);
}
-
+
class ItemInfo {
Bitmap bitmap;
int count;
- int overlayId;
}
-
+
+ static class Item implements Comparable<Item>{
+ // The type is also used as the sort order
+ public final static int TYPE_ALL_IMAGES = 0;
+ public final static int TYPE_ALL_VIDEOS = 1;
+ public final static int TYPE_CAMERA_IMAGES = 2;
+ public final static int TYPE_CAMERA_VIDEOS = 3;
+ public final static int TYPE_NORMAL_FOLDERS = 4;
+
+ public int mType;
+ public String mId;
+ public String mName;
+ public Uri mFirstImageUri;
+ public ItemInfo mThumb;
+
+ public Item(int type, String id, String name) {
+ mType = type;
+ mId = id;
+ mName = name;
+ }
+
+ public boolean needsBucketId() {
+ return mType >= TYPE_CAMERA_IMAGES;
+ }
+
+ public void launch(Activity activity) {
+ android.net.Uri uri = Images.Media.INTERNAL_CONTENT_URI;
+ if (needsBucketId()) {
+ uri = uri.buildUpon().appendQueryParameter("bucketId",mId).build();
+ }
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.putExtra("windowTitle", mName);
+ intent.putExtra("mediaTypes", getIncludeMediaTypes());
+ activity.startActivity(intent);
+ }
+
+ public int getIncludeMediaTypes() {
+ return convertItemTypeToIncludedMediaType(mType);
+ }
+
+ public static int convertItemTypeToIncludedMediaType(int itemType) {
+ switch (itemType) {
+ case TYPE_ALL_IMAGES:
+ case TYPE_CAMERA_IMAGES:
+ return ImageManager.INCLUDE_IMAGES;
+ case TYPE_ALL_VIDEOS:
+ case TYPE_CAMERA_VIDEOS:
+ return ImageManager.INCLUDE_VIDEOS;
+ case TYPE_NORMAL_FOLDERS:
+ default:
+ return ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS;
+ }
+ }
+
+ public int getOverlay() {
+ switch (mType) {
+ case TYPE_ALL_IMAGES:
+ case TYPE_CAMERA_IMAGES:
+ return R.drawable.frame_overlay_gallery_camera;
+ case TYPE_ALL_VIDEOS:
+ case TYPE_CAMERA_VIDEOS:
+ return R.drawable.frame_overlay_gallery_video;
+ case TYPE_NORMAL_FOLDERS:
+ return R.drawable.frame_overlay_gallery_folder;
+ default:
+ return -1;
+ }
+ }
+
+ // sort based on the sort order, then the case-insensitive display name, then the id.
+ public int compareTo(Item other) {
+ int x = mType - other.mType;
+ if (x == 0) {
+ x = mName.compareToIgnoreCase(other.mName);
+ if (x == 0) {
+ x = mId.compareTo(other.mId);
+ }
+ }
+ return x;
+ }
+ }
+
class GalleryPickerAdapter extends BaseAdapter {
- ArrayList<String> mIds = new ArrayList<String>();
- ArrayList<String> mNames = new ArrayList<String>();
- ArrayList<Uri> mFirstImageUris = new ArrayList<Uri>();
-
- ArrayList<View> mAllViews = new ArrayList<View>();
- SparseArray<ItemInfo> mThumbs = new SparseArray<ItemInfo>();
-
+ ArrayList<Item> mItems = new ArrayList<Item>();
+
boolean mDone = false;
CameraThread mWorkerThread;
public void init(boolean assumeMounted) {
- mAllViews.clear();
- mThumbs.clear();
-
+ mItems.clear();
+
ImageManager.IImageList images;
if (assumeMounted) {
images = ImageManager.instance().allImages(
GalleryPicker.this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_IMAGES,
+ getContentResolver(),
+ ImageManager.DataLocation.ALL,
+ ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS,
ImageManager.SORT_DESCENDING);
} else {
images = ImageManager.instance().emptyImageList();
}
- mIds.clear();
- mNames.clear();
- mFirstImageUris.clear();
-
if (mWorkerThread != null) {
try {
mDone = true;
@@ -243,72 +309,56 @@ public class GalleryPicker extends Activity {
mWorkerThread = null;
}
}
-
+
String cameraItem = ImageManager.CAMERA_IMAGE_BUCKET_ID;
final HashMap<String, String> hashMap = images.getBucketIds();
String cameraBucketId = null;
- for (String key : hashMap.keySet()) {
+ for (Map.Entry<String, String> entry: hashMap.entrySet()) {
+ String key = entry.getKey();
if (key.equals(cameraItem)) {
cameraBucketId = key;
} else {
- mIds.add(key);
+ mItems.add(new Item(Item.TYPE_NORMAL_FOLDERS, key, entry.getValue()));
}
}
images.deactivate();
notifyDataSetInvalidated();
-
- // sort baesd on the display name. if two display names compare equal
- // then sort based on the id
- java.util.Collections.sort(mIds, new java.util.Comparator<String>() {
- public int compare(String first, String second) {
- int x = hashMap.get(first).compareTo(hashMap.get(second));
- if (x == 0)
- x = first.compareTo(second);
- return x;
- }
- });
- for (String s : mIds) {
- mNames.add(hashMap.get(s));
- }
+ // If just one
+ addBucketIfNotEmpty(Item.TYPE_ALL_IMAGES, null, R.string.all_images);
+ addBucketIfNotEmpty(Item.TYPE_ALL_VIDEOS, null, R.string.all_videos);
if (cameraBucketId != null) {
- mIds.add(0, cameraBucketId);
- mNames.add(0, "Camera");
+ addBucketIfNotEmpty(Item.TYPE_CAMERA_IMAGES, cameraBucketId,
+ R.string.gallery_camera_bucket_name);
+ addBucketIfNotEmpty(Item.TYPE_CAMERA_VIDEOS, cameraBucketId,
+ R.string.gallery_camera_videos_bucket_name);
}
- final boolean foundCameraBucket = cameraBucketId != null;
-
+
+ java.util.Collections.sort(mItems);
+
mDone = false;
mWorkerThread = new CameraThread(new Runnable() {
public void run() {
try {
// no images, nothing to do
- if (mIds.size() == 0)
+ if (mItems.size() == 0)
return;
-
- for (int i = 0; i < mIds.size() + 1 && !mDone; i++) {
- String id = i == 0 ? null : mIds.get(i-1);
- ImageManager.IImageList list = ImageManager.instance().allImages(
- GalleryPicker.this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_IMAGES,
- ImageManager.SORT_DESCENDING,
- id);
+
+ for (int i = 0; i < mItems.size() && !mDone; i++) {
+ final Item item = mItems.get(i);
+ ImageManager.IImageList list = createImageList(
+ item.getIncludeMediaTypes(), item.mId);
try {
if (mPausing) {
break;
}
if (list.getCount() > 0)
- mFirstImageUris.add(i, list.getImageAt(0).fullSizeImageUri());
+ item.mFirstImageUri = list.getImageAt(0).fullSizeImageUri();
- int overlay = -1;
- if (i == 1 && foundCameraBucket)
- overlay = R.drawable.frame_overlay_gallery_camera;
final Bitmap b = makeMiniThumbBitmap(142, 142, list);
final int pos = i;
final int count = list.getCount();
- final int overlayId = overlay;
final Thread currentThread = Thread.currentThread();
mHandler.post(new Runnable() {
public void run() {
@@ -318,19 +368,18 @@ public class GalleryPicker extends Activity {
}
return;
}
-
+
ItemInfo info = new ItemInfo();
info.bitmap = b;
info.count = count;
- info.overlayId = overlayId;
- mThumbs.put(pos, info);
-
+ item.mThumb = info;
+
final GridView grid = GalleryPicker.this.mGridView;
final int firstVisible = grid.getFirstVisiblePosition();
-
+
// Minor optimization -- only notify if the specified position is visible
if ((pos >= firstVisible) && (pos < firstVisible + grid.getChildCount())) {
- GalleryPickerAdapter.this.notifyDataSetChanged();
+ GalleryPickerAdapter.this.notifyDataSetChanged();
}
}
});
@@ -339,29 +388,22 @@ public class GalleryPicker extends Activity {
}
}
} catch (Exception ex) {
- Log.e(TAG, "got exception generating collage views " + ex.toString());
+ Log.e(TAG, "got exception generating collage views ", ex);
}
}
});
mWorkerThread.start();
mWorkerThread.toBackground();
}
-
- Uri firstImageUri(String id) {
- ImageManager.IImageList list = ImageManager.instance().allImages(
- GalleryPicker.this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_IMAGES,
- ImageManager.SORT_DESCENDING,
- id);
- Uri uri = list.getImageAt(0).fullSizeImageUri();
- list.deactivate();
- return uri;
+
+ private void addBucketIfNotEmpty(int itemType, String bucketId, int labelId) {
+ if (!isEmptyBucket(Item.convertItemTypeToIncludedMediaType(itemType), bucketId)) {
+ mItems.add(new Item(itemType, bucketId, getResources().getString(labelId)));
+ }
}
public int getCount() {
- return mIds.size() + 1; // add 1 for the everything bucket
+ return mItems.size();
}
public Object getItem(int position) {
@@ -371,41 +413,39 @@ public class GalleryPicker extends Activity {
public long getItemId(int position) {
return position;
}
-
+
private String baseTitleForPosition(int position) {
- if (position == 0) {
- return getResources().getString(R.string.all_images);
- } else {
- return mNames.get(position-1);
- }
+ return mItems.get(position).mName;
+ }
+
+ private int getIncludeMediaTypes(int position) {
+ return mItems.get(position).getIncludeMediaTypes();
}
public View getView(final int position, View convertView, ViewGroup parent) {
View v;
-
+
if (convertView == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.gallery_picker_item, null);
} else {
v = convertView;
}
-
+
TextView titleView = (TextView) v.findViewById(R.id.title);
-
GalleryPickerItem iv = (GalleryPickerItem) v.findViewById(R.id.thumbnail);
- ItemInfo info = mThumbs.get(position);
+ iv.setOverlay(mItems.get(position).getOverlay());
+ ItemInfo info = mItems.get(position).mThumb;
if (info != null) {
iv.setImageBitmap(info.bitmap);
- iv.setOverlay(info.overlayId);
String title = baseTitleForPosition(position) + " (" + info.count + ")";
titleView.setText(title);
} else {
iv.setImageResource(android.R.color.transparent);
- iv.setOverlay(-1);
titleView.setText(baseTitleForPosition(position));
}
-
+
return v;
}
};
@@ -415,13 +455,13 @@ public class GalleryPicker extends Activity {
super.onPause();
mPausing = true;
unregisterReceiver(mReceiver);
-
+
// free up some ram
mAdapter = null;
mGridView.setAdapter(null);
System.gc();
}
-
+
@Override
public void onResume() {
super.onResume();
@@ -433,7 +473,7 @@ public class GalleryPicker extends Activity {
boolean scanning = ImageManager.isMediaScannerScanning(this);
rebake(false, scanning);
-
+
// install an intent filter to receive SD card related events.
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
@@ -455,10 +495,10 @@ public class GalleryPicker extends Activity {
StatFs stat = new StatFs(storageDirectory);
long remaining = (long)stat.getAvailableBlocks() * (long)stat.getBlockSize();
if (remaining < LOW_STORAGE_THRESHOLD) {
-
+
mHandler.post(new Runnable() {
public void run() {
- Toast.makeText(GalleryPicker.this.getApplicationContext(),
+ Toast.makeText(GalleryPicker.this.getApplicationContext(),
R.string.not_enough_space, 5000).show();
}
});
@@ -467,8 +507,10 @@ public class GalleryPicker extends Activity {
}
});
t.start();
-
- if (!scanning && mAdapter.mIds.size() <= 1) {
+
+ // If we just have one folder, open it. (Probably never triggered because we always have
+ // At least two folders now.)
+ if (!scanning && mAdapter.mItems.size() <= 1) {
android.net.Uri uri = Images.Media.INTERNAL_CONTENT_URI;
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
@@ -476,26 +518,27 @@ public class GalleryPicker extends Activity {
return;
}
}
-
+
private void setBackgrounds(Resources r) {
mFrameGalleryMask = r.getDrawable(R.drawable.frame_gallery_preview_album_mask);
mCellOutline = r.getDrawable(android.R.drawable.gallery_thumb);
+ mVideoOverlay = r.getDrawable(R.drawable.ic_gallery_video_overlay);
}
-
+
Handler mHandler = new Handler();
-
+
private void placeImage(Bitmap image, Canvas c, Paint paint, int imageWidth, int widthPadding, int imageHeight, int heightPadding, int offsetX, int offsetY, int pos) {
int row = pos / 2;
int col = pos - (row * 2);
-
+
int xPos = (col * (imageWidth + widthPadding)) - offsetX;
int yPos = (row * (imageHeight + heightPadding)) - offsetY;
-
+
c.drawBitmap(image, xPos, yPos, paint);
}
-
+
private Bitmap makeMiniThumbBitmap(int width, int height, ImageManager.IImageList images) {
int count = images.getCount();
// We draw three different version of the folder image depending on the number of images in the folder.
@@ -507,30 +550,20 @@ public class GalleryPicker extends Activity {
int imageHeight = height;
int offsetWidth = 0;
int offsetHeight = 0;
- if (count < 4) {
- count = 1;
- // uncomment for 2 pictures per frame
-// if (count == 2 || count == 3) {
-// count = 2;
-// imageWidth = imageWidth * 2 / 3;
-// imageHeight = imageHeight * 2 / 3;
-// offsetWidth = imageWidth / 3 - padding;
-// offsetHeight = -imageHeight / 3 + padding * 2;
- } else if (count >= 4) {
- count = 4;
- imageWidth = (imageWidth - padding) / 2; // 2 here because we show two images
- imageHeight = (imageHeight - padding) / 2; // per row and column
- }
+
+ imageWidth = (imageWidth - padding) / 2; // 2 here because we show two images
+ imageHeight = (imageHeight - padding) / 2; // per row and column
+
final Paint p = new Paint();
final Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas c = new Canvas(b);
-
+
final Matrix m = new Matrix();
-
+
// draw the whole canvas as transparent
p.setColor(0x00000000);
c.drawPaint(p);
-
+
// draw the mask normally
p.setColor(0xFFFFFFFF);
mFrameGalleryMask.setBounds(0, 0, width, height);
@@ -542,17 +575,34 @@ public class GalleryPicker extends Activity {
pdpaint.setStyle(Paint.Style.FILL);
c.drawRect(0, 0, width, height, pdpaint);
-
- for (int i = 0; i < count; i++) {
+
+ for (int i = 0; i < 4; i++) {
if (mPausing) {
return null;
}
+
+ Bitmap temp = null;
ImageManager.IImage image = i < count ? images.getImageAt(i) : null;
- if (image == null) {
- break;
+
+ if (image != null) {
+ temp = image.miniThumbBitmap();
}
- Bitmap temp = image.miniThumbBitmap();
+
if (temp != null) {
+ if (ImageManager.isVideo(image)) {
+ Bitmap newMap = temp.copy(temp.getConfig(), true);
+ Canvas overlayCanvas = new Canvas(newMap);
+ int overlayWidth = mVideoOverlay.getIntrinsicWidth();
+ int overlayHeight = mVideoOverlay.getIntrinsicHeight();
+ int left = (newMap.getWidth() - overlayWidth) / 2;
+ int top = (newMap.getHeight() - overlayHeight) / 2;
+ Rect newBounds = new Rect(left, top, left + overlayWidth, top + overlayHeight);
+ mVideoOverlay.setBounds(newBounds);
+ mVideoOverlay.draw(overlayCanvas);
+ temp.recycle();
+ temp = newMap;
+ }
+
Bitmap temp2 = ImageLoader.transform(m, temp, imageWidth, imageHeight, true);
if (temp2 != temp)
temp.recycle();
@@ -567,22 +617,24 @@ public class GalleryPicker extends Activity {
mCellOutline.draw(tempCanvas);
placeImage(thumb, c, pdpaint, imageWidth, padding, imageHeight, padding, offsetWidth, offsetHeight, i);
-
+
thumb.recycle();
-
+
if (temp != null)
temp.recycle();
}
+
return b;
}
-
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
-
+
+ MenuHelper.addCaptureMenuItems(menu, this);
mFlipItem = MenuHelper.addFlipOrientation(menu, this, mPrefs);
- menu.add(0, 0, 0, R.string.camerasettings)
+ menu.add(0, 0, 5, R.string.camerasettings)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Intent preferences = new Intent();
@@ -597,11 +649,32 @@ public class GalleryPicker extends Activity {
return true;
}
- @Override
+ @Override
public boolean onPrepareOptionsMenu(android.view.Menu menu) {
int keyboard = getResources().getConfiguration().keyboardHidden;
mFlipItem.setEnabled(keyboard == android.content.res.Configuration.KEYBOARDHIDDEN_YES);
return true;
}
+
+ private boolean isEmptyBucket(int mediaTypes, String bucketId) {
+ // TODO: Find a more efficient way of calculating this
+ ImageManager.IImageList list = createImageList(mediaTypes, bucketId);
+ try {
+ return list.isEmpty();
+ }
+ finally {
+ list.deactivate();
+ }
+ }
+
+ private ImageManager.IImageList createImageList(int mediaTypes, String bucketId) {
+ return ImageManager.instance().allImages(
+ this,
+ getContentResolver(),
+ ImageManager.DataLocation.ALL,
+ mediaTypes,
+ ImageManager.SORT_DESCENDING,
+ bucketId);
+ }
}
diff --git a/src/com/android/camera/GallerySettings.java b/src/com/android/camera/GallerySettings.java
index 3af6867..8cbeba2 100644
--- a/src/com/android/camera/GallerySettings.java
+++ b/src/com/android/camera/GallerySettings.java
@@ -25,7 +25,7 @@ import android.content.Context;
/**
* GallerySettings
*/
-class GallerySettings extends CameraSettings
+public class GallerySettings extends CameraSettings
{
public GallerySettings()
{
diff --git a/src/com/android/camera/HighlightView.java b/src/com/android/camera/HighlightView.java
index 594bab6..408beab 100644
--- a/src/com/android/camera/HighlightView.java
+++ b/src/com/android/camera/HighlightView.java
@@ -376,35 +376,35 @@ public class HighlightView
float heightUnits = widthUnits;
switch (keyCode)
- {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (mMode == ModifyMode.Move)
- moveBy(-widthUnits, 0);
- else if (mMode == ModifyMode.Grow)
- growBy(-widthUnits, 0);
- break;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (mMode == ModifyMode.Move)
- moveBy(widthUnits, 0);
+ {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (mMode == ModifyMode.Move)
+ moveBy(-widthUnits, 0);
else if (mMode == ModifyMode.Grow)
- growBy(widthUnits, 0);
- break;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- if (mMode == ModifyMode.Move)
- moveBy(0, -heightUnits);
+ growBy(-widthUnits, 0);
+ break;
+
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (mMode == ModifyMode.Move)
+ moveBy(widthUnits, 0);
+ else if (mMode == ModifyMode.Grow)
+ growBy(widthUnits, 0);
+ break;
+
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (mMode == ModifyMode.Move)
+ moveBy(0, -heightUnits);
else if (mMode == ModifyMode.Grow)
- growBy(0, -heightUnits);
- break;
+ growBy(0, -heightUnits);
+ break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (mMode == ModifyMode.Move)
- moveBy(0, heightUnits);
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (mMode == ModifyMode.Move)
+ moveBy(0, heightUnits);
else if (mMode == ModifyMode.Grow)
- growBy(0, heightUnits);
- break;
- }
+ growBy(0, heightUnits);
+ break;
+ }
}
enum ModifyMode { None, Move,Grow };
diff --git a/src/com/android/camera/ImageGallery2.java b/src/com/android/camera/ImageGallery2.java
index c8abdae..44d297b 100644
--- a/src/com/android/camera/ImageGallery2.java
+++ b/src/com/android/camera/ImageGallery2.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -51,11 +52,14 @@ import android.view.Window;
import android.widget.TextView;
import android.widget.Toast;
import android.preference.PreferenceManager;
+import android.provider.MediaStore;
import android.widget.Scroller;
import java.util.Calendar;
import java.util.GregorianCalendar;
+import com.android.camera.ImageManager.IImage;
+
public class ImageGallery2 extends Activity {
private static final String TAG = "ImageGallery2";
private ImageManager.IImageList mAllImages;
@@ -66,10 +70,11 @@ public class ImageGallery2 extends Activity {
public final static int VIEW_MSG = 3;
private static final String INSTANCE_STATE_TAG = "scrollY";
-
+
private Dialog mMediaScanningDialog;
-
+
private MenuItem mFlipItem;
+ private MenuItem mSlideShowItem;
private SharedPreferences mPrefs;
public ImageGallery2() {
@@ -115,11 +120,15 @@ public class ImageGallery2 extends Activity {
}
});
- menu.setHeaderTitle(R.string.context_menu_header);
- if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
+ boolean isImage = ImageManager.isImage(mSelectedImageGetter.getCurrentImage());
+
+ menu.setHeaderTitle(isImage ? R.string.context_menu_header
+ : R.string.video_context_menu_header);
+ if ((mInclusion & (ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS)) != 0) {
MenuHelper.MenuItemsResult r = MenuHelper.addImageMenuItems(
menu,
MenuHelper.INCLUDE_ALL,
+ isImage,
ImageGallery2.this,
mHandler,
mDeletePhotoRunnable,
@@ -136,37 +145,15 @@ public class ImageGallery2 extends Activity {
if (r != null)
r.gettingReadyToOpen(menu, mSelectedImageGetter.getCurrentImage());
- addSlideShowMenu(menu, 1000);
- }
-
- if ((mInclusion & ImageManager.INCLUDE_VIDEOS) != 0) {
- MenuHelper.MenuItemsResult r = MenuHelper.addVideoMenuItems(
- menu,
- MenuHelper.INCLUDE_ALL,
- ImageGallery2.this,
- mHandler,
- mSelectedImageGetter,
- new Runnable() {
- public void run() {
- ImageManager.IImage image = mSelectedImageGetter.getCurrentImage();
- if (image != null) {
- mGvs.clearCache();
- mAllImages.removeImage(mSelectedImageGetter.getCurrentImage());
- mGvs.invalidate();
- mGvs.start();
- mNoImagesView.setVisibility(mAllImages.getCount() > 0 ? View.GONE : View.VISIBLE);
- }
- }
- },
- null, null);
- if (r != null)
- r.gettingReadyToOpen(menu, mSelectedImageGetter.getCurrentImage());
+ if (isImage) {
+ addSlideShowMenu(menu, 1000);
+ }
}
}
});
}
}
-
+
private MenuItem addSlideShowMenu(Menu menu, int position) {
return menu.add(0, 207, position, R.string.slide_show)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@@ -194,7 +181,7 @@ public class ImageGallery2 extends Activity {
})
.setIcon(android.R.drawable.ic_menu_slideshow);
}
-
+
private Runnable mDeletePhotoRunnable = new Runnable() {
public void run() {
mGvs.clearCache();
@@ -204,7 +191,7 @@ public class ImageGallery2 extends Activity {
mNoImagesView.setVisibility(mAllImages.getCount() > 0 ? View.GONE : View.VISIBLE);
}
};
-
+
private SelectedImageGetter mSelectedImageGetter = new SelectedImageGetter() {
public Uri getCurrentImageUri() {
ImageManager.IImage image = getCurrentImage();
@@ -227,20 +214,20 @@ public class ImageGallery2 extends Activity {
super.onConfigurationChanged(newConfig);
mTargetScroll = mGvs.getScrollY();
}
-
+
private Runnable mLongPressCallback = new Runnable() {
public void run() {
mGvs.showContextMenu();
}
};
-
+
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// The keyUp doesn't get called when the longpress menu comes up. We only get here when the user
// lets go of the center key before the longpress menu comes up.
mHandler.removeCallbacks(mLongPressCallback);
-
+
// open the photo
if (mSelectedImageGetter.getCurrentImage() != null) {
mGvs.onSelect(mGvs.mCurrentSelection);
@@ -282,7 +269,8 @@ public class ImageGallery2 extends Activity {
mHandler.postDelayed(mLongPressCallback, ViewConfiguration.getLongPressTimeout());
break;
case KeyEvent.KEYCODE_DEL:
- MenuHelper.deletePhoto(this, mDeletePhotoRunnable);
+ MenuHelper.deleteImage(this, mDeletePhotoRunnable,
+ mSelectedImageGetter.getCurrentImage());
break;
default:
handled = false;
@@ -402,10 +390,10 @@ public class ImageGallery2 extends Activity {
}
if (scanning) {
mMediaScanningDialog = ProgressDialog.show(
- this,
- null,
- getResources().getString(R.string.wait),
- true,
+ this,
+ null,
+ getResources().getString(R.string.wait),
+ true,
true);
mAllImages = ImageManager.instance().emptyImageList();
} else {
@@ -418,7 +406,7 @@ public class ImageGallery2 extends Activity {
checkThumbnails();
}
}
-
+
@Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
@@ -431,7 +419,7 @@ public class ImageGallery2 extends Activity {
super.onRestoreInstanceState(state);
mTargetScroll = state.getInt(INSTANCE_STATE_TAG, 0);
}
-
+
int mTargetScroll;
@Override
@@ -474,7 +462,7 @@ public class ImageGallery2 extends Activity {
rebake(true, false);
} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
Toast.makeText(ImageGallery2.this, getResources().getString(R.string.wait), 5000);
- rebake(false, true);
+ rebake(false, true);
} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
if (Config.LOGV)
Log.v(TAG, "rebake because of ACTION_MEDIA_SCANNER_FINISHED");
@@ -489,10 +477,10 @@ public class ImageGallery2 extends Activity {
registerReceiver(mReceiver, intentFilter);
MenuHelper.requestOrientation(this, mPrefs);
-
+
rebake(false, ImageManager.isMediaScannerScanning(this));
}
-
+
private void stopCheckingThumbnails() {
mStopThumbnailChecking = true;
if (mThumbnailCheckThread != null) {
@@ -523,7 +511,7 @@ public class ImageGallery2 extends Activity {
if (mStopThumbnailChecking) {
return false;
}
-
+
if (!mLayoutComplete) {
return true;
}
@@ -563,11 +551,11 @@ public class ImageGallery2 extends Activity {
Log.v(TAG, "check thumbnails thread finishing; took " + (t2-t1));
}
});
-
+
mThumbnailCheckThread.setName("check_thumbnails");
mThumbnailCheckThread.start();
mThumbnailCheckThread.toBackground();
-
+
ImageManager.IImageList list = allImages(true);
mNoImagesView.setVisibility(list.getCount() > 0 ? View.GONE : View.VISIBLE);
}
@@ -575,21 +563,12 @@ public class ImageGallery2 extends Activity {
@Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
MenuItem item;
- if (false) {
- if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
- item = menu.add(0, 0, 0, R.string.upload_all);
- item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- UploadAction.uploadImage(ImageGallery2.this, null);
- return true;
- }
- });
- item.setIcon(android.R.drawable.ic_menu_upload);
- }
- }
- addSlideShowMenu(menu, 0);
+ MenuHelper.addCaptureMenuItems(menu, this);
+ if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
+ mSlideShowItem = addSlideShowMenu(menu, 5);
- mFlipItem = MenuHelper.addFlipOrientation(menu, this, mPrefs);
+ mFlipItem = MenuHelper.addFlipOrientation(menu, this, mPrefs);
+ }
item = menu.add(0, 0, 1000, R.string.camerasettings);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@@ -605,15 +584,32 @@ public class ImageGallery2 extends Activity {
return true;
}
-
- @Override
+
+ @Override
public boolean onPrepareOptionsMenu(android.view.Menu menu) {
- int keyboard = getResources().getConfiguration().keyboardHidden;
- mFlipItem.setEnabled(keyboard == android.content.res.Configuration.KEYBOARDHIDDEN_YES);
+ if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
+ boolean imageSelected = isImageSelected();
+ boolean videoSelected = isVideoSelected();
+ int keyboard = getResources().getConfiguration().keyboardHidden;
+ mFlipItem.setEnabled(imageSelected
+ && (keyboard == android.content.res.Configuration.KEYBOARDHIDDEN_YES));
+ // TODO: Only enable slide show if there is at least one image in the folder.
+ mSlideShowItem.setEnabled(!videoSelected);
+ }
return true;
}
+ private boolean isImageSelected() {
+ IImage image = mSelectedImageGetter.getCurrentImage();
+ return (image != null) && ImageManager.isImage(image);
+ }
+
+ private boolean isVideoSelected() {
+ IImage image = mSelectedImageGetter.getCurrentImage();
+ return (image != null) && ImageManager.isVideo(image);
+ }
+
private synchronized ImageManager.IImageList allImages(boolean assumeMounted) {
if (mAllImages == null) {
mNoImagesView = findViewById(R.id.no_images);
@@ -636,6 +632,11 @@ public class ImageGallery2 extends Activity {
leftText.setText(R.string.photos_gallery_title);
}
if (type.equals("vnd.android.cursor.dir/video") || type.equals("video/*")) {
+ mInclusion = ImageManager.INCLUDE_VIDEOS;
+ if (isPickIntent())
+ leftText.setText(R.string.pick_videos_gallery_title);
+ else
+ leftText.setText(R.string.videos_gallery_title);
}
}
Bundle extras = intent.getExtras();
@@ -644,6 +645,11 @@ public class ImageGallery2 extends Activity {
leftText.setText(title);
}
+ if (extras != null) {
+ mInclusion = (ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS)
+ & extras.getInt("mediaTypes", mInclusion);
+ }
+
if (extras != null && extras.getBoolean("pick-drm")) {
Log.d(TAG, "pick-drm is true");
mInclusion = ImageManager.INCLUDE_DRM_IMAGES;
@@ -651,7 +657,8 @@ public class ImageGallery2 extends Activity {
}
}
if (Config.LOGV)
- Log.v(TAG, "computing images... mSortAscending is " + mSortAscending + "; assumeMounted is " + assumeMounted);
+ Log.v(TAG, "computing images... mSortAscending is " + mSortAscending
+ + "; assumeMounted is " + assumeMounted);
Uri uri = getIntent().getData();
if (!assumeMounted) {
mAllImages = ImageManager.instance().emptyImageList();
@@ -758,7 +765,7 @@ public class ImageGallery2 extends Activity {
velocityY = maxVelocity;
else if (velocityY < -maxVelocity)
velocityY = -maxVelocity;
-
+
select(-1);
if (mFling) {
mScroller = new Scroller(getContext());
@@ -891,8 +898,8 @@ public class ImageGallery2 extends Activity {
if (mGallery.isFinishing() || mGallery.mPausing) {
return;
- }
-
+ }
+
clearCache();
mCurrentSpec = mCellSizeChoices[mSizeChoice];
@@ -905,7 +912,7 @@ public class ImageGallery2 extends Activity {
mCurrentSpec.mLeftEdgePadding = ((right - left) - ((mCurrentSpec.mColumns - 1) * mCurrentSpec.mCellSpacing) - (mCurrentSpec.mColumns * mCurrentSpec.mCellWidth)) / 2;
mCurrentSpec.mRightEdgePadding = mCurrentSpec.mLeftEdgePadding;
-
+
int rows = (mGallery.mAllImages.getCount() + mCurrentSpec.mColumns - 1) / mCurrentSpec.mColumns;
mMaxScrollY = mCurrentSpec.mCellSpacing + (rows * (mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight)) - (bottom - top) + mMaxOvershoot;
mMinScrollY = 0 - mMaxOvershoot;
@@ -950,9 +957,10 @@ public class ImageGallery2 extends Activity {
private int mWorkCounter = 0;
private boolean mDone = false;
-
+
private Thread mWorkerThread;
- private Bitmap mErrorBitmap;
+ private Bitmap mMissingImageThumbnailBitmap;
+ private Bitmap mMissingVideoThumbnailBitmap;
public void dump() {
synchronized (ImageBlockManager.this) {
@@ -1027,12 +1035,20 @@ public class ImageGallery2 extends Activity {
}
// Create this bitmap lazily, and only once for all the ImageBlocks to use
- public Bitmap getErrorBitmap() {
- if (mErrorBitmap == null) {
- mErrorBitmap = BitmapFactory.decodeResource(GridViewSpecial.this.getResources(),
- android.R.drawable.ic_menu_report_image);
+ public Bitmap getErrorBitmap(ImageManager.IImage image) {
+ if (ImageManager.isImage(image)) {
+ if (mMissingImageThumbnailBitmap == null) {
+ mMissingImageThumbnailBitmap = BitmapFactory.decodeResource(GridViewSpecial.this.getResources(),
+ R.drawable.ic_missing_thumbnail_picture);
+ }
+ return mMissingImageThumbnailBitmap;
+ } else {
+ if (mMissingVideoThumbnailBitmap == null) {
+ mMissingVideoThumbnailBitmap = BitmapFactory.decodeResource(GridViewSpecial.this.getResources(),
+ R.drawable.ic_missing_thumbnail_video);
+ }
+ return mMissingVideoThumbnailBitmap;
}
- return mErrorBitmap;
}
private ImageBlock getBlockForPos(int pos) {
@@ -1299,6 +1315,7 @@ public class ImageGallery2 extends Activity {
int mRequestedMask; // columns which have been requested to the loader
int mCompletedMask; // columns which have been completed from the loader
boolean mIsVisible;
+ Drawable mVideoOverlay;
public void dump(StringBuilder line1, StringBuilder line2) {
synchronized (ImageBlock.this) {
@@ -1315,7 +1332,7 @@ public class ImageGallery2 extends Activity {
mBlockNumber = -1;
mCellOutline = GridViewSpecial.this.getResources().getDrawable(android.R.drawable.gallery_thumb);
}
-
+
private void recycleBitmaps() {
synchronized (ImageBlock.this) {
mBitmap.recycle();
@@ -1434,13 +1451,13 @@ public class ImageGallery2 extends Activity {
// change in the future.
int w = mCurrentSpec.mCellWidth;
int h = mCurrentSpec.mCellHeight;
-
+
int bw = b.getWidth();
int bh = b.getHeight();
int deltaW = bw - w;
int deltaH = bh - h;
-
+
if (deltaW < 10 && deltaH < 10) {
int halfDeltaW = deltaW / 2;
int halfDeltaH = deltaH / 2;
@@ -1460,7 +1477,7 @@ public class ImageGallery2 extends Activity {
}
} else {
// If the thumbnail cannot be drawn, put up an error icon instead
- Bitmap error = mImageBlockManager.getErrorBitmap();
+ Bitmap error = mImageBlockManager.getErrorBitmap(image);
int width = error.getWidth();
int height = error.getHeight();
Rect source = new Rect(0, 0, width, height);
@@ -1469,6 +1486,19 @@ public class ImageGallery2 extends Activity {
Rect dest = new Rect(left, top, left + width, top + height);
mCanvas.drawBitmap(error, source, dest, mPaint);
}
+ if (ImageManager.isVideo(image)) {
+ if (mVideoOverlay == null) {
+ mVideoOverlay = getResources().getDrawable(
+ R.drawable.ic_gallery_video_overlay);
+ }
+ int width = mVideoOverlay.getIntrinsicWidth();
+ int height = mVideoOverlay.getIntrinsicHeight();
+ int left = (mCurrentSpec.mCellWidth - width) / 2 + xPos;
+ int top = (mCurrentSpec.mCellHeight - height) / 2 + yPos;
+ Rect newBounds = new Rect(left, top, left + width, top + height);
+ mVideoOverlay.setBounds(newBounds);
+ mVideoOverlay.draw(mCanvas);
+ }
paintSel(base + baseOffset, xPos, yPos);
}
@@ -1524,7 +1554,7 @@ public class ImageGallery2 extends Activity {
// Log.v(TAG, "wanted block " + mBlockNumber + " but got " + startBlock);
return;
}
-
+
if (mBitmap == null) {
return;
}
@@ -1644,11 +1674,11 @@ public class ImageGallery2 extends Activity {
}
Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
- // this should be unnecessary but if you remove this line then executing
- // the subsequent startActivity causes the user to have to choose among
- // ViewImage and a number of bogus entries (like attaching the image to
- // a contact).
- intent.setClass(mContext, ViewImage.class);
+ if (img instanceof ImageManager.VideoObject) {
+ intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ }
+
try {
mContext.startActivity(intent);
} catch (Exception ex) {
diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java
index 8d3f90a..1fe93b5 100755
--- a/src/com/android/camera/ImageManager.java
+++ b/src/com/android/camera/ImageManager.java
@@ -25,8 +25,11 @@ import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
import android.graphics.Matrix;
import android.location.Location;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
@@ -36,8 +39,10 @@ import android.provider.DrmStore;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.Images.Thumbnails;
+import android.provider.MediaStore.Video.VideoColumns;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.MediaColumns;
+import android.provider.MediaStore.Video;
import android.util.Config;
import android.util.Log;
@@ -69,7 +74,7 @@ public class ImageManager {
private static final String TAG = "ImageManager";
private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
-
+
static public void debug_where(String tag, String msg) {
try {
throw new Exception();
@@ -98,11 +103,11 @@ public class ImageManager {
private static int computeSampleSize(BitmapFactory.Options options, int target) {
int w = options.outWidth;
int h = options.outHeight;
-
+
int candidateW = w / target;
int candidateH = h / target;
int candidate = Math.max(candidateW, candidateH);
-
+
if (candidate == 0)
return 1;
@@ -110,7 +115,7 @@ public class ImageManager {
if ((w > target) && (w / candidate) < target)
candidate -= 1;
}
-
+
if (candidate > 1) {
if ((h > target) && (h / candidate) < target)
candidate -= 1;
@@ -121,7 +126,7 @@ public class ImageManager {
return candidate;
}
- /*
+ /*
* All implementors of ICancelable should inherit from BaseCancelable
* since it provides some convenience methods such as acknowledgeCancel
* and checkCancel.
@@ -129,10 +134,10 @@ public class ImageManager {
public abstract class BaseCancelable implements ICancelable {
boolean mCancel = false;
boolean mFinished = false;
-
+
/*
* Subclasses should call acknowledgeCancel when they're finished with
- * their operation.
+ * their operation.
*/
protected void acknowledgeCancel() {
synchronized (this) {
@@ -161,7 +166,7 @@ public class ImageManager {
} catch (InterruptedException ex) {
// now what??? TODO
}
-
+
return retVal;
}
}
@@ -205,13 +210,13 @@ public class ImageManager {
protected BaseImage(long id, long miniThumbId, ContentResolver cr, BaseImageList container, int cursorRow) {
mContentResolver = cr;
mId = id;
- mMiniThumbMagic = miniThumbId;
+ mMiniThumbMagic = miniThumbId;
mContainer = container;
mCursorRow = cursorRow;
}
-
+
abstract Bitmap.CompressFormat compressionType();
-
+
public void commitChanges() {
Cursor c = getCursor();
synchronized (c) {
@@ -221,7 +226,7 @@ public class ImageManager {
}
}
}
-
+
/**
* Take a given bitmap and compress it to a file as described
* by the Uri parameter.
@@ -248,7 +253,7 @@ public class ImageManager {
}
return false;
}
-
+
public boolean get() {
try {
long t1 = System.currentTimeMillis();
@@ -297,7 +302,7 @@ public class ImageManager {
return false;
if (!(other instanceof Image))
return false;
-
+
return fullSizeImageUri().equals(((Image)other).fullSizeImageUri());
}
@@ -327,11 +332,11 @@ public class ImageManager {
ParcelFileDescriptor mPFD;
BitmapFactory.Options mOptions = new BitmapFactory.Options();
long mCancelInitiationTime;
-
+
public LoadBitmapCancelable(ParcelFileDescriptor pfdInput) {
mPFD = pfdInput;
}
-
+
public boolean doCancelWork() {
if (VERBOSE)
Log.v(TAG, "requesting bitmap load cancel");
@@ -339,7 +344,7 @@ public class ImageManager {
mOptions.requestCancelDecode();
return true;
}
-
+
public Bitmap get() {
try {
Bitmap b = makeBitmap(targetWidthHeight, fullSizeImageUri(), mPFD, mOptions);
@@ -386,7 +391,7 @@ public class ImageManager {
return null;
}
}
-
+
public long fullSizeImageId() {
return mId;
}
@@ -394,11 +399,11 @@ public class ImageManager {
public Uri fullSizeImageUri() {
return mContainer.contentUri(mId);
}
-
+
public IImageList getContainer() {
return mContainer;
}
-
+
Cursor getCursor() {
return mContainer.getCursor();
}
@@ -411,7 +416,7 @@ public class ImageManager {
return c.getLong(mContainer.indexDateTaken());
}
}
-
+
protected int getDegreesRotated() {
return 0;
}
@@ -597,7 +602,7 @@ public class ImageManager {
}
}
}
-
+
public int getHeight() {
ParcelFileDescriptor input = null;
try {
@@ -660,7 +665,7 @@ public class ImageManager {
protected Bitmap makeBitmap(int targetWidthHeight, Uri uri, ParcelFileDescriptor pfdInput, BitmapFactory.Options options) {
return mContainer.makeBitmap(targetWidthHeight, uri, pfdInput, options);
}
-
+
/* (non-Javadoc)
* @see com.android.camera.IImage#thumb1()
*/
@@ -702,7 +707,7 @@ public class ImageManager {
return null;
}
}
-
+
public void onRemove() {
mContainer.mCache.remove(mId);
}
@@ -736,7 +741,7 @@ public class ImageManager {
}
}
}
-
+
/* (non-Javadoc)
* @see com.android.camera.IImage#setName()
*/
@@ -748,7 +753,7 @@ public class ImageManager {
}
}
}
-
+
public void setPicasaId(String id) {
Cursor c = null;
try {
@@ -772,7 +777,7 @@ public class ImageManager {
c.close();
}
}
-
+
/* (non-Javadoc)
* @see com.android.camera.IImage#thumbUri()
*/
@@ -782,7 +787,7 @@ public class ImageManager {
uri = uri.buildUpon().appendQueryParameter("thumb", "1").build();
return uri;
}
-
+
@Override
public String toString() {
return fullSizeImageUri().toString();
@@ -810,16 +815,17 @@ public class ImageManager {
mSort = sort;
mUri = uri;
mBaseUri = uri;
+ mBucketId = bucketId;
mContentResolver = cr;
}
-
+
String randomAccessFilePath(int version) {
String directoryName = Environment.getExternalStorageDirectory().toString() + "/dcim/.thumbnails";
String path = directoryName + "/.thumbdata" + version + "-" + mUri.hashCode();
return path;
}
-
+
RandomAccessFile miniThumbDataFile() {
if (mMiniThumbData == null) {
String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION);
@@ -834,7 +840,7 @@ public class ImageManager {
try {
mMiniThumbData = new RandomAccessFile(f, "rw");
} catch (IOException ex) {
-
+
}
}
return mMiniThumbData;
@@ -853,14 +859,14 @@ public class ImageManager {
return thumb;
}
OutputStream thumbOut = mContentResolver.openOutputStream(uri);
- thumb.compress(Bitmap.CompressFormat.JPEG, 60, thumbOut);
+ thumb.compress(Bitmap.CompressFormat.JPEG, 60, thumbOut);
thumbOut.close();
return thumb;
}
catch (Exception ex) {
Log.d(TAG, "unable to store thumbnail: " + ex);
return thumb;
- }
+ }
}
/**
@@ -924,11 +930,11 @@ public class ImageManager {
}
return uri;
}
-
+
java.util.Random mRandom = new java.util.Random(System.currentTimeMillis());
protected SomewhatFairLock mLock = new SomewhatFairLock();
-
+
class SomewhatFairLock {
private Object mSync = new Object();
private boolean mLocked = false;
@@ -954,7 +960,7 @@ public class ImageManager {
mLocked = true;
}
}
-
+
void unlock() {
// if (VERBOSE) Log.v(TAG, "unlocking... thread " + Thread.currentThread().getId());
synchronized (mSync) {
@@ -991,7 +997,7 @@ public class ImageManager {
// which will produce much better scaling quality
// and is significantly faster.
options.inSampleSize = computeSampleSize(options, THUMBNAIL_TARGET_SIZE);
-
+
if (VERBOSE) {
Log.v(TAG, "in createThumbnailFromExif using inSampleSize of " + options.inSampleSize);
}
@@ -1019,7 +1025,20 @@ public class ImageManager {
}
return bitmap;
}
-
+
+ private Bitmap createVideoThumbnail(String filePath) {
+ Bitmap bitmap = null;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
+ retriever.setDataSource(filePath);
+ bitmap = retriever.captureFrame();
+ } finally {
+ retriever.release();
+ }
+ return bitmap;
+ }
+
// returns id
public long checkThumbnail(BaseImage existingImage, Cursor c, int i) {
long magic, fileMagic = 0, id;
@@ -1042,7 +1061,7 @@ public class ImageManager {
}
if (magic != 0) {
- // check the mini thumb file for the right data. Right is defined as
+ // check the mini thumb file for the right data. Right is defined as
// having the right magic number at the offset reserved for this "id".
RandomAccessFile r = miniThumbDataFile();
if (r != null) {
@@ -1072,18 +1091,23 @@ public class ImageManager {
// If we can't retrieve the thumbnail, first check if there is one embedded in the
// EXIF data. If not, or it's not big enough, decompress the full size image.
Bitmap bitmap = null;
-
+
String filePath = null;
synchronized (c) {
if (c.moveToPosition(i)) {
filePath = c.getString(indexData());
}
}
-
if (filePath != null) {
bitmap = createThumbnailFromEXIF(filePath, id);
if (bitmap == null) {
- bitmap = createThumbnailFromUri(c, id);
+ String mimeType = c.getString(indexMimeType());
+ boolean isVideo = isVideoMimeType(mimeType);
+ if (isVideo) {
+ bitmap = createVideoThumbnail(filePath);
+ } else {
+ bitmap = createThumbnailFromUri(c, id);
+ }
}
synchronized (c) {
int degrees = 0;
@@ -1141,7 +1165,7 @@ public class ImageManager {
Log.v(TAG, ">>>>>>>>>>> need to check " + c.getCount() + " rows");
c.close();
-
+
if (!ImageManager.hasStorage()) {
if (VERBOSE)
Log.v(TAG, "bailing from the image checker thread -- no storage");
@@ -1158,7 +1182,7 @@ public class ImageManager {
return;
}
}
-
+
c = getCursor();
try {
if (VERBOSE) Log.v(TAG, "checkThumbnails found " + c.getCount());
@@ -1188,7 +1212,7 @@ public class ImageManager {
}
}
}
-
+
public void commitChanges() {
synchronized (mCursor) {
mCursor.commitUpdates();
@@ -1208,16 +1232,21 @@ public class ImageManager {
return ContentUris.withAppendedId(mBaseUri, id);
}
}
-
+
public void deactivate() {
mCursorDeactivated = true;
- mCursor.deactivate();
+ try {
+ mCursor.deactivate();
+ } catch (IllegalStateException e) {
+ // IllegalStateException may be thrown if the cursor is stale.
+ Log.e(TAG, "Caught exception while deactivating cursor.", e);
+ }
if (mMiniThumbData != null) {
try {
mMiniThumbData.close();
mMiniThumbData = null;
} catch (IOException ex) {
-
+
}
}
}
@@ -1244,6 +1273,11 @@ public class ImageManager {
return 0;
}
}
+
+ public boolean isEmpty() {
+ return getCount() == 0;
+ }
+
protected Cursor getCursor() {
synchronized (mCursor) {
if (mCursorDeactivated) {
@@ -1252,11 +1286,11 @@ public class ImageManager {
return mCursor;
}
}
-
+
protected void activateCursor() {
requery();
}
-
+
public IImage getImageAt(int i) {
Cursor c = getCursor();
synchronized (c) {
@@ -1307,7 +1341,7 @@ public class ImageManager {
RandomAccessFile r = miniThumbDataFile();
if (r == null)
return null;
-
+
long pos = id * sBytesPerMiniThumb;
RandomAccessFile f = r;
synchronized (f) {
@@ -1349,7 +1383,7 @@ public class ImageManager {
}
index += 1;
} while (c.moveToNext());
- }
+ }
return -1;
}
}
@@ -1368,7 +1402,7 @@ public class ImageManager {
protected abstract int indexTitle();
protected abstract int indexDisplayName();
protected abstract int indexThumbId();
-
+
protected IImage make(long id, long miniThumbId, ContentResolver cr, IImageList list, long timestamp, int index, int rotation) {
return null;
}
@@ -1400,7 +1434,7 @@ public class ImageManager {
return false;
}
-
+
/* (non-Javadoc)
* @see com.android.camera.IImageList#removeImageAt(int)
*/
@@ -1460,7 +1494,7 @@ public class ImageManager {
}
r.seek(pos);
r.writeByte(0); // we have no data in this slot
-
+
// if magic is 0 then leave it alone
if (magic == 0)
r.skipBytes(8);
@@ -1468,11 +1502,11 @@ public class ImageManager {
r.writeLong(magic);
r.writeInt(data.length);
r.write(data);
- // f.flush();
+ // f.flush();
r.seek(pos);
r.writeByte(1); // we have data in this slot
long t3 = System.currentTimeMillis();
-
+
if (VERBOSE) Log.v(TAG, "saveMiniThumbToFile took " + (t3-t0) + "; " + (t1-t0) + " " + (t2-t1) + " " + (t3-t2));
}
} catch (IOException ex) {
@@ -1486,9 +1520,9 @@ public class ImageManager {
mHandler = h;
}
}
-
+
public class CanceledException extends Exception {
-
+
}
public enum DataLocation { NONE, INTERNAL, EXTERNAL, ALL }
@@ -1502,17 +1536,17 @@ public class ImageManager {
* from an ICancelable can be retrieved using the get* method. If the
* operation was canceled then null is returned. The act of canceling
* is to call "cancel" -- from another thread.
- *
- * In general an object which implements ICancelable will need to
+ *
+ * In general an object which implements ICancelable will need to
* check, periodically, whether they are canceled or not. This works
* well for some things and less well for others.
- *
+ *
* Right now the actual jpeg encode does not check cancelation but
* the part of encoding which writes the data to disk does. Note,
* though, that there is what appears to be a bug in the jpeg encoder
* in that if the stream that's being written is closed it crashes
* rather than returning an error. TODO fix that.
- *
+ *
* When an object detects that it is canceling it must, before exiting,
* call acknowledgeCancel. This is necessary because the caller of
* cancel() will block until acknowledgeCancel is called.
@@ -1526,7 +1560,7 @@ public class ImageManager {
*/
public boolean cancel();
}
-
+
public interface IGetBitmap_cancelable extends ICancelable {
// returns the bitmap or null if there was an error or we were canceled
public Bitmap get();
@@ -1543,9 +1577,9 @@ public class ImageManager {
* @return the bitmap for the full size image.
*/
public abstract Bitmap fullSizeBitmap(int targetWidthOrHeight);
-
+
/**
- *
+ *
* @return an object which can be canceled while the bitmap is loading
*/
public abstract IGetBitmap_cancelable fullSizeBitmap_cancelable(int targetWidthOrHeight);
@@ -1589,7 +1623,7 @@ public class ImageManager {
public abstract String getDisplayName();
public abstract String getPicasaId();
-
+
public abstract int getRow();
public abstract int getWidth();
@@ -1599,13 +1633,13 @@ public class ImageManager {
public abstract long imageId();
public abstract boolean isReadonly();
-
+
public abstract boolean isDrm();
-
+
public abstract Bitmap miniThumbBitmap();
-
+
public abstract void onRemove();
-
+
public abstract boolean rotateImageBy(int degrees);
/**
@@ -1622,26 +1656,27 @@ public class ImageManager {
* Sets the name of the image.
*/
public abstract void setName(String name);
-
+
public abstract void setPicasaId(String id);
-
+
/**
* Get the bitmap for the medium thumbnail.
* @return the bitmap for the medium thumbnail.
*/
public abstract Bitmap thumbBitmap();
-
+
public abstract Uri thumbUri();
-
+
public abstract String getDataPath();
}
+
public interface IImageList {
public HashMap<String, String> getBucketIds();
public interface OnChange {
public void onChange(IImageList list);
}
-
+
public interface ThumbCheckCallback {
public boolean checking(int current, int count);
}
@@ -1658,7 +1693,13 @@ public class ImageManager {
* @return the number of images
*/
public abstract int getCount();
-
+
+ /**
+ * @return true if the count of image objects is zero.
+ */
+
+ public abstract boolean isEmpty();
+
/**
* Returns the image at the ith position.
*
@@ -1666,7 +1707,7 @@ public class ImageManager {
* @return the image at the ith position
*/
public abstract IImage getImageAt(int i);
-
+
/**
* Returns the image with a particular Uri.
*
@@ -1674,40 +1715,26 @@ public class ImageManager {
* @return the image with a particular Uri.
*/
public abstract IImage getImageForUri(Uri uri);;
-
+
public abstract boolean removeImage(IImage image);
/**
* Removes the image at the ith position.
* @param i the position
*/
public abstract void removeImageAt(int i);
-
+
public abstract void removeOnChangeListener(OnChange changeCallback);
public abstract void setOnChangeListener(OnChange changeCallback, Handler h);
}
-
- class VideoObject extends Image {
- public VideoObject() {
- super(0, 0, null, null, 0, 0);
- }
-
- public String getTags() {
- return null;
- }
-
- public String setTags(String tags) {
- return null;
- }
- }
class Image extends BaseImage implements IImage {
int mRotation;
-
+
protected Image(long id, long miniThumbId, ContentResolver cr, BaseImageList container, int cursorRow, int rotation) {
super(id, miniThumbId, cr, container, cursorRow);
mRotation = rotation;
}
-
+
public String getDataPath() {
String path = null;
Cursor c = getCursor();
@@ -1724,7 +1751,7 @@ public class ImageManager {
protected int getDegreesRotated() {
return mRotation;
}
-
+
protected void setDegreesRotated(int degrees) {
Cursor c = getCursor();
mRotation = degrees;
@@ -1743,12 +1770,12 @@ public class ImageManager {
String mimeType = getMimeType();
if (mimeType == null)
return Bitmap.CompressFormat.JPEG;
-
+
if (mimeType.equals("image/png"))
return Bitmap.CompressFormat.PNG;
else if (mimeType.equals("image/png"))
return Bitmap.CompressFormat.PNG;
-
+
return Bitmap.CompressFormat.JPEG;
}
@@ -1782,16 +1809,16 @@ public class ImageManager {
}
return 0;
}
-
+
public boolean isReadonly() {
String mimeType = getMimeType();
return !"image/jpeg".equals(mimeType) && !"image/png".equals(mimeType);
}
-
+
public boolean isDrm() {
return false;
}
-
+
/**
* Remove tag if already there. Otherwise, does nothing.
* @param tag
@@ -1822,17 +1849,17 @@ public class ImageManager {
* @see com.android.camera.IImage#saveModifiedImage(android.graphics.Bitmap)
*/
public IGetBoolean_cancelable saveImageContents(
- final Bitmap image,
+ final Bitmap image,
final byte [] jpegData,
final int orientation,
final boolean newFile,
final Cursor cursor) {
final class SaveImageContentsCancelable extends BaseCancelable implements IGetBoolean_cancelable {
IGetBoolean_cancelable mCurrentCancelable = null;
-
+
SaveImageContentsCancelable() {
}
-
+
public boolean doCancelWork() {
synchronized (this) {
if (mCurrentCancelable != null)
@@ -1840,22 +1867,22 @@ public class ImageManager {
}
return true;
}
-
+
public boolean get() {
try {
Bitmap thumbnail = null;
-
+
long t1 = System.currentTimeMillis();
Uri uri = mContainer.contentUri(mId);
synchronized (this) {
checkCanceled();
mCurrentCancelable = compressImageToFile(image, jpegData, uri);
}
-
+
long t2 = System.currentTimeMillis();
if (!mCurrentCancelable.get())
return false;
-
+
synchronized (this) {
String filePath;
synchronized (cursor) {
@@ -1890,7 +1917,7 @@ public class ImageManager {
saveMiniThumb(rotate(thumbnail, orientation));
long t5 = System.currentTimeMillis();
checkCanceled();
-
+
if (VERBOSE) Log.v(TAG, String.format("Timing data %d %d %d %d", t2-t1, t3-t2, t4-t3, t5-t4));
return true;
} catch (CanceledException ex) {
@@ -1911,7 +1938,7 @@ public class ImageManager {
}
return new SaveImageContentsCancelable();
}
-
+
private void setExifRotation(int degrees) {
try {
Cursor c = getCursor();
@@ -1952,7 +1979,7 @@ public class ImageManager {
Log.e(TAG, "unable to save exif data with new orientation " + fullSizeImageUri());
}
}
-
+
/**
* Save the rotated image by updating the Exif "Orientation" tag.
* @param degrees
@@ -1979,10 +2006,10 @@ public class ImageManager {
if (mContainer.mThumbUri != null) {
try {
c = mContentResolver.query(
- mContainer.mThumbUri,
- THUMB_PROJECTION,
- Thumbnails.IMAGE_ID + "=?",
- new String[] { String.valueOf(fullSizeImageId()) },
+ mContainer.mThumbUri,
+ THUMB_PROJECTION,
+ Thumbnails.IMAGE_ID + "=?",
+ new String[] { String.valueOf(fullSizeImageId()) },
null);
if (c != null && c.moveToFirst()) {
Uri thumbUri = ContentUris.withAppendedId(mContainer.mThumbUri, c.getLong(((ImageList)mContainer).INDEX_THUMB_ID));
@@ -2011,7 +2038,7 @@ public class ImageManager {
c.close();
}
}
-
+
if (bitmap == null) {
bitmap = fullSizeBitmap(THUMBNAIL_TARGET_SIZE, false);
if (VERBOSE) {
@@ -2038,7 +2065,7 @@ public class ImageManager {
final static private String sWhereClause = "(" + Images.Media.MIME_TYPE + "=? or " + Images.Media.MIME_TYPE + "=?" + ")";
final static private String[] sAcceptableImageTypes = new String[] { "image/jpeg", "image/png" };
-
+
private static final String[] IMAGE_PROJECTION = new String[] {
"_id",
"_data",
@@ -2047,7 +2074,7 @@ public class ImageManager {
ImageColumns.ORIENTATION,
ImageColumns.MIME_TYPE
};
-
+
/**
* Represents an ordered collection of Image objects.
* Provides an api to add and remove an image.
@@ -2059,7 +2086,7 @@ public class ImageManager {
final int INDEX_DATE_TAKEN = indexOf(IMAGE_PROJECTION, ImageColumns.DATE_TAKEN);
final int INDEX_MINI_THUMB_MAGIC = indexOf(IMAGE_PROJECTION, ImageColumns.MINI_THUMB_MAGIC);
final int INDEX_ORIENTATION = indexOf(IMAGE_PROJECTION, ImageColumns.ORIENTATION);
-
+
final int INDEX_THUMB_ID = indexOf(THUMB_PROJECTION, BaseColumns._ID);
final int INDEX_THUMB_IMAGE_ID = indexOf(THUMB_PROJECTION, Images.Thumbnails.IMAGE_ID);
final int INDEX_THUMB_WIDTH = indexOf(THUMB_PROJECTION, Images.Thumbnails.WIDTH);
@@ -2068,12 +2095,12 @@ public class ImageManager {
boolean mIsRegistered = false;
ContentObserver mContentObserver;
DataSetObserver mDataSetObserver;
-
+
public HashMap<String, String> getBucketIds() {
Cursor c = Images.Media.query(
mContentResolver,
mBaseUri.buildUpon().appendQueryParameter("distinct", "true").build(),
- new String[] {
+ new String[] {
ImageColumns.BUCKET_DISPLAY_NAME,
ImageColumns.BUCKET_ID
},
@@ -2098,7 +2125,6 @@ public class ImageManager {
mBaseUri = imageUri;
mThumbUri = thumbUri;
mSort = sort;
- mBucketId = bucketId;
mContentResolver = cr;
@@ -2118,7 +2144,7 @@ public class ImageManager {
// For now ignore them since there shouldn't be anyone modifying the database on the fly.
if (true)
return;
-
+
synchronized (mCursor) {
requery();
}
@@ -2126,7 +2152,7 @@ public class ImageManager {
mListener.onChange(ImageList.this);
}
};
-
+
mContentObserver = new ContentObserver(null) {
@Override
public boolean deliverSelfNotifications() {
@@ -2139,7 +2165,7 @@ public class ImageManager {
updateRunnable.run();
}
};
-
+
mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
@@ -2152,23 +2178,23 @@ public class ImageManager {
if (VERBOSE) Log.v(TAG, "MyDataSetObserver.onInvalidated: " + mCursorDeactivated);
}
};
-
+
registerObservers();
}
-
+
private void registerObservers() {
if (mIsRegistered)
return;
-
+
mCursor.registerContentObserver(mContentObserver);
mCursor.registerDataSetObserver(mDataSetObserver);
mIsRegistered = true;
}
-
+
private void unregisterObservers() {
if (!mIsRegistered)
return;
-
+
mCursor.unregisterContentObserver(mContentObserver);
mCursor.unregisterDataSetObserver(mDataSetObserver);
mIsRegistered = false;
@@ -2183,21 +2209,21 @@ public class ImageManager {
super.activateCursor();
registerObservers();
}
-
+
protected String whereClause() {
if (mBucketId != null) {
- return sWhereClause + " and " + Images.Media.BUCKET_ID + " = " + mBucketId;
+ return sWhereClause + " and " + Images.Media.BUCKET_ID + " = '" + mBucketId + "'";
} else {
return sWhereClause;
}
}
-
+
protected String[] whereClauseArgs() {
return sAcceptableImageTypes;
}
-
+
protected Cursor createCursor() {
- Cursor c =
+ Cursor c =
Images.Media.query(
mContentResolver,
mBaseUri,
@@ -2209,7 +2235,7 @@ public class ImageManager {
Log.v(TAG, "createCursor got cursor with count " + (c == null ? -1 : c.getCount()));
return c;
}
-
+
protected int indexOrientation() { return INDEX_ORIENTATION; }
protected int indexDateTaken() { return INDEX_DATE_TAKEN; }
protected int indexDescription() { return -1; }
@@ -2225,7 +2251,7 @@ public class ImageManager {
protected int indexTitle() { return -1; }
protected int indexDisplayName() { return -1; }
protected int indexThumbId() { return INDEX_THUMB_ID; }
-
+
protected IImage make(long id, long miniThumbId, ContentResolver cr, IImageList list, long timestamp, int index, int rotation) {
return new Image(id, miniThumbId, mContentResolver, this, index, rotation);
}
@@ -2234,12 +2260,12 @@ public class ImageManager {
Bitmap b = null;
try {
- if (pfd == null)
+ if (pfd == null)
pfd = makeInputStream(uri);
if (pfd == null)
return null;
-
+
if (options == null)
options = new BitmapFactory.Options();
@@ -2272,7 +2298,7 @@ public class ImageManager {
}
return b;
}
-
+
private ParcelFileDescriptor makeInputStream(Uri uri) {
try {
return mContentResolver.openFileDescriptor(uri, "r");
@@ -2286,11 +2312,11 @@ public class ImageManager {
// which could happen, I suppose, if the first two values were
// duplicated
String ascending = (mSort == SORT_ASCENDING ? " ASC" : " DESC");
- return
+ return
Images.Media.DATE_TAKEN + ascending + "," +
Images.Media._ID + ascending;
}
-
+
}
/**
@@ -2301,11 +2327,11 @@ public class ImageManager {
DrmStore.Audio._ID,
DrmStore.Audio.DATA,
DrmStore.Audio.MIME_TYPE,
- };
-
+ };
+
final int INDEX_ID = indexOf(DRM_IMAGE_PROJECTION, DrmStore.Audio._ID);
final int INDEX_MIME_TYPE = indexOf(DRM_IMAGE_PROJECTION, DrmStore.Audio.MIME_TYPE);
-
+
public DrmImageList(Context ctx, ContentResolver cr, Uri imageUri, int sort, String bucketId) {
super(ctx, cr, imageUri, null, sort, bucketId);
}
@@ -2323,16 +2349,16 @@ public class ImageManager {
public long checkThumbnail(BaseImage existingImage, Cursor c, int i) {
return 0;
}
-
+
class DrmImage extends Image {
protected DrmImage(long id, ContentResolver cr, BaseImageList container, int cursorRow) {
super(id, 0, cr, container, cursorRow, 0);
}
-
+
public boolean isDrm() {
return true;
}
-
+
public boolean isReadonly() {
return true;
}
@@ -2340,16 +2366,21 @@ public class ImageManager {
public Bitmap miniThumbBitmap() {
return fullSizeBitmap(MINI_THUMB_TARGET_SIZE);
}
-
+
public Bitmap thumbBitmap() {
return fullSizeBitmap(THUMBNAIL_TARGET_SIZE);
}
+
+ public String getDisplayName() {
+ return getTitle();
+ }
}
-
- protected IImage make(long id, long miniThumbId, ContentResolver cr, IImageList list, long timestamp, int index) {
+
+ @Override
+ protected IImage make(long id, long miniThumbId, ContentResolver cr, IImageList list, long timestamp, int index, int rotation) {
return new DrmImage(id, mContentResolver, this, index);
}
-
+
protected int indexOrientation() { return -1; }
protected int indexDateTaken() { return -1; }
protected int indexDescription() { return -1; }
@@ -2363,11 +2394,11 @@ public class ImageManager {
protected int indexTitle() { return -1; }
protected int indexDisplayName() { return -1; }
protected int indexThumbId() { return -1; }
-
+
// TODO review this probably should be based on DATE_TAKEN same as images
private String sortOrder() {
String ascending = (mSort == SORT_ASCENDING ? " ASC" : " DESC");
- return
+ return
DrmStore.Images.TITLE + ascending + "," +
DrmStore.Images._ID;
}
@@ -2385,7 +2416,7 @@ public class ImageManager {
// The second component indicates which sublist we're referring
// to (an int which is used to index into mSubList).
ArrayList<Long> mSkipList = null;
-
+
int [] mSkipCounts = null;
public HashMap<String, String> getBucketIds() {
@@ -2395,7 +2426,7 @@ public class ImageManager {
}
return hashMap;
}
-
+
public ImageListUber(IImageList [] sublist, int sort) {
mSubList = sublist.clone();
mSort = sort;
@@ -2412,7 +2443,7 @@ public class ImageManager {
}
}
}
-
+
public void checkThumbnails(ThumbCheckCallback cb) {
// TODO this isn't quite right because we need to get the
// total from each sub item and provide that in the callback
@@ -2421,7 +2452,7 @@ public class ImageManager {
for (int i = 0; i < length; i++)
sublist[i].checkThumbnails(cb);
}
-
+
public void commitChanges() {
final IImageList sublist[] = mSubList;
final int length = sublist.length;
@@ -2448,6 +2479,17 @@ public class ImageManager {
return count;
}
+ public boolean isEmpty() {
+ final IImageList sublist[] = mSubList;
+ final int length = sublist.length;
+ for (int i = 0; i < length; i++) {
+ if (! sublist[i].isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
// mSkipCounts is used to tally the counts as we traverse
// the mSkipList. It's a member variable only so that
// we don't have to allocate each time through. Otherwise
@@ -2456,7 +2498,7 @@ public class ImageManager {
public synchronized IImage getImageAt(int index) {
if (index < 0 || index > getCount())
throw new IndexOutOfBoundsException("index " + index + " out of range max is " + getCount());
-
+
// first make sure our allocations are in order
if (mSkipCounts == null || mSubList.length > mSkipCounts.length)
mSkipCounts = new int[mSubList.length];
@@ -2610,7 +2652,7 @@ public class ImageManager {
if (changeCallback == mListener)
mListener = null;
}
-
+
public void setOnChangeListener(OnChange changeCallback, Handler h) {
mListener = changeCallback;
mHandler = h;
@@ -2642,7 +2684,7 @@ public class ImageManager {
public long getDateTaken() {
return 0;
}
-
+
public String getMimeType() {
throw new UnsupportedOperationException();
}
@@ -2658,7 +2700,7 @@ public class ImageManager {
public double getLatitude() {
return 0D;
}
-
+
public double getLongitude() {
return 0D;
}
@@ -2678,7 +2720,7 @@ public class ImageManager {
public int getRow() {
throw new UnsupportedOperationException();
}
-
+
public int getHeight() {
return 0;
}
@@ -2686,7 +2728,7 @@ public class ImageManager {
public int getWidth() {
return 0;
}
-
+
public boolean hasLatLong() {
return false;
}
@@ -2694,7 +2736,7 @@ public class ImageManager {
public boolean isReadonly() {
return true;
}
-
+
public boolean isDrm() {
return false;
}
@@ -2706,7 +2748,7 @@ public class ImageManager {
public boolean rotateImageBy(int degrees) {
return false;
}
-
+
public void setDescription(String description) {
throw new UnsupportedOperationException();
}
@@ -2718,13 +2760,13 @@ public class ImageManager {
public void setName(String name) {
throw new UnsupportedOperationException();
}
-
+
public void setPicasaId(long id) {
}
public void setPicasaId(String id) {
}
-
+
public Uri thumbUri() {
throw new UnsupportedOperationException();
}
@@ -2739,11 +2781,11 @@ public class ImageManager {
UriImage() {
}
-
+
public String getDataPath() {
return mUri.getPath();
}
-
+
InputStream getInputStream() {
try {
if (mUri.getScheme().equals("file")) {
@@ -2758,7 +2800,7 @@ public class ImageManager {
return null;
}
}
-
+
ParcelFileDescriptor getPFD() {
try {
if (mUri.getScheme().equals("file")) {
@@ -2773,7 +2815,7 @@ public class ImageManager {
return null;
}
}
-
+
/* (non-Javadoc)
* @see com.android.camera.ImageManager.IImage#fullSizeBitmap(int)
*/
@@ -2790,7 +2832,7 @@ public class ImageManager {
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-
+
Bitmap b = BitmapFactory.decodeFileDescriptor(pfdInput.getFileDescriptor(), null, options);
if (VERBOSE) {
Log.v(TAG, "B: got bitmap " + b + " with sampleSize " + options.inSampleSize);
@@ -2808,11 +2850,11 @@ public class ImageManager {
ParcelFileDescriptor pfdInput;
BitmapFactory.Options mOptions = new BitmapFactory.Options();
long mCancelInitiationTime;
-
+
public LoadBitmapCancelable(ParcelFileDescriptor pfd) {
pfdInput = pfd;
}
-
+
public boolean doCancelWork() {
if (VERBOSE)
Log.v(TAG, "requesting bitmap load cancel");
@@ -2820,7 +2862,7 @@ public class ImageManager {
mOptions.requestCancelDecode();
return true;
}
-
+
public Bitmap get() {
try {
Bitmap b = makeBitmap(targetWidthOrHeight, fullSizeImageUri(), pfdInput, mOptions);
@@ -2848,12 +2890,12 @@ public class ImageManager {
return null;
}
}
-
+
@Override
public Uri fullSizeImageUri() {
return mUri;
}
-
+
@Override
public InputStream fullSizeImageData() {
return getInputStream();
@@ -2862,26 +2904,26 @@ public class ImageManager {
public long imageId() {
return 0;
}
-
+
public Bitmap miniThumbBitmap() {
return thumbBitmap();
}
-
+
@Override
public String getTitle() {
return mUri.toString();
}
-
+
@Override
public String getDisplayName() {
return getTitle();
}
-
- @Override
+
+ @Override
public String getDescription() {
return "";
}
-
+
public Bitmap thumbBitmap() {
Bitmap b = fullSizeBitmap(THUMBNAIL_TARGET_SIZE);
if (b != null) {
@@ -2894,7 +2936,7 @@ public class ImageManager {
return null;
}
}
-
+
private BitmapFactory.Options snifBitmapOptions() {
ParcelFileDescriptor input = getPFD();
if (input == null)
@@ -2920,13 +2962,13 @@ public class ImageManager {
BitmapFactory.Options options = snifBitmapOptions();
return (options!=null) ? options.outMimeType : "";
}
-
+
@Override
public int getHeight() {
BitmapFactory.Options options = snifBitmapOptions();
return (options!=null) ? options.outHeight : 0;
}
-
+
@Override
public int getWidth() {
BitmapFactory.Options options = snifBitmapOptions();
@@ -2948,11 +2990,15 @@ public class ImageManager {
public void deactivate() {
// nothing to do here
}
-
+
public int getCount() {
return 1;
}
+ public boolean isEmpty() {
+ return false;
+ }
+
public IImage getImageAt(int i) {
if (i == 0)
return mSingleImage;
@@ -2980,7 +3026,7 @@ public class ImageManager {
protected int indexDateTaken() {
return -1;
}
-
+
@Override
protected int indexMimeType() {
return -1;
@@ -2990,12 +3036,12 @@ public class ImageManager {
protected int indexDescription() {
return -1;
}
-
+
@Override
protected int indexId() {
return -1;
}
-
+
@Override
protected int indexData() {
return -1;
@@ -3040,7 +3086,7 @@ public class ImageManager {
protected int indexThumbId() {
return -1;
}
-
+
private InputStream makeInputStream(Uri uri) {
InputStream input = null;
try {
@@ -3087,14 +3133,14 @@ public class ImageManager {
public ThreadSafeOutputStream(OutputStream delegate) {
mDelegateStream = delegate;
}
-
+
@Override
synchronized public void close() throws IOException {
try {
mClosed = true;
mDelegateStream.close();
} catch (IOException ex) {
-
+
}
}
@@ -3113,7 +3159,7 @@ public class ImageManager {
synchronized (this) {
if (mClosed)
return;
-
+
int writeLength = Math.min(8192, length);
mDelegateStream.write(b, offset, writeLength);
offset += writeLength;
@@ -3129,14 +3175,349 @@ public class ImageManager {
mDelegateStream.write(oneByte);
}
}
-
+
+ class VideoList extends BaseImageList implements IImageList {
+ private final String[] sProjection = new String[] {
+ Video.Media._ID,
+ Video.Media.DATA,
+ Video.Media.DATE_TAKEN,
+ Video.Media.TITLE,
+ Video.Media.DISPLAY_NAME,
+ Video.Media.DESCRIPTION,
+ Video.Media.IS_PRIVATE,
+ Video.Media.TAGS,
+ Video.Media.CATEGORY,
+ Video.Media.LANGUAGE,
+ Video.Media.LATITUDE,
+ Video.Media.LONGITUDE,
+ Video.Media.MINI_THUMB_MAGIC,
+ Video.Media.MIME_TYPE,
+ };
+
+ final int INDEX_ID = indexOf(sProjection, Video.Media._ID);
+ final int INDEX_DATA = indexOf(sProjection, Video.Media.DATA);
+ final int INDEX_DATE_TAKEN = indexOf(sProjection, Video.Media.DATE_TAKEN);
+ final int INDEX_TITLE = indexOf(sProjection, Video.Media.TITLE);
+ final int INDEX_DISPLAY_NAME = indexOf(sProjection, Video.Media.DISPLAY_NAME);
+ final int INDEX_MIME_TYPE = indexOf(sProjection, Video.Media.MIME_TYPE);
+ final int INDEX_DESCRIPTION = indexOf(sProjection, Video.Media.DESCRIPTION);
+ final int INDEX_PRIVATE = indexOf(sProjection, Video.Media.IS_PRIVATE);
+ final int INDEX_TAGS = indexOf(sProjection, Video.Media.TAGS);
+ final int INDEX_CATEGORY = indexOf(sProjection, Video.Media.CATEGORY);
+ final int INDEX_LANGUAGE = indexOf(sProjection, Video.Media.LANGUAGE);
+ final int INDEX_LATITUDE = indexOf(sProjection, Video.Media.LATITUDE);
+ final int INDEX_LONGITUDE = indexOf(sProjection, Video.Media.LONGITUDE);
+ final int INDEX_MINI_THUMB_MAGIC = indexOf(sProjection, Video.Media.MINI_THUMB_MAGIC);
+ final int INDEX_THUMB_ID = indexOf(sProjection, BaseColumns._ID);
+
+ public VideoList(Context ctx, ContentResolver cr, Uri uri, Uri thumbUri,
+ int sort, String bucketId) {
+ super(ctx, cr, uri, sort, bucketId);
+
+ mCursor = createCursor();
+ if (mCursor == null) {
+ Log.e(TAG, "unable to create video cursor for " + mBaseUri);
+ throw new UnsupportedOperationException();
+ }
+
+ if (Config.LOGV) {
+ Log.v(TAG, "for " + mUri.toString() + " got cursor " + mCursor + " with length "
+ + (mCursor != null ? mCursor.getCount() : -1));
+ }
+
+ if (mCursor == null) {
+ throw new UnsupportedOperationException();
+ }
+ if (mCursor != null && mCursor.moveToFirst()) {
+ int row = 0;
+ do {
+ long imageId = mCursor.getLong(indexId());
+ long dateTaken = mCursor.getLong(indexDateTaken());
+ long miniThumbId = mCursor.getLong(indexMiniThumbId());
+ mCache.put(imageId, new VideoObject(imageId, miniThumbId, mContentResolver,
+ this, dateTaken, row++));
+ } while (mCursor.moveToNext());
+ }
+ }
+
+ public HashMap<String, String> getBucketIds() {
+ Cursor c = Images.Media.query(
+ mContentResolver,
+ mBaseUri.buildUpon().appendQueryParameter("distinct", "true").build(),
+ new String[] {
+ VideoColumns.BUCKET_DISPLAY_NAME,
+ VideoColumns.BUCKET_ID
+ },
+ whereClause(),
+ whereClauseArgs(),
+ sortOrder());
+
+ HashMap<String, String> hash = new HashMap<String, String>();
+ if (c != null && c.moveToFirst()) {
+ do {
+ Log.e(TAG, "id: " + c.getString(1) + " display_name: " + c.getString(0));
+ hash.put(c.getString(1), c.getString(0));
+ } while (c.moveToNext());
+ }
+ return hash;
+ }
+
+ protected String whereClause() {
+ if (mBucketId != null) {
+ return Images.Media.BUCKET_ID + " = '" + mBucketId + "'";
+ } else {
+ return null;
+ }
+ }
+
+ protected String[] whereClauseArgs() {
+ return null;
+ }
+
+ protected Cursor createCursor() {
+ Cursor c =
+ Images.Media.query(
+ mContentResolver,
+ mBaseUri,
+ sProjection,
+ whereClause(),
+ whereClauseArgs(),
+ sortOrder());
+ if (VERBOSE)
+ Log.v(TAG, "createCursor got cursor with count " + (c == null ? -1 : c.getCount()));
+ return c;
+ }
+
+ protected int indexOrientation() { return -1; }
+ protected int indexDateTaken() { return INDEX_DATE_TAKEN; }
+ protected int indexDescription() { return INDEX_DESCRIPTION; }
+ protected int indexMimeType() { return INDEX_MIME_TYPE; }
+ protected int indexData() { return INDEX_DATA; }
+ protected int indexId() { return INDEX_ID; }
+ protected int indexLatitude() { return INDEX_LATITUDE; }
+ protected int indexLongitude() { return INDEX_LONGITUDE; }
+ protected int indexMiniThumbId() { return INDEX_MINI_THUMB_MAGIC; }
+ protected int indexPicasaWeb() { return -1; }
+ protected int indexPrivate() { return INDEX_PRIVATE; }
+ protected int indexTitle() { return INDEX_TITLE; }
+ protected int indexDisplayName() { return -1; }
+ protected int indexThumbId() { return INDEX_THUMB_ID; }
+
+ protected IImage make(long id, long miniThumbId, ContentResolver cr, IImageList list,
+ long timestamp, int index) {
+ return new VideoObject(id, miniThumbId, mContentResolver, this, timestamp, index);
+ }
+
+ @Override
+ protected Bitmap makeBitmap(int targetWidthHeight, Uri uri, ParcelFileDescriptor pfdInput,
+ BitmapFactory.Options options) {
+ MediaPlayer mp = new MediaPlayer();
+ Bitmap thumbnail = sDefaultThumbnail;
+ try {
+ mp.setDataSource(mContext, uri);
+// int duration = mp.getDuration();
+// int at = duration > 2000 ? 1000 : duration / 2;
+ int at = 1000;
+ thumbnail = mp.getFrameAt(at);
+ if (Config.LOGV) {
+ if ( thumbnail != null) {
+ Log.v(TAG, "getFrameAt @ " + at + " returned " + thumbnail + "; " +
+ thumbnail.getWidth() + " " + thumbnail.getHeight());
+ } else {
+ Log.v(TAG, "getFrame @ " + at + " failed for " + uri);
+ }
+ }
+ } catch (IOException ex) {
+ } catch (IllegalArgumentException ex) {
+ } catch (SecurityException ex) {
+ } finally {
+ mp.release();
+ }
+ return thumbnail;
+ }
+
+ private final Bitmap sDefaultThumbnail = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565);
+
+ private String sortOrder() {
+ return Video.Media.DATE_MODIFIED + (mSort == SORT_ASCENDING ? " ASC " : " DESC");
+ }
+ }
+
+ /**
+ * Represents a particular video and provides access
+ * to the underlying data and two thumbnail bitmaps
+ * as well as other information such as the id, and
+ * the path to the actual video data.
+ */
+ class VideoObject extends BaseImage implements IImage {
+ /**
+ * Constructor.
+ *
+ * @param id the image id of the image
+ * @param cr the content resolver
+ */
+ protected VideoObject(long id, long miniThumbId, ContentResolver cr, VideoList container,
+ long dateTaken, int row) {
+ super(id, miniThumbId, cr, container, row);
+ }
+
+ protected Bitmap.CompressFormat compressionType() {
+ return Bitmap.CompressFormat.JPEG;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null)
+ return false;
+ if (!(other instanceof VideoObject))
+ return false;
+
+ return fullSizeImageUri().equals(((VideoObject)other).fullSizeImageUri());
+ }
+
+ public String getDataPath() {
+ String path = null;
+ Cursor c = getCursor();
+ synchronized (c) {
+ if (c.moveToPosition(getRow())) {
+ int column = ((VideoList)getContainer()).indexData();
+ if (column >= 0)
+ path = c.getString(column);
+ }
+ }
+ return path;
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.camera.IImage#fullSizeBitmap()
+ */
+ public Bitmap fullSizeBitmap(int targetWidthHeight) {
+ return sNoImageBitmap;
+ }
+
+ public IGetBitmap_cancelable fullSizeBitmap_cancelable(int targetWidthHeight) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.camera.IImage#fullSizeImageData()
+ */
+ public InputStream fullSizeImageData() {
+ try {
+ InputStream input = mContentResolver.openInputStream(
+ fullSizeImageUri());
+ return input;
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.camera.IImage#fullSizeImageId()
+ */
+ public long fullSizeImageId() {
+ return mId;
+ }
+
+ public String getCategory() {
+ return getStringEntry(((VideoList)mContainer).INDEX_CATEGORY);
+ }
+
+ public int getHeight() {
+ return 0;
+ }
+
+ public String getLanguage() {
+ return getStringEntry(((VideoList)mContainer).INDEX_LANGUAGE);
+ }
+
+ public String getPicasaId() {
+ return null;
+ }
+
+ private String getStringEntry(int entryName) {
+ String entry = null;
+ Cursor c = getCursor();
+ synchronized(c) {
+ if (c.moveToPosition(getRow())) {
+ entry = c.getString(entryName);
+ }
+ }
+ return entry;
+ }
+
+ public String getTags() {
+ return getStringEntry(((VideoList)mContainer).INDEX_TAGS);
+ }
+
+ public int getWidth() {
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.camera.IImage#imageId()
+ */
+ public long imageId() {
+ return mId;
+ }
+
+ public boolean isReadonly() {
+ return false;
+ }
+
+ public boolean isDrm() {
+ return false;
+ }
+
+ public boolean rotateImageBy(int degrees) {
+ return false;
+ }
+
+ public void setCategory(String category) {
+ setStringEntry(category, ((VideoList)mContainer).INDEX_CATEGORY);
+ }
+
+ public void setLanguage(String language) {
+ setStringEntry(language, ((VideoList)mContainer).INDEX_LANGUAGE);
+ }
+
+ private void setStringEntry(String entry, int entryName) {
+ Cursor c = getCursor();
+ synchronized (c) {
+ if (c.moveToPosition(getRow())) {
+ c.updateString(entryName, entry);
+ }
+ }
+ }
+
+ public void setTags(String tags) {
+ setStringEntry(tags, ((VideoList)mContainer).INDEX_TAGS);
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.camera.IImage#thumb1()
+ */
+ public Bitmap thumbBitmap() {
+ return fullSizeBitmap(320);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("" + mId);
+ return sb.toString();
+ }
+
+ private final Bitmap sNoImageBitmap = Bitmap.createBitmap(128, 128, Bitmap.Config.RGB_565);
+ }
+
/*
* How much quality to use when storing the thumbnail.
*/
private static ImageManager sInstance = null;
private static final int MINI_THUMB_TARGET_SIZE = 96;
private static final int THUMBNAIL_TARGET_SIZE = 320;
-
+
private static final String[] THUMB_PROJECTION = new String[] {
BaseColumns._ID, // 0
Images.Thumbnails.IMAGE_ID, // 1
@@ -3147,6 +3528,10 @@ public class ImageManager {
private static Uri sStorageURI = Images.Media.EXTERNAL_CONTENT_URI;
private static Uri sThumbURI = Images.Thumbnails.EXTERNAL_CONTENT_URI;
+
+ private static Uri sVideoStorageURI = Uri.parse("content://media/external/video/media");
+
+ private static Uri sVideoThumbURI = Uri.parse("content://media/external/video/thumbnails");
/**
* Returns an ImageList object that contains
* all of the images.
@@ -3157,13 +3542,13 @@ public class ImageManager {
* @return the singleton ImageList
*/
static final public int SORT_ASCENDING = 1;
-
+
static final public int SORT_DESCENDING = 2;
static final public int INCLUDE_IMAGES = (1 << 0);
static final public int INCLUDE_DRM_IMAGES = (1 << 1);
static final public int INCLUDE_VIDEOS = (1 << 2);
-
+
static public DataLocation getDefaultDataLocation() {
return DataLocation.EXTERNAL;
}
@@ -3190,7 +3575,7 @@ public class ImageManager {
static public byte [] miniThumbData(Bitmap source) {
if (source == null)
return null;
-
+
float scale;
if (source.getWidth() < source.getHeight()) {
scale = MINI_THUMB_TARGET_SIZE / (float)source.getWidth();
@@ -3199,7 +3584,7 @@ public class ImageManager {
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
- Bitmap miniThumbnail = ImageLoader.transform(matrix, source,
+ Bitmap miniThumbnail = ImageLoader.transform(matrix, source,
MINI_THUMB_TARGET_SIZE, MINI_THUMB_TARGET_SIZE, false);
if (miniThumbnail != source) {
@@ -3223,7 +3608,7 @@ public class ImageManager {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2);
-
+
Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
// TODO should recycle here but that needs more testing/verification
// b.recycle();
@@ -3231,12 +3616,12 @@ public class ImageManager {
}
return b;
}
-
+
public static int roundOrientation(int orientationInput) {
int orientation = orientationInput;
if (orientation == -1)
orientation = 0;
-
+
orientation = orientation % 360;
int retVal;
if (orientation < (0*90) + 45) {
@@ -3255,6 +3640,35 @@ public class ImageManager {
return retVal;
}
+
+ /**
+ * @return true if the mimetype is an image mimetype.
+ */
+ public static boolean isImageMimeType(String mimeType) {
+ return mimeType.startsWith("image/");
+ }
+
+ /**
+ * @return true if the mimetype is a video mimetype.
+ */
+ public static boolean isVideoMimeType(String mimeType) {
+ return mimeType.startsWith("video/");
+ }
+
+ /**
+ * @return true if the image is an image.
+ */
+ public static boolean isImage(IImage image) {
+ return isImageMimeType(image.getMimeType());
+ }
+
+ /**
+ * @return true if the image is a video.
+ */
+ public static boolean isVideo(IImage image) {
+ return isVideoMimeType(image.getMimeType());
+ }
+
public Uri addImage(
final Context ctx,
final ContentResolver cr,
@@ -3274,11 +3688,12 @@ public class ImageManager {
values.put(Images.Media.ORIENTATION, orientation);
File parentFile = new File(directory);
+ // Lowercase the path for hashing. This avoids duplicate buckets if the filepath
+ // case is changed externally.
+ // Keep the original case for display.
String path = parentFile.toString().toLowerCase();
- String name = parentFile.getName().toLowerCase();
-
- values.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
- values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
+ String name = parentFile.getName();
+
if (VERBOSE) Log.v(TAG, "addImage id is " + path.hashCode() + "; name " + name + "; path is " + path);
if (location != null) {
@@ -3288,24 +3703,24 @@ public class ImageManager {
values.put(Images.Media.LATITUDE, location.getLatitude());
values.put(Images.Media.LONGITUDE, location.getLongitude());
}
-
+
if (directory != null && filename != null) {
String value = directory + "/" + filename;
values.put("_data", value);
}
-
+
long t3 = System.currentTimeMillis();
Uri uri = cr.insert(sStorageURI, values);
-
+
// The line above will create a filename that ends in .jpg
// That filename is what will be handed to gmail when a user shares a photo.
// Gmail gets the name of the picture attachment from the "DISPLAY_NAME" field.
// Extract the filename and jam it into the display name.
Cursor c = cr.query(
- uri,
- new String [] { ImageColumns._ID, Images.Media.DISPLAY_NAME, "_data" },
- null,
- null,
+ uri,
+ new String [] { ImageColumns._ID, Images.Media.DISPLAY_NAME, "_data" },
+ null,
+ null,
null);
if (c.moveToFirst()) {
String filePath = c.getString(2);
@@ -3331,7 +3746,7 @@ public class ImageManager {
final byte [] jpegData) {
class AddImageCancelable extends BaseCancelable implements IAddImage_cancelable {
private IGetBoolean_cancelable mSaveImageCancelable;
-
+
public boolean doCancelWork() {
if (VERBOSE) {
Log.v(TAG, "calling AddImageCancelable.cancel() " + mSaveImageCancelable);
@@ -3347,7 +3762,7 @@ public class ImageManager {
if (source == null && jpegData == null) {
throw new IllegalArgumentException("source cannot be null");
}
-
+
try {
long t1 = System.currentTimeMillis();
synchronized (this) {
@@ -3356,15 +3771,15 @@ public class ImageManager {
}
}
long id = ContentUris.parseId(uri);
-
+
BaseImageList il = new ImageList(ctx, cr, sStorageURI, sThumbURI, SORT_ASCENDING, null);
ImageManager.Image image = new Image(id, 0, cr, il, il.getCount(), 0);
long t5 = System.currentTimeMillis();
Cursor c = cr.query(
- uri,
- new String [] { ImageColumns._ID, ImageColumns.MINI_THUMB_MAGIC, "_data" },
- null,
- null,
+ uri,
+ new String [] { ImageColumns._ID, ImageColumns.MINI_THUMB_MAGIC, "_data" },
+ null,
+ null,
null);
c.moveToPosition(0);
@@ -3372,7 +3787,7 @@ public class ImageManager {
checkCanceled();
mSaveImageCancelable = image.saveImageContents(source, jpegData, orientation, true, c);
}
-
+
if (mSaveImageCancelable.get()) {
long t6 = System.currentTimeMillis();
if (VERBOSE) Log.v(TAG, "saveImageContents took " + (t6-t5));
@@ -3403,7 +3818,7 @@ public class ImageManager {
}
return new AddImageCancelable();
}
-
+
static public IImageList makeImageList(Uri uri, Context ctx, int sort) {
ContentResolver cr = ctx.getContentResolver();
String uriString = (uri != null) ? uri.toString() : "";
@@ -3411,7 +3826,7 @@ public class ImageManager {
// DRM images in a better way. Is there a constant
// for content://drm somewhere??
IImageList imageList;
-
+
if (uriString.startsWith("content://drm")) {
imageList = ImageManager.instance().allImages(
ctx,
@@ -3435,7 +3850,7 @@ public class ImageManager {
}
return imageList;
}
-
+
public IImageList emptyImageList() {
return
new IImageList() {
@@ -3456,6 +3871,10 @@ public class ImageManager {
return 0;
}
+ public boolean isEmpty() {
+ return true;
+ }
+
public IImage getImageAt(int i) {
return null;
}
@@ -3476,10 +3895,10 @@ public class ImageManager {
public void setOnChangeListener(com.android.camera.ImageManager.IImageList.OnChange changeCallback, Handler h) {
}
-
+
};
}
-
+
public IImageList allImages(Context ctx, ContentResolver cr, DataLocation location, int inclusion, int sort) {
return allImages(ctx, cr, location, inclusion, sort, null, null);
}
@@ -3487,12 +3906,12 @@ public class ImageManager {
public IImageList allImages(Context ctx, ContentResolver cr, DataLocation location, int inclusion, int sort, String bucketId) {
return allImages(ctx, cr, location, inclusion, sort, bucketId, null);
}
-
+
public IImageList allImages(Context ctx, ContentResolver cr, DataLocation location, int inclusion, int sort, String bucketId, Uri specificImageUri) {
if (VERBOSE) {
Log.v(TAG, "allImages " + location + " " + ((inclusion&INCLUDE_IMAGES)!=0) + " + v=" + ((inclusion&INCLUDE_VIDEOS)!=0));
}
-
+
if (cr == null) {
return null;
} else {
@@ -3510,7 +3929,7 @@ public class ImageManager {
try {
if (specificImageUri.getScheme().equalsIgnoreCase("content"))
l.add(new ImageList(ctx, cr, specificImageUri, sThumbURI, sort, bucketId));
- else
+ else
l.add(new SingleImageList(cr, specificImageUri));
} catch (UnsupportedOperationException ex) {
}
@@ -3522,11 +3941,17 @@ public class ImageManager {
} catch (UnsupportedOperationException ex) {
}
}
+ if ((inclusion & INCLUDE_VIDEOS) != 0) {
+ try {
+ l.add(new VideoList(ctx, cr, sVideoStorageURI, sVideoThumbURI, sort, bucketId));
+ } catch (UnsupportedOperationException ex) {
+ }
+ }
}
if (location == DataLocation.INTERNAL || location == DataLocation.ALL) {
if ((inclusion & INCLUDE_IMAGES) != 0) {
try {
- l.add(new ImageList(ctx, cr, Images.Media.INTERNAL_CONTENT_URI,
+ l.add(new ImageList(ctx, cr, Images.Media.INTERNAL_CONTENT_URI,
Images.Thumbnails.INTERNAL_CONTENT_URI, sort, bucketId));
} catch (UnsupportedOperationException ex) {
}
@@ -3546,7 +3971,7 @@ public class ImageManager {
if (haveSdCard && location != DataLocation.INTERNAL) {
return new ImageList(ctx, cr, sStorageURI, sThumbURI, sort, bucketId);
} else {
- return new ImageList(ctx, cr, Images.Media.INTERNAL_CONTENT_URI,
+ return new ImageList(ctx, cr, Images.Media.INTERNAL_CONTENT_URI,
Images.Thumbnails.INTERNAL_CONTENT_URI, sort, bucketId);
}
}
@@ -3577,7 +4002,7 @@ public class ImageManager {
return false;
}
}
-
+
static public boolean hasStorage() {
return hasStorage(true);
}
@@ -3610,20 +4035,20 @@ public class ImageManager {
} catch (UnsupportedOperationException ex) {
return null;
}
-
+
}
-
+
public static boolean isMediaScannerScanning(Context context) {
boolean result = false;
- Cursor cursor = query(context, MediaStore.getMediaScannerUri(),
+ Cursor cursor = query(context, MediaStore.getMediaScannerUri(),
new String [] { MediaStore.MEDIA_SCANNER_VOLUME }, null, null, null);
if (cursor != null) {
if (cursor.getCount() == 1) {
cursor.moveToFirst();
result = "external".equals(cursor.getString(0));
}
- cursor.close();
- }
+ cursor.close();
+ }
if (VERBOSE)
Log.v(TAG, ">>>>>>>>>>>>>>>>>>>>>>>>> isMediaScannerScanning returning " + result);
diff --git a/src/com/android/camera/ImageViewTouchBase.java b/src/com/android/camera/ImageViewTouchBase.java
index 9993373..7cdf55e 100644
--- a/src/com/android/camera/ImageViewTouchBase.java
+++ b/src/com/android/camera/ImageViewTouchBase.java
@@ -13,6 +13,7 @@ import android.util.Config;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
+import android.view.KeyEvent;
import android.widget.ImageView;
abstract public class ImageViewTouchBase extends ImageView {
@@ -91,6 +92,17 @@ abstract public class ImageViewTouchBase extends ImageView {
}
}
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && getScale() > 1.0f) {
+ // If we're zoomed in, pressing Back jumps out to show the entire image, otherwise Back
+ // returns the user to the gallery.
+ zoomTo(1.0f);
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
protected Handler mHandler = new Handler();
protected int mLastXTouchPos;
diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java
index 033fc9c..9e4fb82 100644
--- a/src/com/android/camera/MenuHelper.java
+++ b/src/com/android/camera/MenuHelper.java
@@ -23,12 +23,14 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
+import android.provider.MediaStore;
import android.util.Config;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
+import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
@@ -39,16 +41,18 @@ import android.widget.Toast;
import java.util.ArrayList;
+import com.android.camera.ImageManager.IImage;
+
public class MenuHelper {
static private final String TAG = "MenuHelper";
-
+
static public final int GENERIC_ITEM = 1;
static public final int IMAGE_SAVING_ITEM = 2;
static public final int VIDEO_SAVING_ITEM = 3;
static public final int IMAGE_MODE_ITEM = 4;
static public final int VIDEO_MODE_ITEM = 5;
static public final int MENU_ITEM_MAX = 5;
-
+
static public final int INCLUDE_ALL = 0xFFFFFFFF;
static public final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
static public final int INCLUDE_SHARE_MENU = (1 << 1);
@@ -57,84 +61,52 @@ public class MenuHelper {
static public final int INCLUDE_DELETE_MENU = (1 << 4);
static public final int INCLUDE_ROTATE_MENU = (1 << 5);
static public final int INCLUDE_DETAILS_MENU = (1 << 5);
-
+
+ static public final int MENU_SWITCH_CAMERA_MODE = 0;
+ static public final int MENU_CAPTURE_PICTURE = 1;
+ static public final int MENU_CAPTURE_VIDEO = 2;
static public final int MENU_IMAGE_SHARE = 10;
- static public final int MENU_IMAGE_SHARE_EMAIL = 11;
- static public final int MENU_IMAGE_SHARE_MMS = 12;
- static public final int MENU_IMAGE_SHARE_PICASA =13;
static public final int MENU_IMAGE_SET = 14;
static public final int MENU_IMAGE_SET_WALLPAPER = 15;
static public final int MENU_IMAGE_SET_CONTACT = 16;
static public final int MENU_IMAGE_SET_MYFAVE = 17;
static public final int MENU_IMAGE_CROP = 18;
static public final int MENU_IMAGE_ROTATE = 19;
- static public final int MENU_IMAGE_ROTATE_LEFT = 20;
+ static public final int MENU_IMAGE_ROTATE_LEFT = 20;
static public final int MENU_IMAGE_ROTATE_RIGHT = 21;
static public final int MENU_IMAGE_TOSS = 22;
static public final int MENU_VIDEO_PLAY = 23;
static public final int MENU_VIDEO_SHARE = 24;
- static public final int MENU_VIDEO_SHARE_MMS = 25;
- static public final int MENU_VIDEO_SHARE_YOUTUBE = 26;
static public final int MENU_VIDEO_TOSS = 27;
- static public final int MENU_IMAGE_SHARE_PICASA_ALL =28;
-
+
public interface MenuItemsResult {
public void gettingReadyToOpen(Menu menu, ImageManager.IImage image);
public void aboutToCall(MenuItem item, ImageManager.IImage image);
}
-
+
public interface MenuInvoker {
public void run(MenuCallback r);
}
-
+
public interface MenuCallback {
public void run(Uri uri, ImageManager.IImage image);
}
static MenuItemsResult addImageMenuItems(
- Menu menu,
+ Menu menu,
int inclusions,
+ final boolean isImage,
final Activity activity,
final Handler handler,
final Runnable onDelete,
final MenuInvoker onInvoke) {
- final ArrayList<MenuItem> requiresWriteAccessItems = new ArrayList<MenuItem>();
- final ArrayList<MenuItem> requiresNoDrmAccessItems = new ArrayList<MenuItem>();
- if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
- if (Config.LOGV)
- Log.v(TAG, ">>>>> add share");
- MenuItem item = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
- R.string.camera_share).setOnMenuItemClickListener(
- new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- onInvoke.run(new MenuCallback() {
- public void run(Uri u, ImageManager.IImage image) {
- if (image == null)
- return;
-
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_SEND);
- intent.setType(image.getMimeType());
- intent.putExtra(Intent.EXTRA_STREAM, u);
- try {
- activity.startActivity(Intent.createChooser(intent,
- activity.getText(R.string.sendImage)));
- } catch (android.content.ActivityNotFoundException ex) {
- Toast.makeText(activity, R.string.no_way_to_share_image, Toast.LENGTH_SHORT).show();
- }
- }
- });
- return true;
- }
- });
- item.setIcon(android.R.drawable.ic_menu_share);
- requiresNoDrmAccessItems.add(item);
- }
+ final ArrayList<MenuItem> requiresWriteAccessItems = new ArrayList<MenuItem>();
+ final ArrayList<MenuItem> requiresNoDrmAccessItems = new ArrayList<MenuItem>();
- if ((inclusions & INCLUDE_ROTATE_MENU) != 0) {
+ if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM, MENU_IMAGE_ROTATE,
40, R.string.rotate).setIcon(android.R.drawable.ic_menu_rotate);
- // Don't show the rotate submenu if the item at hand is read only
+ // Don't show the rotate submenu if the item at hand is read only
// since the items within the submenu won't be shown anyway. This is
// really a framework bug in that it shouldn't show the submenu if
// the submenu has no visible items.
@@ -158,7 +130,7 @@ public class MenuHelper {
public void run(Uri u, ImageManager.IImage image) {
if (image == null || image.isReadonly())
return;
-
+
image.rotateImageBy(90);
}
});
@@ -167,21 +139,8 @@ public class MenuHelper {
}).setAlphabeticShortcut('r'));
}
}
-
- if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
- MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS, 70, R.string.camera_toss);
- requiresWriteAccessItems.add(deleteItem);
- deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- deletePhoto(activity, onDelete);
- return true;
- }
- })
- .setAlphabeticShortcut('d')
- .setIcon(android.R.drawable.ic_menu_delete);
- }
-
- if ((inclusions & INCLUDE_CROP_MENU) != 0) {
+
+ if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
R.string.camera_crop).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@@ -190,7 +149,7 @@ public class MenuHelper {
public void run(Uri u, ImageManager.IImage image) {
if (u == null)
return;
-
+
Intent cropIntent = new Intent();
cropIntent.setClass(activity, CropImage.class);
cropIntent.setData(u);
@@ -203,8 +162,8 @@ public class MenuHelper {
autoCrop.setIcon(android.R.drawable.ic_menu_crop);
requiresWriteAccessItems.add(autoCrop);
}
-
- if ((inclusions & INCLUDE_SET_MENU) != 0) {
+
+ if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75, R.string.camera_set);
setMenu.setIcon(android.R.drawable.ic_menu_set_as);
@@ -214,7 +173,7 @@ public class MenuHelper {
public void run(Uri u, ImageManager.IImage image) {
if (u == null || image == null)
return;
-
+
if (Config.LOGV)
Log.v(TAG, "in callback u is " + u + "; mime type is " + image.getMimeType());
Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
@@ -228,6 +187,56 @@ public class MenuHelper {
});
}
+ if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
+ if (Config.LOGV)
+ Log.v(TAG, ">>>>> add share");
+ MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
+ R.string.camera_share).setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ onInvoke.run(new MenuCallback() {
+ public void run(Uri u, ImageManager.IImage image) {
+ if (image == null)
+ return;
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_SEND);
+ String mimeType = image.getMimeType();
+ intent.setType(mimeType);
+ intent.putExtra(Intent.EXTRA_STREAM, u);
+ boolean isImage = ImageManager.isImageMimeType(mimeType);
+ try {
+ activity.startActivity(Intent.createChooser(intent,
+ activity.getText(
+ isImage ? R.string.sendImage : R.string.sendVideo)));
+ } catch (android.content.ActivityNotFoundException ex) {
+ Toast.makeText(activity,
+ isImage ? R.string.no_way_to_share_image
+ : R.string.no_way_to_share_video,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ return true;
+ }
+ });
+ item1.setIcon(android.R.drawable.ic_menu_share);
+ MenuItem item = item1;
+ requiresNoDrmAccessItems.add(item);
+ }
+
+ if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
+ MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS, 70, R.string.camera_toss);
+ requiresWriteAccessItems.add(deleteItem);
+ deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ deleteImageImpl(activity, onDelete, isImage);
+ return true;
+ }
+ })
+ .setAlphabeticShortcut('d')
+ .setIcon(android.R.drawable.ic_menu_delete);
+ }
+
if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -237,9 +246,9 @@ public class MenuHelper {
return;
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-
+
final View d = View.inflate(activity, R.layout.detailsview, null);
-
+
ImageView imageView = (ImageView) d.findViewById(R.id.details_thumbnail_image);
imageView.setImageBitmap(image.miniThumbBitmap());
@@ -250,8 +259,8 @@ public class MenuHelper {
String lengthString = "";
try {
long length = data.available();
- lengthString =
- android.content.Formatter.formatFileSize(activity, length);
+ lengthString =
+ android.text.format.Formatter.formatFileSize(activity, length);
data.close();
} catch (java.io.IOException ex) {
@@ -260,9 +269,14 @@ public class MenuHelper {
((TextView)d.findViewById(R.id.details_attrname_1)).setText(R.string.details_file_size);
((TextView)d.findViewById(R.id.details_attrvalu_1)).setText(lengthString);
- String dimensionsString = String.valueOf(image.getWidth() + " X " + image.getHeight());
- ((TextView)d.findViewById(R.id.details_attrname_2)).setText(R.string.details_image_resolution);
- ((TextView)d.findViewById(R.id.details_attrvalu_2)).setText(dimensionsString);
+ if (isImage) {
+ String dimensionsString = String.valueOf(image.getWidth() + " X " + image.getHeight());
+ ((TextView)d.findViewById(R.id.details_attrname_2)).setText(R.string.details_image_resolution);
+ ((TextView)d.findViewById(R.id.details_attrvalu_2)).setText(dimensionsString);
+ } else {
+ d.findViewById(R.id.details_attrname_2).setVisibility(View.GONE);
+ d.findViewById(R.id.details_attrvalu_2).setVisibility(View.GONE);
+ }
String dateString = "";
long dateTaken = image.getDateTaken();
@@ -270,19 +284,19 @@ public class MenuHelper {
java.util.Date date = new java.util.Date(image.getDateTaken());
java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat();
dateString = dateFormat.format(date);
-
+
((TextView)d.findViewById(R.id.details_attrname_3)).setText(R.string.details_date_taken);
((TextView)d.findViewById(R.id.details_attrvalu_3)).setText(dateString);
} else {
d.findViewById(R.id.details_daterow).setVisibility(View.GONE);
}
-
+
builder.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.details_panel_title)
.setView(d)
.show();
-
+
}
});
return true;
@@ -290,7 +304,23 @@ public class MenuHelper {
});
detailsMenu.setIcon(R.drawable.ic_menu_view_details);
}
-
+
+ if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
+ menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
+ .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ onInvoke.run(new MenuCallback() {
+ public void run(Uri uri, IImage image) {
+ Intent intent = new Intent(Intent.ACTION_VIEW,
+ image.fullSizeImageUri());
+ activity.startActivity(intent);
+ }});
+ return true;
+ }
+ });
+ }
+
+
return new MenuItemsResult() {
public void gettingReadyToOpen(Menu menu, ImageManager.IImage image) {
// protect against null here. this isn't strictly speaking required
@@ -321,94 +351,25 @@ public class MenuHelper {
};
}
- static MenuItemsResult addVideoMenuItems(
- Menu menu,
- int inclusions,
- final Activity activity,
- final Handler handler,
- final SelectedImageGetter mGetter,
- final Runnable onDelete,
- final Runnable preWork,
- final Runnable postWork) {
-
- if ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0) {
- menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- if (preWork != null)
- preWork.run();
-
- Intent intent = new Intent(Intent.ACTION_VIEW, mGetter.getCurrentImageUri());
- activity.startActivity(intent);
-
- // don't do the postWork since we're launching another activity
- return true;
- }
- });
- }
-
- if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
- MenuItem item = menu.add(VIDEO_SAVING_ITEM, 0, 0, R.string.camera_share).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- Uri u = mGetter.getCurrentImageUri();
- if (u == null)
- return true;
-
- if (preWork != null)
- preWork.run();
-
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_SEND);
- intent.setType(mGetter.getCurrentImage().getMimeType());
- intent.putExtra(Intent.EXTRA_STREAM, u);
- try {
- activity.startActivity(Intent.createChooser(intent,
- activity.getText(R.string.sendVideo)));
- } catch (android.content.ActivityNotFoundException ex) {
- Toast.makeText(activity, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show();
-
- if (postWork != null)
- postWork.run();
- }
- return true;
- }
- });
- item.setIcon(android.R.drawable.ic_menu_share);
- }
-
- if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
- MenuItem deleteMenu = menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_TOSS, 0, R.string.camera_toss).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- if (preWork != null)
- preWork.run();
-
- activity.getContentResolver().delete(mGetter.getCurrentImageUri(), null, null);
-
- if (onDelete != null)
- onDelete.run();
-
- if (postWork != null)
- postWork.run();
-
- return true;
- }
- });
- deleteMenu.setIcon(android.R.drawable.ic_menu_delete);
- deleteMenu.setAlphabeticShortcut('d');
- }
+ static void deletePhoto(Activity activity, Runnable onDelete) {
+ deleteImageImpl(activity, onDelete, true);
+ }
- return null;
+ static void deleteImage(Activity activity, Runnable onDelete, IImage image) {
+ deleteImageImpl(activity, onDelete, ImageManager.isImage(image));
}
-
- static void deletePhoto(Activity activity, final Runnable onDelete) {
+
+ private static void deleteImageImpl(Activity activity, final Runnable onDelete, boolean isPhoto) {
boolean confirm = android.preference.PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("pref_gallery_confirm_delete_key", true);
if (!confirm) {
if (onDelete != null)
onDelete.run();
} else {
android.app.AlertDialog.Builder b = new android.app.AlertDialog.Builder(activity);
- b.setIcon(R.drawable.delete_image);
+ b.setIcon(android.R.drawable.ic_dialog_alert);
b.setTitle(R.string.confirm_delete_title);
- b.setMessage(R.string.confirm_delete_message);
+ b.setMessage(isPhoto? R.string.confirm_delete_message
+ : R.string.confirm_delete_video_message);
b.setPositiveButton(android.R.string.ok, new android.content.DialogInterface.OnClickListener() {
public void onClick(android.content.DialogInterface v, int x) {
if (onDelete != null)
@@ -423,7 +384,62 @@ public class MenuHelper {
b.create().show();
}
}
-
+
+ static void addSwitchModeMenuItem(Menu menu, final Activity activity,
+ final boolean switchToVideo) {
+ int group = switchToVideo ? MenuHelper.IMAGE_MODE_ITEM : MenuHelper.VIDEO_MODE_ITEM;
+ int labelId = switchToVideo ? R.string.switch_to_video_lable
+ : R.string.switch_to_camera_lable;
+ int iconId = switchToVideo ? R.drawable.ic_menu_camera_video_view
+ : R.drawable.ic_menu_camera;
+ MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0,
+ labelId).setOnMenuItemClickListener(
+ new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ String action = switchToVideo ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
+ : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
+ Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ activity.finish();
+ activity.startActivity(intent);
+ return true;
+ }
+ });
+ item.setIcon(iconId);
+ }
+
+ static void addCaptureMenuItems(Menu menu, final Activity activity) {
+
+ menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
+ .setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ try {
+ activity.startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ // Ignore exception
+ }
+ return true;
+ }
+ })
+ .setIcon(R.drawable.ic_menu_camera);
+
+ menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
+ .setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+ try {
+ activity.startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ // Ignore exception
+ }
+ return true;
+ }
+ })
+ .setIcon(R.drawable.ic_menu_camera_video_view);
+ }
static MenuItem addFlipOrientation(Menu menu, final Activity activity, final SharedPreferences prefs) {
// position 41 after rotate
return menu
@@ -457,65 +473,5 @@ public class MenuHelper {
? android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER
: req);
}
-
- static public class YouTubeUploadInfoDialog extends Dialog {
- private CheckBox mPrivate;
- private ImageManager.VideoObject mVideo;
- private EditText mTitle;
- private EditText mTags;
- private EditText mDescription;
- private Spinner mCategory;
- private Button mUpload;
-
- public YouTubeUploadInfoDialog(final Activity activity,
- final ArrayList<String> categoriesShort,
- final ArrayList<String> categoriesLong,
- ImageManager.VideoObject video,
- final Runnable postRunnable) {
- super(activity, android.R.style.Theme_Dialog);
- mVideo = video;
- setContentView(R.layout.youtube_upload_info);
- setTitle(R.string.upload_dialog_title);
-
- mPrivate = (CheckBox)findViewById(R.id.public_or_private);
- if (!mPrivate.isChecked()) {
- mPrivate.setChecked(true);
- }
-
- mTitle = (EditText)findViewById(R.id.video_title);
- mTags = (EditText)findViewById(R.id.video_tags);
- mDescription = (EditText)findViewById(R.id.video_description);
- mCategory = (Spinner)findViewById(R.id.category);
-
- if (Config.LOGV)
- Log.v(TAG, "setting categories in adapter");
- android.widget.ArrayAdapter<String> categories = new android.widget.ArrayAdapter<String>(activity, android.R.layout.simple_spinner_item, categoriesLong);
- categories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mCategory.setAdapter(categories);
-
- if (mVideo != null) {
- mTitle.setText(mVideo.getTitle());
- mTags.setText(mVideo.getTags());
- mDescription.setText(mVideo.getDescription());
- }
-
- mUpload = (Button)findViewById(R.id.do_upload);
- mUpload.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v)
- {
- if (mVideo != null) {
- mVideo.setName(mTitle.getText().toString());
- mVideo.setDescription(mDescription.getText().toString());
- mVideo.setTags(mTags.getText().toString());
- }
-
- YouTubeUploadInfoDialog.this.dismiss();
- UploadAction.uploadImage(activity, mVideo);
- if (postRunnable != null)
- postRunnable.run();
- }
- });
- }
- }
}
diff --git a/src/com/android/camera/MovieView.java b/src/com/android/camera/MovieView.java
new file mode 100644
index 0000000..58e80df
--- /dev/null
+++ b/src/com/android/camera/MovieView.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 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.app.Activity;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.MediaStore;
+import android.view.View;
+import android.widget.MediaController;
+import android.widget.VideoView;
+
+public class MovieView extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener
+{
+ private static final String TAG = "MovieView";
+ // Copied from MediaPlaybackService in the Music Player app. Should be public, but isn't.
+ private static final String SERVICECMD = "com.android.music.musicservicecommand";
+ private static final String CMDNAME = "command";
+ private static final String CMDPAUSE = "pause";
+
+ private VideoView mVideoView;
+ private View mProgressView;
+ private boolean mFinishOnCompletion;
+ public MovieView()
+ {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.movie_view);
+
+ mVideoView = (VideoView) findViewById(R.id.surface_view);
+ mProgressView = findViewById(R.id.progress_indicator);
+ Intent intent = getIntent();
+ if (intent.hasExtra(MediaStore.EXTRA_SCREEN_ORIENTATION)) {
+ int orientation = intent.getIntExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
+ ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ if (orientation != getRequestedOrientation()) {
+ setRequestedOrientation(orientation);
+ }
+ }
+ mFinishOnCompletion = intent.getBooleanExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, true);
+ Uri uri = intent.getData();
+
+ // For streams that we expect to be slow to start up, show a
+ // progress spinner until playback starts.
+ String scheme = uri.getScheme();
+ if ("http".equalsIgnoreCase(scheme) ||
+ "rtsp".equalsIgnoreCase(scheme)) {
+ mHandler.postDelayed(mPlayingChecker, 250);
+ } else {
+ mProgressView.setVisibility(View.GONE);
+ }
+
+ mVideoView.setOnErrorListener(this);
+ mVideoView.setOnCompletionListener(this);
+ mVideoView.setVideoURI(uri);
+ mVideoView.setMediaController(new MediaController(this));
+ mVideoView.requestFocus(); // make the video view handle keys for seeking and pausing
+
+ Intent i = new Intent(SERVICECMD);
+ i.putExtra(CMDNAME, CMDPAUSE);
+ sendBroadcast(i);
+
+ mVideoView.start();
+ }
+
+ @Override
+ public void onPause() {
+ mHandler.removeCallbacksAndMessages(null);
+ super.onPause();
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ }
+ };
+
+ Runnable mPlayingChecker = new Runnable() {
+ public void run() {
+ if (mVideoView.isPlaying()) {
+ mProgressView.setVisibility(View.GONE);
+ } else {
+ mHandler.postDelayed(mPlayingChecker, 250);
+ }
+ }
+ };
+
+ public boolean onError(MediaPlayer player, int arg1, int arg2) {
+ mHandler.removeCallbacksAndMessages(null);
+ mProgressView.setVisibility(View.GONE);
+ return false;
+ }
+
+ public void onCompletion(MediaPlayer mp) {
+ if (mFinishOnCompletion) {
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/camera/PwaUpload.java b/src/com/android/camera/PwaUpload.java
deleted file mode 100644
index 8df08df..0000000
--- a/src/com/android/camera/PwaUpload.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2006 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.content.Intent;
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.net.Uri;
-
-/**
- *
- */
-public class PwaUpload extends Activity
-{
- private static final String TAG = "camera";
-
- @Override public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- ImageManager.IImageList imageList = ImageManager.instance().allImages(
- this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_IMAGES|ImageManager.INCLUDE_VIDEOS,
- ImageManager.SORT_ASCENDING);
- Uri uri = (Uri) getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
- if (android.util.Config.LOGV)
- Log.v(TAG, "uri is " + uri);
- ImageManager.IImage imageObj = imageList.getImageForUri(uri);
-
- if (android.util.Config.LOGV)
- Log.v(TAG, "imageObj is " + imageObj);
- if (imageObj != null) {
- UploadAction.uploadImage(this, imageObj);
- }
- finish();
- }
-
- @Override public void onResume() {
- super.onResume();
- }
-}
diff --git a/src/com/android/camera/SlideShow.java b/src/com/android/camera/SlideShow.java
index ee6c7be..2be99ac 100644
--- a/src/com/android/camera/SlideShow.java
+++ b/src/com/android/camera/SlideShow.java
@@ -60,21 +60,21 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
private int mCurrentPosition = 0;
private ImageView mSwitcher;
private boolean mPosted = false;
-
+
@Override
protected void onCreate(Bundle icicle)
{
super.onCreate(icicle);
Window wp = getWindow();
wp.setFlags(FLAG_KEEP_SCREEN_ON, FLAG_KEEP_SCREEN_ON);
-
+
setContentView(R.layout.slide_show);
-
+
mSwitcher = (ImageView)findViewById(R.id.imageview);
if (android.util.Config.LOGV)
Log.v(TAG, "mSwitcher " + mSwitcher);
}
-
+
@Override
protected void onResume()
{
@@ -86,13 +86,13 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
}
loadImage();
}
-
+
@Override
protected void onPause() {
super.onPause();
cancelPost();
}
-
+
static public class ImageViewTouch extends ImageView {
class xy {
public xy(float xIn, float yIn) {
@@ -108,26 +108,26 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
float x,y;
long timeAdded;
}
-
+
SlideShow mSlideShow;
Paint mPaints[] = new Paint[1];
ArrayList<xy> mPoints = new ArrayList<xy>();
boolean mDown;
-
+
public ImageViewTouch(Context context) {
super(context);
mSlideShow = (SlideShow) context;
setScaleType(ImageView.ScaleType.CENTER);
setupPaint();
}
-
+
public ImageViewTouch(Context context, AttributeSet attrs) {
super(context, attrs);
mSlideShow = (SlideShow) context;
setScaleType(ImageView.ScaleType.CENTER);
setupPaint();
}
-
+
private void setupPaint() {
for (int i = 0; i < mPaints.length; i++) {
Paint p = new Paint();
@@ -138,7 +138,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
mPaints[i] = p;
}
}
-
+
private void addEvent(MotionEvent event) {
long now = System.currentTimeMillis();
mPoints.add(new xy(event));
@@ -151,7 +151,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
mPoints.remove(0);
}
}
-
+
public boolean onTouchEvent(MotionEvent event) {
addEvent(event);
switch (event.getAction()) {
@@ -182,7 +182,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
long delta = now - ev.timeAdded;
if (delta > sLag)
continue;
-
+
int alpha2 = Math.max(0, 255 - (255 * (int)delta / sLag));
if (alpha2 == 0)
continue;
@@ -195,7 +195,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
}
}
-
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
@@ -203,14 +203,14 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
cancelPost();
loadPreviousImage();
return true;
-
+
case KeyEvent.KEYCODE_DPAD_RIGHT:
cancelPost();
loadNextImage();
return true;
-
+
case KeyEvent.KEYCODE_DPAD_CENTER:
- if (mPosted)
+ if (mPosted)
cancelPost();
else
loadNextImage();
@@ -218,12 +218,12 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
}
return super.onKeyDown(keyCode, event);
}
-
+
private void cancelPost() {
mHandler.removeCallbacks(mNextImageRunnable);
mPosted = false;
}
-
+
private void post() {
mHandler.postDelayed(mNextImageRunnable, sNextImageInterval);
mPosted = true;
@@ -233,7 +233,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
ImageManager.IImage image = mImageList.getImageAt(mCurrentPosition);
if (image == null)
return;
-
+
Bitmap bitmap = image.thumbBitmap();
if (bitmap == null)
return;
@@ -241,7 +241,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
mSwitcher.setImageDrawable(new BitmapDrawable(bitmap));
post();
}
-
+
private Runnable mNextImageRunnable = new Runnable() {
public void run() {
if (android.util.Config.LOGV)
@@ -249,13 +249,13 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
loadNextImage();
}
};
-
+
private void loadNextImage() {
if (++mCurrentPosition >= mImageList.getCount())
mCurrentPosition = 0;
loadImage();
}
-
+
private void loadPreviousImage() {
if (mCurrentPosition == 0)
mCurrentPosition = mImageList.getCount() - 1;
@@ -272,7 +272,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
i.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
return i;
}
-
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -286,22 +286,22 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
public void checkThumbnails(ThumbCheckCallback cb) {
// TODO Auto-generated method stub
-
+
}
public void commitChanges() {
// TODO Auto-generated method stub
-
+
}
public void removeOnChangeListener(OnChange changeCallback) {
// TODO Auto-generated method stub
-
+
}
public void setOnChangeListener(OnChange changeCallback, Handler h) {
// TODO Auto-generated method stub
-
+
}
private ArrayList<FileImage> mImages = new ArrayList<FileImage>();
@@ -320,7 +320,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
public long imageId() {
return mId;
}
-
+
public String getDataPath() {
return mPath;
}
@@ -332,7 +332,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
public IGetBitmap_cancelable fullSizeBitmap_cancelable(int targetWidthOrHeight) {
return null;
}
-
+
public Bitmap thumbBitmap() {
Bitmap b = fullSizeBitmap(320);
Matrix m = new Matrix();
@@ -341,7 +341,7 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
Bitmap scaledBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
return scaledBitmap;
}
-
+
public Bitmap miniThumbBitmap() {
return thumbBitmap();
}
@@ -416,7 +416,11 @@ public class SlideShow extends Activity implements ViewSwitcher.ViewFactory
public int getCount() {
return mImages.size();
}
-
+
+ public boolean isEmpty() {
+ return mImages.isEmpty();
+ }
+
public void deactivate() {
// nothing to do here
}
diff --git a/src/com/android/camera/UploadAction.java b/src/com/android/camera/UploadAction.java
deleted file mode 100644
index 41cc351..0000000
--- a/src/com/android/camera/UploadAction.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2007 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.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Config;
-import android.util.Log;
-
-public class UploadAction {
- static private final String TAG = "UploadAction";
-
- static public void uploadImage(Activity activity, ImageManager.IImage image) {
- Bundle args = new Bundle();
- if (image != null)
- args.putString("imageuri", image.fullSizeImageUri().toString());
- activity.startService(new Intent(activity, UploadService.class).putExtras(args));
- }
-}
diff --git a/src/com/android/camera/UploadService.java b/src/com/android/camera/UploadService.java
deleted file mode 100644
index 9c7d2b0..0000000
--- a/src/com/android/camera/UploadService.java
+++ /dev/null
@@ -1,1181 +0,0 @@
-/*
- * Copyright (C) 2006 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 com.android.camera.ImageManager.IImage;
-import com.android.internal.http.multipart.Part;
-import com.android.internal.http.multipart.MultipartEntity;
-import com.android.internal.http.multipart.PartBase;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.preference.PreferenceManager;
-import android.sax.Element;
-import android.sax.ElementListener;
-import android.sax.EndTextElementListener;
-import android.sax.RootElement;
-import android.util.Config;
-import android.util.Log;
-import android.util.Xml;
-
-import com.google.android.googleapps.GoogleLoginCredentialsResult;
-import com.google.android.googlelogin.GoogleLoginServiceBlockingHelper;
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-import com.google.android.googlelogin.GoogleLoginServiceNotFoundException;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-import android.net.http.AndroidHttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpGet;
-import com.android.internal.http.multipart.StringPart;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EncodingUtils;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class UploadService extends Service implements Runnable {
- private static final String TAG = "UploadService";
-
- static final boolean DEBUG = false;
- private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
-
- private GoogleLoginServiceBlockingHelper mGls;
- static public final int MSG_STATUS = 3;
- static public final int EVENT_UPLOAD_ERROR = 400;
-
- static public final String sPicasaService = "lh2";
- static public final String sYouTubeService = "youtube";
- static public final String sYouTubeUserService = "YouTubeUser";
-
- static public final String sUploadAlbumName = "android_upload";
- HashMap<String, Album> mAlbums;
- ArrayList<String> mAndroidUploadAlbumPhotos = null;
- HashMap<String, String> mGDataAuthTokenMap = new HashMap<String, String>();
-
- int mStartId;
- Thread mThread;
-
- android.os.Handler mHandler = new android.os.Handler() {
-
- };
-
- ArrayList<Runnable> mStatusListeners = new ArrayList<Runnable>();
-
- ArrayList<Uri> mUploadList = new ArrayList<Uri>();
-
- ImageManager.IImageList mImageList = null;
-
- String mPicasaUsername;
- String mPicasaAuthToken;
- String mYouTubeUsername;
- String mYouTubeAuthToken;
-
- AndroidHttpClient mClient = AndroidHttpClient.newInstance("Android-Camera/0.1");
-
- private static final ComponentName sLogin = new ComponentName(
- "com.google.android.googleapps",
- "com.google.android.googleapps.GoogleLoginService");
-
- public UploadService() {
- if (LOCAL_LOGV)
- Log.v(TAG, "UploadService Constructor !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
- }
-
- private void computeAuthToken() {
- if (LOCAL_LOGV) Log.v(TAG, "computeAuthToken()");
- if (mPicasaAuthToken != null) return;
-
- try {
- String account = mGls.getAccount(GoogleLoginServiceConstants.REQUIRE_GOOGLE);
- GoogleLoginCredentialsResult result =
- mGls.getCredentials(account, sPicasaService, true);
- mPicasaAuthToken = result.getCredentialsString();
- mPicasaUsername = result.getAccount();
- if (Config.LOGV)
- Log.v(TAG, "mPicasaUsername is " + mPicasaUsername);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not get auth token", e);
- }
- }
-
- private void computeYouTubeAuthToken() {
- if (LOCAL_LOGV) Log.v(TAG, "computeYouTubeAuthToken()");
- if (mYouTubeAuthToken != null) return;
-
- try {
- String account = mGls.getAccount(GoogleLoginServiceConstants.REQUIRE_GOOGLE);
- GoogleLoginCredentialsResult result =
- mGls.getCredentials(account, sYouTubeService, true);
- mYouTubeAuthToken = result.getCredentialsString();
- mYouTubeUsername = result.getAccount();
- if (mYouTubeAuthToken.equals("NoLinkedYouTubeAccount")) {
- // we successfully logged in to the google account, but it
- // is not linked to a YouTube username.
- if (Config.LOGV)
- Log.v(TAG, "account " + mYouTubeUsername + " is not linked to a youtube account");
- mYouTubeAuthToken = null;
- return;
- }
-
- mYouTubeUsername = mGls.peekCredentials(mYouTubeUsername, sYouTubeUserService);
- // now mYouTubeUsername is the YouTube username linked to the
- // google account, which is probably what we want to display.
-
- if (Config.LOGV)
- Log.v(TAG, "3 mYouTubeUsername: " + mYouTubeUsername);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not get auth token", e);
- }
- }
-
- NotificationManager mNotificationManager;
-
- @Override
- public void onCreate() {
-
- try {
- mGls = new GoogleLoginServiceBlockingHelper(this);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not find google login service, stopping service");
- stopSelf();
- }
-
- if (mThread == null) {
- mThread = new Thread(this);
- mThread.start();
- }
- mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
-
- IntentFilter intentFilter = new IntentFilter("com.android.camera.NEW_PICTURE");
- b = new android.content.BroadcastReceiver() {
- public void onReceive(android.content.Context ctx, Intent intent) {
- android.content.SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
- if (prefs.getBoolean("pref_camera_autoupload_key", false)) {
- if (Config.LOGV)
- Log.v(TAG, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> auto upload " + intent.getData());
- }
- }
- };
- registerReceiver(b, intentFilter);
- }
-
- android.content.BroadcastReceiver b = null;
-
- @Override
- public void onDestroy() {
- mGls.close();
- if (b != null) {
- unregisterReceiver(b);
- }
- }
-
- @Override
- public void onStart(Intent intent, int startId) {
- if (LOCAL_LOGV)
- Log.v(TAG, "UploadService.onStart; this is " + hashCode());
-
- if (mImageList == null) {
- mImageList = ImageManager.instance().allImages(
- this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS,
- ImageManager.SORT_ASCENDING);
- mImageList.setOnChangeListener(new ImageManager.IImageList.OnChange() {
- public void onChange(ImageManager.IImageList list) {
- /*
- Log.v(TAG, "onChange <<<<<<<<<<<<<<<<<<<<<<<<<");
- for (int i = 0; i < list.getCount(); i++) {
- ImageManager.IImage img = list.getImageAt(i);
- Log.v(TAG, "pos " + i + " " + img.fullSizeImageUri());
- String picasaId = img.getPicasaId();
- if (picasaId == null || picasaId.length() == 0) {
- synchronized (mUploadList) {
- Uri uri = img.fullSizeImageUri();
- if (mUploadList.contains(uri)) {
- mUploadList.add(img.fullSizeImageUri());
- mUploadList.notify();
- }
- }
- }
- }
- */
- }
- }, mHandler);
- }
-
- if (LOCAL_LOGV)
- Log.v(TAG, "got image list with count " + mImageList.getCount());
-
- synchronized (mUploadList) {
- mStartId = startId;
- String uriString = intent.getStringExtra("imageuri");
-
- if (LOCAL_LOGV)
- Log.v(TAG, "starting UploadService; startId = " + startId + " start uri: " + uriString);
-
- if (uriString != null) {
- Uri uri = Uri.parse(uriString);
- IImage image = mImageList.getImageForUri(uri);
- if (!mUploadList.contains(uri)) {
- if (LOCAL_LOGV)
- Log.v(TAG, "queing upload of " + image.fullSizeImageUri());
- mUploadList.add(uri);
- }
- } else {
- // for now upload all applies to images only, not videos
- for (int i = 0; i < mImageList.getCount(); i++) {
- IImage image = mImageList.getImageAt(i);
- if (image instanceof ImageManager.Image) {
- Uri uri = image.fullSizeImageUri();
- if (!mUploadList.contains(uri)) {
- if (LOCAL_LOGV)
- Log.v(TAG, "queing upload of " + image.fullSizeImageUri());
- mUploadList.add(uri);
- }
- }
- }
- }
- updateNotification();
- }
-
- synchronized(mUploadList) {
- mUploadList.notify();
- }
- }
-
- void updateNotification() {
- int videosCount = 0, imagesCount = 0;
- for (int i = 0;i < mUploadList.size(); i++) {
- // TODO yes this is a hack
- Uri uri = mUploadList.get(i);
- if (uri.toString().contains("video"))
- videosCount += 1;
- else
- imagesCount += 1;
- }
- updateNotification(imagesCount, videosCount);
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- // This is the object that recieves interactions from clients.
- private final IBinder mBinder = new Binder() {
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
- return true;
- }
- };
-
- private void updateNotification(int pendingImagesCount, int pendingVideosCount) {
- final int mVideoUploadId = 1;
- final int mImageUploadId = 2;
- if (pendingImagesCount == 0) {
- if (mNotificationManager != null)
- mNotificationManager.cancel(mImageUploadId);
- } else {
- String detailedMsg = String.format(getResources().getString(R.string.uploadingNPhotos), pendingImagesCount);
- Notification n = new Notification(
- this,
- android.R.drawable.stat_sys_upload,
- getResources().getString(R.string.uploading_photos),
- System.currentTimeMillis(),
- getResources().getString(R.string.uploading_photos_2),
- detailedMsg,
- null);
- mNotificationManager.notify(mImageUploadId, n);
- }
- if (pendingVideosCount == 0) {
- if (mNotificationManager != null)
- mNotificationManager.cancel(mVideoUploadId);
- } else {
- String detailedMsg = String.format(getResources().getString(R.string.uploadingNVideos), pendingImagesCount);
- Notification n = new Notification(
- this,
- android.R.drawable.stat_sys_upload,
- getResources().getString(R.string.uploading_videos),
- System.currentTimeMillis(),
- getResources().getString(R.string.uploading_videos_2),
- detailedMsg,
- null);
- mNotificationManager.notify(mVideoUploadId, n);
- }
- }
-
- public void run() {
- try {
- if (Config.LOGV)
- Log.v(TAG, "running upload thread...");
- while (true) {
- IImage image = null;
- synchronized (mUploadList) {
- if (LOCAL_LOGV)
- Log.v(TAG, "mUploadList.size() is " + mUploadList.size());
- if (mUploadList.size() == 0) {
- try {
- updateNotification(0, 0);
- if (Config.LOGV)
- Log.v(TAG, "waiting...");
- mUploadList.wait(60000);
- if (Config.LOGV)
- Log.v(TAG, "done waiting...");
- } catch (InterruptedException ex) {
- }
- if (mUploadList.size() == 0) {
-// if (LOCAL_LOGV) Log.v(TAG, "exiting run, stoping service");
-// stopSelf(mStartId);
-// break;
- continue;
- }
- }
- Uri uri = mUploadList.get(0);
- image = mImageList.getImageForUri(uri);
- if (Config.LOGV)
- Log.v(TAG, "got uri " + uri + " " + image);
- }
-
- boolean success = false;
- if (image != null) {
- updateNotification();
-
- long t1 = System.currentTimeMillis();
- success = uploadItem(image);
- long t2 = System.currentTimeMillis();
- if (LOCAL_LOGV) Log.v(TAG, "upload took " + (t2-t1) + "; success = " + success);
- }
-
- synchronized (mUploadList) {
- mUploadList.remove(0);
- if (!success && image != null) {
- mUploadList.add(image.fullSizeImageUri());
- }
- }
- if (!success) {
- int retryDelay = 30000;
- if (LOCAL_LOGV)
- Log.v(TAG, "failed to upload " + image.fullSizeImageUri() + " trying again in " + retryDelay + " ms");
- try {
- synchronized (mUploadList) {
- long t1x = System.currentTimeMillis();
- mUploadList.wait(retryDelay);
- long t2x = System.currentTimeMillis();
- if (Config.LOGV)
- Log.v(TAG, "retry waited " + (t2x-t1x));
- }
- } catch (InterruptedException ex) {
- if (Config.LOGV)
- Log.v(TAG, "ping, was waiting but now retry again");
- };
- }
- }
- } catch (Exception ex) {
- Log.e(TAG, "got exception in upload thread", ex);
- }
- finally {
- if (LOCAL_LOGV)
- Log.v(TAG, "finished task");
- }
- }
-
- private String getLatLongString(IImage image) {
- if (image.hasLatLong()) {
- return "<georss:where><gml:Point><gml:pos>"
- + image.getLatitude()
- + " "
- + image.getLongitude()
- + "</gml:pos></gml:Point></georss:where>";
- } else {
- return "";
- }
- }
-
- private String uploadAlbumName() {
- android.content.SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- String s = prefs.getString("pref_camera_upload_albumname_key", sUploadAlbumName);
- return s;
- }
-
- private boolean uploadItem(IImage image) {
- if (LOCAL_LOGV)
- Log.v(TAG, "starting work on " + image);
-
- if (image instanceof ImageManager.VideoObject) {
- if (LOCAL_LOGV)
- Log.v(TAG, "Uploading video");
- computeYouTubeAuthToken();
- return (new VideoUploadTask(image)).upload();
- } else {
- if (LOCAL_LOGV)
- Log.v(TAG, "Uploading photo");
-
- computeAuthToken();
- // handle photos
- if (mAlbums == null)
- mAlbums = getAlbums();
-
- String albumName = uploadAlbumName();
- if (mAlbums == null || !mAlbums.containsKey(albumName)) {
- Album a = createAlbum(albumName, uploadAlbumName());
- if (a == null) {
- return false;
- }
- if (LOCAL_LOGV)
- Log.v(TAG, "made new album: " + a.getAlbumName() + "; " + a.getAlbumId());
- mAlbums.put(a.getAlbumName(), a);
- }
-
- if (mAndroidUploadAlbumPhotos == null)
- mAndroidUploadAlbumPhotos = getAlbumContents(albumName);
-
- if (mAndroidUploadAlbumPhotos != null) {
- String previousUploadId = image.getPicasaId();
- if (previousUploadId != null) {
- if (mAndroidUploadAlbumPhotos.contains(previousUploadId)) {
- if (Config.LOGV)
- Log.v(TAG, "already have id " + previousUploadId);
- return true;
- }
- }
- }
- Album album = mAlbums.get(albumName);
- return (new ImageUploadTask(image)).upload(album);
- }
- }
-
-// void broadcastError(int error) {
-// HashMap map = new HashMap();
-// map.put("error", new Integer(error));
-//
-// Message send = Message.obtain();
-// send.what = EVENT_UPLOAD_ERROR;
-// send.setData(map);
-//
-// if (mBroadcaster == null) {
-// mBroadcaster = new Broadcaster();
-// }
-// mBroadcaster.broadcast(send);
-// }
-
- class Album {
- String mAlbumName;
-
- String mAlbumId;
-
- public Album() {
- }
-
- public void setAlbumName(String albumName) {
- mAlbumName = albumName;
- }
-
- public void setAlbumId(String albumId) {
- mAlbumId = albumId;
- }
-
- public String getAlbumName() {
- return mAlbumName;
- }
-
- public String getAlbumId() {
- return mAlbumId;
- }
- }
-
- static private String stringFromResponse(HttpResponse response) {
- try {
- HttpEntity entity = response.getEntity();
- InputStream inputStream = entity.getContent();
- StringWriter s = new StringWriter();
- while (true) {
- int c = inputStream.read();
- if (c == -1)
- break;
- s.write((char)c);
- }
- inputStream.close();
- String retval = s.toString();
- if (Config.LOGV)
- Log.v(TAG, "got resposne " + retval);
- return retval;
- } catch (Exception ex) {
- return null;
- }
- }
-
- abstract class UploadTask {
- IImage mImageObj;
-
- public UploadTask(IImage image) {
- mImageObj = image;
- }
-
- public class UploadResponse {
- private HttpResponse mStatus;
- private String mBody;
-
- public UploadResponse(HttpResponse status) {
- mStatus = status;
- mBody = stringFromResponse(status);
- }
-
- public int getStatus() {
- return mStatus.getStatusLine().getStatusCode();
- }
-
- public String getResponse() {
- return mBody;
- }
- }
-
- class StreamPart extends PartBase {
- InputStream mInputStream;
- long mLength;
-
- StreamPart(String name, InputStream inputStream, String contentType) {
- super(name,
- contentType == null ? "application/octet-stream" : contentType,
- "ISO-8859-1",
- "binary"
- );
- mInputStream = inputStream;
- try {
- mLength = inputStream.available();
- } catch (IOException ex) {
-
- }
- }
-
- @Override
- protected long lengthOfData() throws IOException {
- return mLength;
- }
-
- @Override
- protected void sendData(OutputStream out) throws IOException {
- byte [] buffer = new byte[4096];
- while (true) {
- int got = mInputStream.read(buffer);
- if (got == -1)
- break;
- out.write(buffer, 0, got);
- }
- mInputStream.close();
- }
-
- @Override
- protected void sendDispositionHeader(OutputStream out) throws IOException {
- }
-
- @Override
- protected void sendContentTypeHeader(OutputStream out) throws IOException {
- String contentType = getContentType();
- if (contentType != null) {
- out.write(CONTENT_TYPE_BYTES);
- out.write(EncodingUtils.getAsciiBytes(contentType));
- String charSet = getCharSet();
- if (charSet != null) {
- out.write(CHARSET_BYTES);
- out.write(EncodingUtils.getAsciiBytes(charSet));
- }
- }
- }
- }
-
- public class StringPartX extends StringPart {
- public StringPartX(String name, String value, String charset) {
- super(name, value, charset);
- setContentType("application/atom+xml");
- }
-
- @Override
- protected void sendDispositionHeader(OutputStream out) throws IOException {
- }
-
- @Override
- protected void sendContentTypeHeader(OutputStream out) throws IOException {
- String contentType = getContentType();
- if (contentType != null) {
- out.write(CONTENT_TYPE_BYTES);
- out.write(EncodingUtils.getAsciiBytes(contentType));
- String charSet = getCharSet();
- if (charSet != null) {
- out.write(CHARSET_BYTES);
- out.write(EncodingUtils.getAsciiBytes(charSet));
- }
- }
- }
- }
-
- public class MultipartEntityX extends MultipartEntity {
- public MultipartEntityX(Part[] parts, HttpParams params) {
- super(parts, params);
- }
-
- @Override
- public Header getContentType() {
- StringBuilder buffer = new StringBuilder();
- buffer.append("multipart/related; boundary=");
- buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
- return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
- }
-
- }
-
- protected UploadResponse doUpload(String uploadUrl,
- String mimeType,
- String data,
- IImage imageObj,
- String authToken,
- String title,
- String filename,
- boolean youTubeAuthenticate) {
- if (authToken == null)
- return null;
-
- FileInputStream inputStream = (FileInputStream)mImageObj.fullSizeImageData();
- try {
- HttpPost post = new HttpPost(uploadUrl);
- post.addHeader(new BasicHeader("Authorization", "GoogleLogin auth=" + authToken));
- if (youTubeAuthenticate) {
- // TODO: remove hardwired key? - This is our official YouTube issued developer key to Android.
- String youTubeDeveloperKey = "key=AI39si5Cr35CiD1IgDqD9Ua6N4dSbY-oibnLUPITmBN_rFW6qRz-hd8sTqNzRf1gzNwSYZbDuS31Txa4iKyjAV77507O4tq7JA";
- post.addHeader("X-GData-Key", youTubeDeveloperKey);
- post.addHeader("Slug", filename);
- }
-
- Part p1 = new StringPartX("param_name", data, null);
- Part p2 = new StreamPart("field_uploadfile", inputStream, mimeType);
-
- MultipartEntity mpe = new MultipartEntityX(new Part[] { p1, p2 }, post.getParams());
- post.setEntity(mpe);
- HttpResponse status = mClient.execute(post);
- if (LOCAL_LOGV) Log.v(TAG, "doUpload response is " + status.getStatusLine());
- return new UploadResponse(status);
- } catch (java.io.IOException ex) {
- if (LOCAL_LOGV) Log.v(TAG, "IOException in doUpload", ex);
- return null;
- }
- }
-
- class ResponseHandler implements ElementListener {
- private static final String ATOM_NAMESPACE
- = "http://www.w3.org/2005/Atom";
- private static final String PICASSA_NAMESPACE
- = "http://schemas.google.com/photos/2007";
-
- private ContentHandler mHandler = null;
- private String mId = null;
-
- public ResponseHandler() {
- RootElement root = new RootElement(ATOM_NAMESPACE, "entry");
- Element entry = root;
- entry.setElementListener(this);
-
- entry.getChild(PICASSA_NAMESPACE, "id")
- .setEndTextElementListener(new EndTextElementListener() {
- public void end(String body) {
- mId = body;
- }
- });
-
- mHandler = root.getContentHandler();
- }
-
- public void start(Attributes attributes) {
- }
-
- public void end() {
- }
-
- ContentHandler getContentHandler() {
- return mHandler;
- }
-
- public String getId() {
- return mId;
- }
- }
- }
-
- private class VideoUploadTask extends UploadTask {
- public VideoUploadTask(IImage image) {
- super(image);
- }
- protected String getYouTubeBaseUrl() {
- return "http://gdata.youtube.com";
- }
-
- public boolean upload() {
- String uploadUrl = "http://uploads.gdata.youtube.com"
- + "/feeds/users/"
- + mYouTubeUsername
- + "/uploads?client=ytapi-google-android";
-
- String title = mImageObj.getTitle();
- String isPrivate = "";
- String keywords = "";
- String category = "";
- if (mImageObj instanceof ImageManager.VideoObject) {
- ImageManager.VideoObject video = (ImageManager.VideoObject)mImageObj;
- if (mImageObj.getIsPrivate()) {
- isPrivate = "<yt:private/>";
- }
- keywords = video.getTags();
- if (keywords == null || keywords.trim().length() == 0) {
- // there must be a keyword or YouTube will reject the video
- keywords = getResources().getString(R.string.upload_default_tags_text);
- }
- // TODO: use the real category when we have the category spinner in details
-// category = video.getCategory();
- category = "";
- if (category == null || category.trim().length() == 0) {
- // there must be a description or YouTube will get an internal error and return 500
- category = getResources().getString(R.string.upload_default_category_text);
- }
- }
- String description = mImageObj.getDescription();
- if (description == null || description.trim().length() == 0) {
- // there must be a description or YouTube will get an internal error and return 500
- description = getResources().getString(R.string.upload_default_description_text);
- }
- String data = "<?xml version='1.0'?>\n"
- + "<entry xmlns='http://www.w3.org/2005/Atom'\n"
- + " xmlns:media='http://search.yahoo.com/mrss/'\n"
- + " xmlns:yt='http://gdata.youtube.com/schemas/2007'>\n"
- + " <media:group>\n"
- + " <media:title type='plain'>" + title + "</media:title>\n" // TODO: need user entered title
- + " <media:description type='plain'>" + description + "</media:description>\n"
- + isPrivate
- + " <media:category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>\n"
- + category
- + " </media:category>\n"
- + " <media:keywords>" + keywords + "</media:keywords>\n"
- + " </media:group>\n"
- + "</entry>";
-
- if (LOCAL_LOGV) Log.v("youtube", "uploadUrl: " + uploadUrl);
- if (LOCAL_LOGV) Log.v("youtube", "GData: " + data);
-
- UploadResponse result = doUpload(uploadUrl,
- "video/3gpp2",
- data,
- null,
- mYouTubeAuthToken,
- title,
- mImageObj.fullSizeImageUri().getLastPathSegment(),
- true);
-
- boolean success = false;
- if (result != null) {
- switch (result.getStatus()) {
- case 401:
- if (result.getResponse().contains("Token expired")) {
- // When we tried to upload a video to YouTube, the youtube server told us
- // our auth token was expired. Get a new one and try again.
- try {
- mGls.invalidateAuthToken(mYouTubeAuthToken);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not invalidate youtube auth token", e);
- }
- mYouTubeAuthToken = null; // Forces computeYouTubeAuthToken to get a new token.
- computeYouTubeAuthToken();
- }
- break;
-
- case 200:
- case 201:
- case 202:
- case 203:
- case 204:
- case 205:
- case 206:
- success = true;
- break;
-
- }
- }
- return success;
- }
- }
-
- private class ImageUploadTask extends UploadTask {
- public ImageUploadTask(IImage image) {
- super(image);
- }
-
- public boolean upload(Album album) {
- String uploadUrl = getServiceBaseUrl()
- + mPicasaUsername
- + "/album/"
- + album.getAlbumId();
-
- String name = mImageObj.getTitle();
- String description = mImageObj.getDescription();
- String data = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:georss='http://www.georss.org/georss' xmlns:gml='http://www.opengis.net/gml'><title>"
- + name
- + "</title>"
- + "<summary>"
- + (description != null ? description : "")
- + "</summary>"
- + getLatLongString(mImageObj)
- + "<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#photo'/></entry>\n";
-
- if (LOCAL_LOGV)
- Log.v(TAG, "xml for image is " + data);
- UploadResponse response = doUpload(uploadUrl,
- "image/jpeg",
- data,
- mImageObj,
- mPicasaAuthToken,
- name,
- name,
- false);
-
- if (response != null) {
- int status = response.getStatus();
- if (status == HttpStatus.SC_UNAUTHORIZED ||
- status == HttpStatus.SC_FORBIDDEN ||
- status == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
- try {
- mGls.invalidateAuthToken(mPicasaAuthToken);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not invalidate picasa auth token", e);
- }
- mPicasaAuthToken = null;
- } else {
- ResponseHandler h = new ResponseHandler();
- try {
- Xml.parse(response.getResponse(), h.getContentHandler());
- String id = h.getId();
- if (id != null && mImageObj != null) {
- mImageObj.setPicasaId(id);
- mAndroidUploadAlbumPhotos.add(id);
- return true;
- }
- } catch (org.xml.sax.SAXException ex) {
- Log.e(TAG, "SAXException in doUpload " + ex.toString());
- }
- }
- }
- return false;
- }
- }
-
- private Album createAlbum(String name, String summary) {
- String authToken = mPicasaAuthToken;
- if (authToken == null)
- return null;
-
- try {
- String url = getServiceBaseUrl() + mPicasaUsername;
- HttpPost post = new HttpPost(url);
- String entryString = "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gphoto='http://schemas.google.com/photos/2007'>"
- + "<title type='text'>"
- + name
- + "</title>"
- + "<summary>"
- + summary
- + "</summary>"
- + "<gphoto:access>private</gphoto:access>"
- + "<gphoto:commentingEnabled>true</gphoto:commentingEnabled>"
- + "<gphoto:timestamp>"
- + String.valueOf(System.currentTimeMillis())
- + "</gphoto:timestamp>"
- + "<category scheme=\"http://schemas.google.com/g/2005#kind\" term=\"http://schemas.google.com/photos/2007#album\"/>"
- + "</entry>\n";
-
- StringEntity entity = new StringEntity(entryString);
- entity.setContentType(new BasicHeader("Content-Type", "application/atom+xml"));
- post.setEntity(entity);
- post.addHeader(new BasicHeader("Authorization", "GoogleLogin auth=" + authToken));
- HttpResponse status = mClient.execute(post);
- if (LOCAL_LOGV)
- Log.v(TAG, "status is " + status.getStatusLine());
- if (status.getStatusLine().getStatusCode() < 200 || status.getStatusLine().getStatusCode() >= 300) {
- return null;
- }
- Album album = new Album();
- Xml.parse(stringFromResponse(status), new PicasaAlbumHandler(album).getContentHandler());
- return album;
- } catch (java.io.UnsupportedEncodingException ex) {
- Log.e(TAG, "gak, UnsupportedEncodingException " + ex.toString());
- } catch (java.io.IOException ex) {
- Log.e(TAG, "IOException " + ex.toString());
- } catch (org.xml.sax.SAXException ex) {
- Log.e(TAG, "XmlPullParserException " + ex.toString());
- }
- return null;
- }
-
- public static String streamToString(InputStream stream, int maxChars, boolean reset)
- throws IOException {
- BufferedReader reader = new BufferedReader(new InputStreamReader(stream), 8192);
- StringBuilder sb = new StringBuilder();
- String line = null;
-
- while ((line = reader.readLine()) != null
- && (maxChars == -1 || sb.length() < maxChars)) {
- sb.append(line);
- }
- reader.close();
- if (reset) stream.reset();
- return sb.toString();
- }
-
- InputStream get(String url) {
- try {
- if (LOCAL_LOGV) Log.v(TAG, "url is " + url);
-
- for (int i = 0; i < 2; ++i) {
- HttpGet get = new HttpGet(url);
- get.setHeader(new BasicHeader("Authorization",
- "GoogleLogin auth=" + mPicasaAuthToken));
-
- HttpResponse response = mClient.execute(get);
- if (LOCAL_LOGV) Log.v(TAG, "response is " + response.getStatusLine());
- switch (response.getStatusLine().getStatusCode()) {
- case HttpStatus.SC_UNAUTHORIZED:
- case HttpStatus.SC_FORBIDDEN:
- case HttpStatus.SC_INTERNAL_SERVER_ERROR: // http://b/1151576
- try {
- mGls.invalidateAuthToken(mPicasaAuthToken);
- } catch (GoogleLoginServiceNotFoundException e) {
- Log.e(TAG, "Could not invalidate picasa auth token", e);
- }
- mPicasaAuthToken = null;
- computeAuthToken();
- if (mPicasaAuthToken != null) {
- // retry fetch after getting new token
- continue;
- }
- break;
- }
-
- InputStream inputStream = response.getEntity().getContent();
- return inputStream;
- }
- return null;
- } catch (java.io.IOException ex) {
- Log.e(TAG, "IOException");
- }
- return null;
- }
-
- private HashMap<String, Album> getAlbums() {
- if (LOCAL_LOGV)
- Log.v(TAG, "getAlbums");
-
- PicasaAlbumHandler h = new PicasaAlbumHandler();
- try {
- String url = getServiceBaseUrl() + mPicasaUsername + "?kind=album";
- InputStream inputStream = get(url);
- if (inputStream == null) {
- if (Config.LOGV)
- Log.v(TAG, "can't get " + url + "; bail from getAlbums()");
- mPicasaAuthToken = null;
- return null;
- }
-
- Xml.parse(inputStream, Xml.findEncodingByName("UTF-8"), h.getContentHandler());
- if (LOCAL_LOGV)
- Log.v(TAG, "done getting albums");
- inputStream.close();
- } catch (IOException e) {
- Log.e(TAG, "got exception " + e.toString());
- e.printStackTrace();
- } catch (SAXException e) {
- Log.e(TAG, "got exception " + e.toString());
- e.printStackTrace();
- }
- if (LOCAL_LOGV) {
- java.util.Iterator it = h.getAlbums().keySet().iterator();
- while (it.hasNext()) {
- if (Config.LOGV)
- Log.v(TAG, "album: " + (String) it.next());
- }
- }
- return h.getAlbums();
- }
-
- ArrayList<String> getAlbumContents(String albumName) {
- String url = getServiceBaseUrl() + mPicasaUsername + "/album/" + albumName + "?kind=photo&max-results=10000";
- try {
- InputStream inputStream = get(url);
- if (inputStream == null)
- return null;
-
- AlbumContentsHandler ah = new AlbumContentsHandler();
- Xml.parse(inputStream, Xml.findEncodingByName("UTF-8"), ah.getContentHandler());
- ArrayList<String> photos = ah.getPhotos();
- inputStream.close();
- return photos;
- } catch (IOException e) {
- Log.e(TAG, "got IOException " + e.toString());
- e.printStackTrace();
- } catch (SAXException e) {
- Log.e(TAG, "got SAXException " + e.toString());
- e.printStackTrace();
- }
- return null;
- }
-
- class AlbumContentsHandler implements ElementListener {
- private static final String ATOM_NAMESPACE
- = "http://www.w3.org/2005/Atom";
- private static final String PICASA_NAMESPACE
- = "http://schemas.google.com/photos/2007";
-
- private ContentHandler mHandler = null;
- private ArrayList<String> mPhotos = new ArrayList<String>();
-
- public AlbumContentsHandler() {
- RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
- Element entry = root.getChild(ATOM_NAMESPACE, "entry");
-
- entry.setElementListener(this);
-
- entry.getChild(PICASA_NAMESPACE, "id")
- .setEndTextElementListener(new EndTextElementListener() {
- public void end(String body) {
- mPhotos.add(body);
- }
- });
-
- mHandler = root.getContentHandler();
- }
-
- public void start(Attributes attributes) {
- }
-
- public void end() {
- }
-
- ContentHandler getContentHandler() {
- return mHandler;
- }
-
- public ArrayList<String> getPhotos() {
- return mPhotos;
- }
- }
-
- private String getServiceBaseUrl() {
- return "http://picasaweb.google.com/data/feed/api/user/";
- }
-
-
- class PicasaAlbumHandler implements ElementListener {
- private Album mAlbum;
- private HashMap<String, Album> mAlbums = new HashMap<String, Album>();
- private boolean mJustOne;
- private static final String ATOM_NAMESPACE
- = "http://www.w3.org/2005/Atom";
- private static final String PICASSA_NAMESPACE
- = "http://schemas.google.com/photos/2007";
- private ContentHandler handler = null;
-
- public PicasaAlbumHandler() {
- mJustOne = false;
- init();
- }
-
- public HashMap<String, Album> getAlbums() {
- return mAlbums;
- }
-
- public PicasaAlbumHandler(Album album) {
- mJustOne = true;
- mAlbum = album;
- init();
- }
-
- private void init() {
- Element entry;
- RootElement root;
- if (mJustOne) {
- root = new RootElement(ATOM_NAMESPACE, "entry");
- entry = root;
- } else {
- root = new RootElement(ATOM_NAMESPACE, "feed");
- entry = root.getChild(ATOM_NAMESPACE, "entry");
- }
- entry.setElementListener(this);
-
- entry.getChild(ATOM_NAMESPACE, "title")
- .setEndTextElementListener(new EndTextElementListener() {
- public void end(String body) {
- mAlbum.setAlbumName(body);
- }
- });
-
- entry.getChild(PICASSA_NAMESPACE, "name")
- .setEndTextElementListener(new EndTextElementListener() {
- public void end(String body) {
- mAlbum.setAlbumId(body);
- }
- });
-
- this.handler = root.getContentHandler();
- }
-
- public void start(Attributes attributes) {
- if (!mJustOne) {
- mAlbum = new Album();
- }
- }
-
- public void end() {
- if (!mJustOne) {
- mAlbums.put(mAlbum.getAlbumName(), mAlbum);
- mAlbum = null;
- }
- }
-
- ContentHandler getContentHandler() {
- return handler;
- }
- }
-}
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
new file mode 100644
index 0000000..7fcab9a
--- /dev/null
+++ b/src/com/android/camera/VideoCamera.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2007 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 java.io.File;
+import java.util.ArrayList;
+import java.io.IOException;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.ColorDrawable;
+import android.location.LocationManager;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaRecorder;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.os.StatFs;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Video;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.animation.Animation;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.RelativeLayout.LayoutParams;
+
+public class VideoCamera extends Activity implements View.OnClickListener, SurfaceHolder.Callback {
+
+ private static final String TAG = "videocamera";
+
+ private static final boolean DEBUG = true;
+ private static final boolean DEBUG_SUPPRESS_AUDIO_RECORDING = DEBUG && true;
+ private static final boolean DEBUG_DO_NOT_REUSE_MEDIA_RECORDER = DEBUG && true;
+
+ private static final int KEEP = 2;
+ private static final int CLEAR_SCREEN_DELAY = 4;
+ private static final int UPDATE_RECORD_TIME = 5;
+ private static final int RESTART_PREVIEW = 6;
+
+ private static final int SCREEN_DELAY = 2 * 60 * 1000;
+ private static final int POST_PICTURE_ALERT_TIMEOUT = 6 * 1000;
+
+ private static final int NO_STORAGE_ERROR = -1;
+ private static final int CANNOT_STAT_ERROR = -2;
+
+ public static final int MENU_SWITCH_TO_VIDEO = 0;
+ public static final int MENU_SWITCH_TO_CAMERA = 1;
+ public static final int MENU_SETTINGS = 6;
+ public static final int MENU_GALLERY_PHOTOS = 7;
+ public static final int MENU_GALLERY_VIDEOS = 8;
+ public static final int MENU_SAVE_SELECT_PHOTOS = 30;
+ public static final int MENU_SAVE_NEW_PHOTO = 31;
+ public static final int MENU_SAVE_SELECTVIDEO = 32;
+ public static final int MENU_SAVE_TAKE_NEW_VIDEO = 33;
+ public static final int MENU_SAVE_GALLERY_PHOTO = 34;
+ public static final int MENU_SAVE_GALLERY_VIDEO_PHOTO = 35;
+ public static final int MENU_SAVE_CAMERA_DONE = 36;
+ public static final int MENU_SAVE_CAMERA_VIDEO_DONE = 37;
+
+ Toast mToast;
+ SharedPreferences mPreferences;
+
+ private static final float VIDEO_ASPECT_RATIO = 176.0f / 144.0f;
+ VideoPreview mVideoPreview;
+ SurfaceHolder mSurfaceHolder = null;
+ ImageView mBlackout = null;
+ ImageView mVideoFrame;
+ Bitmap mVideoFrameBitmap;
+
+ private MediaRecorder mMediaRecorder;
+ private boolean mMediaRecorderRecording = false;
+ private long mRecordingStartTime;
+ private String mCurrentVideoFilename;
+ private Uri mCurrentVideoUri;
+
+ boolean mPausing = false;
+
+ static ContentResolver mContentResolver;
+ boolean mDidRegister = false;
+
+ int mCurrentZoomIndex = 0;
+
+ private ImageView mModeIndicatorView;
+ private ImageView mRecordingIndicatorView;
+ private TextView mRecordingTimeView;
+
+ ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
+
+ View mPostPictureAlert;
+ LocationManager mLocationManager = null;
+
+ private int mPicturesRemaining;
+
+ private Handler mHandler = new MainHandler();
+
+ private void cancelSavingNotification() {
+ if (mToast != null) {
+ mToast.cancel();
+ mToast = null;
+ }
+ }
+
+ /** This Handler is used to post message back onto the main thread of the application */
+ private class MainHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case KEEP: {
+ keep();
+
+ if (msg.obj != null) {
+ mHandler.post((Runnable)msg.obj);
+ }
+ break;
+ }
+
+ case CLEAR_SCREEN_DELAY: {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ break;
+ }
+
+ case UPDATE_RECORD_TIME: {
+ if (mMediaRecorderRecording) {
+ long now = SystemClock.uptimeMillis();
+ long delta = now - mRecordingStartTime;
+ long seconds = delta / 1000;
+ long minutes = seconds / 60;
+ long remainderSeconds = seconds - (minutes * 60);
+
+ String secondsString = Long.toString(remainderSeconds);
+ if (secondsString.length() < 2) {
+ secondsString = "0" + secondsString;
+ }
+ String minutesString = Long.toString(minutes);
+ if (minutesString.length() < 2) {
+ minutesString = "0" + minutesString;
+ }
+ String text = minutesString + ":" + secondsString;
+ mRecordingTimeView.setText(text);
+ mHandler.sendEmptyMessageDelayed(UPDATE_RECORD_TIME, 1000);
+ }
+ break;
+ }
+
+ case RESTART_PREVIEW:
+ hideVideoFrameAndStartPreview();
+ break;
+
+ default:
+ Log.v(TAG, "Unhandled message: " + msg.what);
+ break;
+ }
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
+ // SD card available
+ // TODO put up a "please wait" message
+ // TODO also listen for the media scanner finished message
+ showStorageToast();
+ } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
+ // SD card unavailable
+ showStorageToast();
+ } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
+ Toast.makeText(VideoCamera.this, getResources().getString(R.string.wait), 5000);
+ } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
+ showStorageToast();
+ }
+ }
+ };
+
+ static private String createName(long dateTaken) {
+ return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
+ }
+
+ private void postAfterKeep(final Runnable r) {
+ Message msg = mHandler.obtainMessage(KEEP);
+ msg.obj = r;
+ msg.sendToTarget();
+ }
+
+ /** Called with the activity is first created. */
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ mContentResolver = getContentResolver();
+
+ //setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
+ requestWindowFeature(Window.FEATURE_PROGRESS);
+
+ Window win = getWindow();
+ win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setContentView(R.layout.video_camera);
+
+ mVideoPreview = (VideoPreview) findViewById(R.id.camera_preview);
+ mVideoPreview.setAspectRatio(VIDEO_ASPECT_RATIO);
+
+ // don't set mSurfaceHolder here. We have it set ONLY within
+ // surfaceCreated / surfaceDestroyed, other parts of the code
+ // assume that when it is set, the surface is also set.
+ SurfaceHolder holder = mVideoPreview.getHolder();
+ holder.addCallback(this);
+ holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+
+ mBlackout = (ImageView) findViewById(R.id.blackout);
+ mBlackout.setBackgroundDrawable(new ColorDrawable(0xFF000000));
+
+ mPostPictureAlert = findViewById(R.id.post_picture_panel);
+ View b;
+
+ b = findViewById(R.id.play);
+ b.setOnClickListener(this);
+
+ b = findViewById(R.id.share);
+ b.setOnClickListener(this);
+
+ b = findViewById(R.id.discard);
+ b.setOnClickListener(this);
+
+ mModeIndicatorView = (ImageView) findViewById(R.id.mode_indicator);
+ mRecordingIndicatorView = (ImageView) findViewById(R.id.recording_indicator);
+ mRecordingTimeView = (TextView) findViewById(R.id.recording_time);
+ mVideoFrame = (ImageView) findViewById(R.id.video_frame);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final View hintView = findViewById(R.id.hint_toast);
+ if (hintView != null)
+ hintView.setVisibility(View.GONE);
+
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ final boolean storageOK = calculatePicturesRemaining() > 0;
+ if (hintView == null)
+ return;
+
+ if (storageOK) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ hintView.setVisibility(View.VISIBLE);
+ }
+ });
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ Animation a = new android.view.animation.AlphaAnimation(1F, 0F);
+ a.setDuration(500);
+ a.startNow();
+ hintView.setAnimation(a);
+ hintView.setVisibility(View.GONE);
+ }
+ }, 3000);
+ } else {
+ mHandler.post(new Runnable() {
+ public void run() {
+ hintView.setVisibility(View.GONE);
+ showStorageToast();
+ }
+ });
+ }
+ }
+ });
+ t.start();
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.discard: {
+ File f = new File(mCurrentVideoFilename);
+ f.delete();
+ mContentResolver.delete(mCurrentVideoUri, null, null);
+
+ hideVideoFrameAndStartPreview();
+ break;
+ }
+
+ case R.id.share: {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_SEND);
+ intent.setType("video/3gpp");
+ intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri);
+ try {
+ startActivity(Intent.createChooser(intent, getText(R.string.sendVideo)));
+ } catch (android.content.ActivityNotFoundException ex) {
+ Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show();
+ }
+
+ break;
+ }
+
+ case R.id.play: {
+ Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri);
+ try {
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException ex) {
+ Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex);
+ }
+ break;
+ }
+ }
+ }
+
+ private void showStorageToast() {
+ String noStorageText = null;
+ int remaining = calculatePicturesRemaining();
+
+ if (remaining == NO_STORAGE_ERROR) {
+ noStorageText = getString(R.string.no_storage);
+ } else if (remaining < 1) {
+ noStorageText = getString(R.string.not_enough_space);
+ }
+
+ if (noStorageText != null) {
+ Toast.makeText(this, noStorageText, 5000).show();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
+
+ mPausing = false;
+
+ // install an intent filter to receive SD card related events.
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
+ intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
+ intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
+ intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
+ intentFilter.addDataScheme("file");
+ registerReceiver(mReceiver, intentFilter);
+ mDidRegister = true;
+
+ mBlackout.setVisibility(View.INVISIBLE);
+ if (mVideoFrameBitmap == null) {
+ initializeVideo();
+ } else {
+ showPostRecordingAlert();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ Log.v(TAG, "onStop");
+ stopVideoRecording();
+ keep();
+ mHandler.removeMessages(CLEAR_SCREEN_DELAY);
+ super.onStop();
+ }
+
+ @Override
+ protected void onPause() {
+ Log.v(TAG, "onPause");
+ stopVideoRecording();
+ keep();
+ hidePostPictureAlert();
+
+ mPausing = true;
+
+ if (mDidRegister) {
+ unregisterReceiver(mReceiver);
+ mDidRegister = false;
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ if (mMediaRecorderRecording) {
+ Log.v(TAG, "onKeyBack");
+ stopVideoRecordingAndDisplayDialog();
+ return true;
+ } else if(isPostRecordingAlertVisible()) {
+ hideVideoFrameAndStartPreview();
+ return true;
+ }
+ break;
+ case KeyEvent.KEYCODE_FOCUS:
+ return true;
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (event.getRepeatCount() == 0) {
+ if (!mMediaRecorderRecording) {
+ startVideoRecording();
+ } else {
+ stopVideoRecordingAndDisplayDialog();
+ }
+ return true;
+ }
+ return true;
+ case KeyEvent.KEYCODE_MENU:
+ if (mMediaRecorderRecording) {
+ stopVideoRecordingAndDisplayDialog();
+ return true;
+ }
+ hideVideoFrameAndStartPreview();
+ break;
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ cancelRestartPreviewTimeout();
+ return super.onTrackballEvent(event);
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ stopVideoRecording();
+ initializeVideo();
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ mSurfaceHolder = holder;
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mSurfaceHolder = null;
+ }
+
+ void gotoGallery() {
+ Uri target = Video.Media.INTERNAL_CONTENT_URI;
+ Intent intent = new Intent(Intent.ACTION_VIEW, target);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Could not start gallery activity", e);
+ }
+ }
+
+ void keep() {
+ cancelSavingNotification();
+ };
+
+ void toss() {
+ cancelSavingNotification();
+ };
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ for (int i = 1; i <= MenuHelper.MENU_ITEM_MAX; i++) {
+ if (i != MenuHelper.GENERIC_ITEM) {
+ menu.setGroupVisible(i, false);
+ }
+ }
+
+ menu.setGroupVisible(MenuHelper.VIDEO_MODE_ITEM, true);
+
+ return true;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ addBaseMenuItems(menu);
+ MenuHelper.addImageMenuItems(
+ menu,
+ MenuHelper.INCLUDE_ALL & ~MenuHelper.INCLUDE_ROTATE_MENU,
+ false,
+ VideoCamera.this,
+ mHandler,
+
+ // Handler for deletion
+ new Runnable() {
+ public void run() {
+ // What do we do here?
+ // mContentResolver.delete(uri, null, null);
+ }
+ },
+ new MenuHelper.MenuInvoker() {
+ public void run(final MenuHelper.MenuCallback cb) {
+ }
+ });
+
+ MenuItem gallery = menu.add(MenuHelper.IMAGE_SAVING_ITEM, MENU_SAVE_GALLERY_PHOTO, 0,
+ R.string.camera_gallery_photos_text).setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ postAfterKeep(new Runnable() {
+ public void run() {
+ gotoGallery();
+ }
+ });
+ return true;
+ }
+ });
+ gallery.setIcon(android.R.drawable.ic_menu_gallery);
+ return true;
+ }
+
+ private int calculatePicturesRemaining() {
+ try {
+ if (!ImageManager.hasStorage()) {
+ mPicturesRemaining = NO_STORAGE_ERROR;
+ } else {
+ String storageDirectory = Environment.getExternalStorageDirectory().toString();
+ StatFs stat = new StatFs(storageDirectory);
+ float remaining = ((float)stat.getAvailableBlocks() * (float)stat.getBlockSize()) / 400000F;
+ mPicturesRemaining = (int)remaining;
+ }
+ } catch (Exception ex) {
+ // if we can't stat the filesystem then we don't know how many
+ // pictures are remaining. it might be zero but just leave it
+ // blank since we really don't know.
+ mPicturesRemaining = CANNOT_STAT_ERROR;
+ }
+ return mPicturesRemaining;
+ }
+
+ private void initializeVideo() {
+ Log.v(TAG, "initializeVideo");
+ releaseMediaRecorder();
+
+ if (mSurfaceHolder == null) {
+ Log.v(TAG, "SurfaceHolder is null");
+ return;
+ }
+
+ mMediaRecorder = new MediaRecorder();
+
+ if (DEBUG_SUPPRESS_AUDIO_RECORDING) {
+ Log.v(TAG, "DEBUG_SUPPRESS_AUDIO_RECORDING is true.");
+ } else {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ Log.v(TAG, "before setOutputFile");
+ createVideoPath();
+ mMediaRecorder.setOutputFile(mCurrentVideoFilename);
+ Boolean videoQualityLow = getIntPreference("pref_camera_videoquality_key") == 0;
+
+ // Use the same frame rate for both, since internally
+ // if the frame rate is too large, it can cause camera to become
+ // unstable. We need to fix the MediaRecorder to disable the support
+ // of setting frame rate for now.
+ mMediaRecorder.setVideoFrameRate(20);
+ if (videoQualityLow) {
+ mMediaRecorder.setVideoSize(176,144);
+ } else {
+ mMediaRecorder.setVideoSize(352,288);
+ }
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
+ if (!DEBUG_SUPPRESS_AUDIO_RECORDING) {
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ }
+ Log.v(TAG, "before setPreviewDisplay");
+ mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ try {
+ mMediaRecorder.prepare();
+ } catch (IOException exception) {
+ Log.e(TAG, "prepare failed for " + mCurrentVideoFilename);
+ releaseMediaRecorder();
+ // TODO: add more exception handling logic here
+ return;
+ }
+ mMediaRecorderRecording = false;
+ }
+
+ private void releaseMediaRecorder() {
+ Log.v(TAG, "Releasing media recorder.");
+ if (mMediaRecorder != null) {
+ mMediaRecorder.reset();
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ }
+
+ private void restartPreview() {
+ if (DEBUG_DO_NOT_REUSE_MEDIA_RECORDER) {
+ Log.v(TAG, "DEBUG_DO_NOT_REUSE_MEDIA_RECORDER recreating mMediaRecorder.");
+ initializeVideo();
+ } else {
+ try {
+ mMediaRecorder.prepare();
+ } catch (IOException exception) {
+ Log.e(TAG, "prepare failed for " + mCurrentVideoFilename);
+ releaseMediaRecorder();
+ // TODO: add more exception handling logic here
+ }
+ }
+ }
+
+ private int getIntPreference(String key) {
+ String s = mPreferences.getString(key, "0");
+ return Integer.parseInt(s);
+ }
+
+ private void createVideoPath() {
+ long dateTaken = System.currentTimeMillis();
+ String title = createName(dateTaken);
+ String displayName = title + ".3gp"; // Used when emailing.
+ String filename = ImageManager.CAMERA_IMAGE_BUCKET_NAME + "/"
+ + Long.toString(dateTaken) + ".3gp";
+ ContentValues values = new ContentValues(7);
+ values.put(Video.Media.TITLE, title);
+ values.put(Video.Media.DISPLAY_NAME, displayName);
+ values.put(Video.Media.DESCRIPTION, "");
+ values.put(Video.Media.DATE_TAKEN, dateTaken);
+ values.put(Video.Media.MIME_TYPE, "video/3gpp");
+ values.put(Video.Media.DATA, filename);
+ Uri videoTable = Uri.parse("content://media/external/video/media");
+ Uri item = mContentResolver.insert(videoTable, values);
+ mCurrentVideoFilename = filename;
+ mCurrentVideoUri = item;
+ }
+
+ private void addBaseMenuItems(Menu menu) {
+ MenuHelper.addSwitchModeMenuItem(menu, this, false);
+ {
+ MenuItem gallery = menu.add(MenuHelper.IMAGE_MODE_ITEM, MENU_GALLERY_PHOTOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ gotoGallery();
+ return true;
+ }
+ });
+ gallery.setIcon(android.R.drawable.ic_menu_gallery);
+ mGalleryItems.add(gallery);
+ }
+ {
+ MenuItem gallery = menu.add(MenuHelper.VIDEO_MODE_ITEM, MENU_GALLERY_VIDEOS, 0, R.string.camera_gallery_photos_text).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ gotoGallery();
+ return true;
+ }
+ });
+ gallery.setIcon(android.R.drawable.ic_menu_gallery);
+ mGalleryItems.add(gallery);
+ }
+
+ MenuItem item = menu.add(MenuHelper.GENERIC_ITEM, MENU_SETTINGS, 0, R.string.settings).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent();
+ intent.setClass(VideoCamera.this, CameraSettings.class);
+ startActivity(intent);
+ return true;
+ }
+ });
+ item.setIcon(android.R.drawable.ic_menu_preferences);
+ }
+
+ private void startVideoRecording() {
+ Log.v(TAG, "startVideoRecording");
+ if (!mMediaRecorderRecording) {
+
+ // Check mMediaRecorder to see whether it is initialized or not.
+ if (mMediaRecorder == null) {
+ initializeVideo();
+ }
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ try {
+ mMediaRecorder.start(); // Recording is now started
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Could not start media recorder. ", e);
+ return;
+ }
+ mMediaRecorderRecording = true;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mModeIndicatorView.setVisibility(View.GONE);
+ mRecordingIndicatorView.setVisibility(View.VISIBLE);
+ mRecordingTimeView.setText("");
+ mRecordingTimeView.setVisibility(View.VISIBLE);
+ mHandler.sendEmptyMessage(UPDATE_RECORD_TIME);
+ }
+ }
+
+ private void stopVideoRecordingAndDisplayDialog() {
+ Log.v(TAG, "stopVideoRecordingAndDisplayDialog");
+ if (mMediaRecorderRecording) {
+ stopVideoRecording();
+ acquireAndShowVideoFrame();
+ showPostRecordingAlert();
+ }
+ }
+
+ private void showPostRecordingAlert() {
+ cancelRestartPreviewTimeout();
+ mPostPictureAlert.setVisibility(View.VISIBLE);
+ mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, POST_PICTURE_ALERT_TIMEOUT);
+ }
+
+ private void hidePostPictureAlert() {
+ cancelRestartPreviewTimeout();
+ mPostPictureAlert.setVisibility(View.INVISIBLE);
+ }
+
+ private void cancelRestartPreviewTimeout() {
+ mHandler.removeMessages(RESTART_PREVIEW);
+ }
+
+ private boolean isPostRecordingAlertVisible() {
+ return mPostPictureAlert.getVisibility() == View.VISIBLE;
+ }
+
+ private void stopVideoRecording() {
+ Log.v(TAG, "stopVideoRecording");
+ if (mMediaRecorderRecording || mMediaRecorder != null) {
+ if (mMediaRecorderRecording) {
+ mMediaRecorder.stop();
+ }
+ releaseMediaRecorder();
+ mMediaRecorderRecording = false;
+ mModeIndicatorView.setVisibility(View.VISIBLE);
+ mRecordingIndicatorView.setVisibility(View.GONE);
+ mRecordingTimeView.setVisibility(View.GONE);
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+ }
+
+ private void hideVideoFrameAndStartPreview() {
+ hidePostPictureAlert();
+ hideVideoFrame();
+ restartPreview();
+ }
+
+ private void acquireAndShowVideoFrame() {
+ recycleVideoFrameBitmap();
+ mVideoFrameBitmap = createVideoThumbnail(mCurrentVideoFilename);
+ mVideoFrame.setImageBitmap(mVideoFrameBitmap);
+ mVideoFrame.setVisibility(View.VISIBLE);
+ }
+
+ private void hideVideoFrame() {
+ recycleVideoFrameBitmap();
+ mVideoFrame.setVisibility(View.GONE);
+ }
+
+ private void recycleVideoFrameBitmap() {
+ if (mVideoFrameBitmap != null) {
+ mVideoFrame.setImageDrawable(null);
+ mVideoFrameBitmap.recycle();
+ mVideoFrameBitmap = null;
+ }
+ }
+
+ private Bitmap createVideoThumbnail(String filePath) {
+ Bitmap bitmap = null;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
+ retriever.setDataSource(filePath);
+ bitmap = retriever.captureFrame();
+ } finally {
+ retriever.release();
+ }
+ return bitmap;
+ }
+
+}
+
diff --git a/src/com/android/camera/VideoPreview.java b/src/com/android/camera/VideoPreview.java
new file mode 100644
index 0000000..aed1e89
--- /dev/null
+++ b/src/com/android/camera/VideoPreview.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 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.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.view.View.MeasureSpec;
+
+class VideoPreview extends SurfaceView {
+ private float mAspectRatio;
+ private int mHorizontalTileSize = 1;
+ private int mVerticalTileSize = 1;
+
+ /**
+ * Setting the aspect ratio to this value means to not enforce an aspect ratio.
+ */
+ public static float DONT_CARE = 0.0f;
+
+ public VideoPreview(Context context) {
+ super(context);
+ }
+
+ public VideoPreview(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public VideoPreview(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setTileSize(int horizontalTileSize, int verticalTileSize) {
+ if ((mHorizontalTileSize != horizontalTileSize)
+ || (mVerticalTileSize != verticalTileSize)) {
+ mHorizontalTileSize = horizontalTileSize;
+ mVerticalTileSize = verticalTileSize;
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ public void setAspectRatio(int width, int height) {
+ setAspectRatio(((float) width) / ((float) height));
+ }
+
+ public void setAspectRatio(float aspectRatio) {
+ if (mAspectRatio != aspectRatio) {
+ mAspectRatio = aspectRatio;
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mAspectRatio != DONT_CARE) {
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ int width = widthSpecSize;
+ int height = heightSpecSize;
+
+ if (width > 0 && height > 0) {
+ float defaultRatio = ((float) width) / ((float) height);
+ if (defaultRatio < mAspectRatio) {
+ // Need to reduce height
+ height = (int) (width / mAspectRatio);
+ } else if (defaultRatio > mAspectRatio) {
+ width = (int) (height * mAspectRatio);
+ }
+ width = roundUpToTile(width, mHorizontalTileSize, widthSpecSize);
+ height = roundUpToTile(height, mVerticalTileSize, heightSpecSize);
+ Log.i("VideoPreview", "ar " + mAspectRatio + " setting size: " + width + 'x' + height);
+ setMeasuredDimension(width, height);
+ return;
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private int roundUpToTile(int dimension, int tileSize, int maxDimension) {
+ return Math.min(((dimension + tileSize - 1) / tileSize) * tileSize, maxDimension);
+ }
+}
diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java
index 4b9eb58..9579f19 100644
--- a/src/com/android/camera/ViewImage.java
+++ b/src/com/android/camera/ViewImage.java
@@ -102,8 +102,8 @@ public class ViewImage extends Activity
private Animation mHidePrevImageViewAnimation = new AlphaAnimation(1F, 0F);
private Animation mShowNextImageViewAnimation = new AlphaAnimation(0F, 1F);
private Animation mShowPrevImageViewAnimation = new AlphaAnimation(0F, 1F);
-
-
+
+
static final int sPadding = 20;
static final int sHysteresis = sPadding * 2;
static final int sBaseScrollDuration = 1000; // ms
@@ -127,17 +127,17 @@ public class ViewImage extends Activity
Runnable mDismissOnScreenControlsRunnable;
ZoomControls mZoomControls;
-
+
public ViewImage() {
}
-
+
private void updateNextPrevControls() {
boolean showPrev = mCurrentPosition > 0;
boolean showNext = mCurrentPosition < mAllImages.getCount() - 1;
-
+
boolean prevIsVisible = mPrevImageView.getVisibility() == View.VISIBLE;
boolean nextIsVisible = mNextImageView.getVisibility() == View.VISIBLE;
-
+
if (showPrev && !prevIsVisible) {
Animation a = mShowPrevImageViewAnimation;
a.setDuration(500);
@@ -205,7 +205,7 @@ public class ViewImage extends Activity
mDismissOnScreenControlsRunnable = new Runnable() {
public void run() {
mZoomControls.hide();
-
+
if (mNextImageView.getVisibility() == View.VISIBLE) {
Animation a = mHideNextImageViewAnimation;
a.setDuration(500);
@@ -213,7 +213,7 @@ public class ViewImage extends Activity
mNextImageView.setAnimation(a);
mNextImageView.setVisibility(View.INVISIBLE);
}
-
+
if (mPrevImageView.getVisibility() == View.VISIBLE) {
Animation a = mHidePrevImageViewAnimation;
a.setDuration(500);
@@ -252,14 +252,14 @@ public class ViewImage extends Activity
static public class ImageViewTouch extends ImageViewTouchBase {
private ViewImage mViewImage;
-
+
private static int TOUCH_STATE_REST = 0;
private static int TOUCH_STATE_LEFT_PRESS = 1;
- private static int TOUCH_STATE_RIGHT_PRESS = 2;
- private static int TOUCH_STATE_PANNING = 3;
-
+ private static int TOUCH_STATE_RIGHT_PRESS = 2;
+ private static int TOUCH_STATE_PANNING = 3;
+
private static int TOUCH_AREA_WIDTH = 60;
-
+
private int mTouchState = TOUCH_STATE_REST;
public ImageViewTouch(Context context) {
@@ -300,7 +300,7 @@ public class ViewImage extends Activity
mLastYTouchPos = y;
mTouchState = TOUCH_STATE_REST;
break;
- case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_MOVE:
if (x < TOUCH_AREA_WIDTH) {
if (mTouchState == TOUCH_STATE_REST) {
mTouchState = TOUCH_STATE_LEFT_PRESS;
@@ -325,10 +325,10 @@ public class ViewImage extends Activity
mTouchState = TOUCH_STATE_PANNING;
viewImage.mPrevImageView.setPressed(false);
viewImage.mNextImageView.setPressed(false);
-
+
int deltaX;
int deltaY;
-
+
if (mLastXTouchPos == -1) {
deltaX = 0;
deltaY = 0;
@@ -342,7 +342,7 @@ public class ViewImage extends Activity
if (mBitmapDisplayed == null)
return true;
-
+
if (deltaX != 0) {
// Second. Pan to whatever degree is possible.
if (getScale() > 1F) {
@@ -357,7 +357,7 @@ public class ViewImage extends Activity
int nextImagePos = -1;
if (mTouchState == TOUCH_STATE_LEFT_PRESS && x < TOUCH_AREA_WIDTH) {
nextImagePos = viewImage.mCurrentPosition - 1;
- } else if (mTouchState == TOUCH_STATE_RIGHT_PRESS &&
+ } else if (mTouchState == TOUCH_STATE_RIGHT_PRESS &&
x > viewWidth - TOUCH_AREA_WIDTH) {
nextImagePos = viewImage.mCurrentPosition + 1;
}
@@ -546,7 +546,7 @@ public class ViewImage extends Activity
private void animateScrollTo(int xNew, int yNew) {
mScroller.startScrollTo(xNew, yNew);
}
-
+
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
@@ -564,9 +564,8 @@ public class ViewImage extends Activity
});
item.setIcon(android.R.drawable.ic_menu_slideshow);
}
-
+
mFlipItem = MenuHelper.addFlipOrientation(menu, ViewImage.this, mPrefs);
- mFlipItem.setIcon(android.R.drawable.ic_menu_always_landscape_portrait);
final SelectedImageGetter selectedImageGetter = new SelectedImageGetter() {
public ImageManager.IImage getCurrentImage() {
@@ -581,6 +580,7 @@ public class ViewImage extends Activity
mImageMenuRunnable = MenuHelper.addImageMenuItems(
menu,
MenuHelper.INCLUDE_ALL,
+ true,
ViewImage.this,
mHandler,
mDeletePhotoRunnable,
@@ -641,7 +641,7 @@ public class ViewImage extends Activity
setImage(mCurrentPosition);
}
};
-
+
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
@@ -663,7 +663,7 @@ public class ViewImage extends Activity
private boolean isCurrentImageShareable() {
IImage image = mAllImages.getImageAt(mCurrentPosition);
if (image != null){
- Uri uri = image.fullSizeImageUri();
+ Uri uri = image.fullSizeImageUri();
String fullUri = uri.toString();
return fullUri.startsWith(MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString()) ||
fullUri.startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString());
@@ -674,10 +674,12 @@ public class ViewImage extends Activity
@Override
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- for (ImageViewTouchBase iv: mImageViews) {
- iv.setImageBitmapResetBase(null, false, true);
+ if (newConfig.orientation != getResources().getConfiguration().orientation) {
+ for (ImageViewTouchBase iv: mImageViews) {
+ iv.setImageBitmapResetBase(null, false, true);
+ }
+ MenuHelper.requestOrientation(this, mPrefs);
}
- MenuHelper.requestOrientation(this, mPrefs);
}
@Override
@@ -839,7 +841,7 @@ public class ViewImage extends Activity
if (mLoad != null) {
long t1;
if (Config.LOGV) t1 = System.currentTimeMillis();
-
+
Bitmap b = null;
try {
b = mLoad.get();
@@ -941,7 +943,7 @@ public class ViewImage extends Activity
for (ImageViewTouchBase ivtb : mImageViews)
ivtb.dump();
}
-
+
if (!mFirst) {
if (left) {
mImageViews[2].copyFrom(mImageViews[1]);
@@ -977,7 +979,7 @@ public class ViewImage extends Activity
} else {
mScroller.scrollTo(to, 0);
}
-
+
ImageGetterCallback cb = new ImageGetterCallback() {
public void completed(boolean wasCanceled) {
mImageViews[1].setFocusableInTouchMode(true);
@@ -1064,7 +1066,7 @@ public class ViewImage extends Activity
mSlideShowImageViews[i].setImageBitmapResetBase(null, true, true);
mSlideShowImageViews[i].setVisibility(View.INVISIBLE);
}
-
+
Uri uri = getIntent().getData();
if (Config.LOGV)
@@ -1132,7 +1134,7 @@ public class ViewImage extends Activity
for (ImageViewTouchBase ivt: mImageViews) {
ivt.clear();
}
-
+
if (false) {
Log.v(TAG, "current is " + this.mSlideShowImageCurrent);
this.mSlideShowImageViews[0].dump();
@@ -1161,7 +1163,7 @@ public class ViewImage extends Activity
Log.v(TAG, "read prefs... animidx: " + mAnimationIndex);
Log.v(TAG, "read prefs... interval: " + mSlideShowInterval);
}
-
+
if (mUseShuffleOrder) {
generateShuffleOrder();
}
@@ -1345,16 +1347,16 @@ public class ViewImage extends Activity
public void onSaveInstanceState(Bundle b) {
super.onSaveInstanceState(b);
ImageManager.IImage image = mAllImages.getImageAt(mCurrentPosition);
-
+
if (image != null){
- Uri uri = image.fullSizeImageUri();
- String bucket = null;
- if(getIntent()!= null && getIntent().getData()!=null)
- bucket = getIntent().getData().getQueryParameter("bucketId");
-
- if(bucket!=null)
- uri = uri.buildUpon().appendQueryParameter("bucketId", bucket).build();
-
+ Uri uri = image.fullSizeImageUri();
+ String bucket = null;
+ if(getIntent()!= null && getIntent().getData()!=null)
+ bucket = getIntent().getData().getQueryParameter("bucketId");
+
+ if(bucket!=null)
+ uri = uri.buildUpon().appendQueryParameter("bucketId", bucket).build();
+
b.putString("uri", uri.toString());
}
if (mMode == MODE_SLIDESHOW)
@@ -1364,8 +1366,15 @@ public class ViewImage extends Activity
@Override
public void onResume()
{
- super.onResume();
-
+ super.onResume();
+
+ // normally this will never be zero but if one "backs" into this
+ // activity after removing the sdcard it could be zero. in that
+ // case just "finish" since there's nothing useful that can happen.
+ if (mAllImages.getCount() == 0) {
+ finish();
+ }
+
ImageManager.IImage image = mAllImages.getImageAt(mCurrentPosition);
String sortOrder = mPrefs.getString("pref_gallery_sort_key", null);
@@ -1376,7 +1385,7 @@ public class ViewImage extends Activity
if (sortAscending != mSortAscending) {
init(image.fullSizeImageUri());
}
-
+
if (mGetter == null) {
makeGetter();
}
@@ -1394,20 +1403,13 @@ public class ViewImage extends Activity
});
setImage(mCurrentPosition);
- // normally this will never be zero but if one "backs" into this
- // activity after removing the sdcard it could be zero. in that
- // case just "finish" since there's nothing useful that can happen.
- if (mAllImages.getCount() == 0) {
- finish();
- } else {
- MenuHelper.requestOrientation(this, mPrefs);
- }
+ MenuHelper.requestOrientation(this, mPrefs);
}
@Override
public void onPause()
{
- super.onPause();
+ super.onPause();
mGetter.cancelCurrent();
mGetter.stop();
@@ -1415,18 +1417,18 @@ public class ViewImage extends Activity
setMode(MODE_NORMAL);
mAllImages.deactivate();
-
+
for (ImageViewTouchBase iv: mImageViews) {
iv.recycleBitmaps();
iv.setImageBitmap(null, true);
}
-
+
for (ImageViewTouchBase iv: mSlideShowImageViews) {
iv.recycleBitmaps();
iv.setImageBitmap(null, true);
}
}
-
+
@Override
public void onStop() {
super.onStop();
diff --git a/src/com/android/camera/ViewVideo.java b/src/com/android/camera/ViewVideo.java
deleted file mode 100644
index 527f0bb..0000000
--- a/src/com/android/camera/ViewVideo.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2008 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.media.MediaPlayer;
-import android.app.Activity;
-import android.os.Bundle;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.Uri;
-import android.os.PowerManager;
-import android.util.Log;
-import android.view.Menu;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.MediaController;
-import android.view.Window;
-import android.widget.VideoView;
-import android.util.Config;
-
-class ViewVideo extends Activity
-{
- static final String TAG = "ViewVideo";
-
- private ImageManager.IImageList mAllVideos;
- private PowerManager.WakeLock mWakeLock;
- private ContentResolver mContentResolver;
- private VideoView mVideoView;
- private ImageManager.IImage mVideo;
- private int mCurrentPosition = -1;
- private MediaController mMediaController;
-
- // if the activity gets paused the stash the current position here
- int mPausedPlaybackPosition = 0;
-
-
- public ViewVideo()
- {
- }
-
- @Override
- public void onCreate(Bundle icicle)
- {
- super.onCreate(icicle);
- if (Config.LOGV)
- Log.v(TAG, "onCreate");
- //getWindow().setFormat(android.graphics.PixelFormat.TRANSLUCENT);
-
- PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
-
- mContentResolver = getContentResolver();
-
- setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
- setContentView(R.layout.viewvideo);
-
- mMediaController = new MediaController(this);
- mVideoView = (VideoView) findViewById(R.id.video);
- mVideoView.setMediaController(mMediaController);
- mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- public void onCompletion(MediaPlayer mp) {
- // TODO what do we really want to do at the end of playback?
- finish();
- }
- });
- }
-
- @Override
- public void onSaveInstanceState(Bundle b) {
- if (Config.LOGV)
- Log.v(TAG, "onSaveInstanceState");
- b.putInt("playback_position", mPausedPlaybackPosition);
- }
-
- @Override
- public void onRestoreInstanceState(Bundle b) {
- if (Config.LOGV)
- Log.v(TAG, "onRestoreInstanceState");
- mPausedPlaybackPosition = b.getInt("playback_position", 0);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (Config.LOGV)
- Log.v(TAG, "onPause");
- mAllVideos.deactivate();
-
- mVideoView.pause();
- mPausedPlaybackPosition = mVideoView.getCurrentPosition();
- mVideoView.setVideoURI(null);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- if (Config.LOGV)
- Log.v(TAG, "onStop");
- }
-
- @Override
- public void onResume()
- {
- super.onResume();
- if (Config.LOGV)
- Log.v(TAG, "onResume");
-
- mAllVideos = ImageManager.instance().allImages(
- ViewVideo.this,
- mContentResolver,
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_VIDEOS,
- ImageManager.SORT_DESCENDING);
-
- // TODO smarter/faster here please
- Uri uri = getIntent().getData();
- if (mVideo == null) {
- for (int i = 0; i < mAllVideos.getCount(); i++) {
- ImageManager.IImage video = mAllVideos.getImageAt(i);
- if (video.fullSizeImageUri().equals(uri)) {
- mCurrentPosition = i;
- mVideo = video;
- break;
- }
- }
- }
-
- if (mCurrentPosition != -1) {
- mMediaController.setPrevNextListeners(
- new android.view.View.OnClickListener() {
- public void onClick(View v) {
- if (++mCurrentPosition == mAllVideos.getCount())
- mCurrentPosition = 0;
- ImageManager.IImage video = mAllVideos.getImageAt(mCurrentPosition);
- mVideo = video;
- mVideoView.setVideoURI(video.fullSizeImageUri());
- mVideoView.start();
- }
- },
- new android.view.View.OnClickListener() {
- public void onClick(View v) {
- if (--mCurrentPosition == -1)
- mCurrentPosition = mAllVideos.getCount() - 1;
- ImageManager.IImage video = mAllVideos.getImageAt(mCurrentPosition);
- mVideo = video;
- mVideoView.setVideoURI(video.fullSizeImageUri());
- mVideoView.start();
- }
- });
- }
- if (Config.LOGV)
- android.util.Log.v("camera", "seekTo " + mPausedPlaybackPosition);
- mVideoView.setVideoURI(uri);
- mVideoView.seekTo(mPausedPlaybackPosition);
- mVideoView.start();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu)
- {
- super.onCreateOptionsMenu(menu);
- MenuHelper.addVideoMenuItems(
- menu,
- MenuHelper.INCLUDE_ALL & ~MenuHelper.INCLUDE_VIEWPLAY_MENU,
- ViewVideo.this, // activity
- null, // handler
- new SelectedImageGetter() {
- public ImageManager.IImage getCurrentImage() {
- return mVideo;
- }
- public Uri getCurrentImageUri() {
- return mVideo.fullSizeImageUri();
- }
- },
-
- // deletion case
- new Runnable() {
- public void run() {
- mAllVideos.removeImage(mVideo);
- finish();
- }
- },
-
- // pre-work
- null,
-
- // post-work
- null);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu)
- {
- return super.onPrepareOptionsMenu(menu);
- }
-}
diff --git a/src/com/android/camera/YouTubeUpload.java b/src/com/android/camera/YouTubeUpload.java
deleted file mode 100644
index 0963d09..0000000
--- a/src/com/android/camera/YouTubeUpload.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2006 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.content.Intent;
-import android.net.Uri;
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.net.http.AndroidHttpClient;
-import android.os.Bundle;
-import android.widget.TextView;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
-import android.util.Log;
-import android.util.Xml;
-
-
-public class YouTubeUpload extends Activity
-{
- private static final String TAG = "YouTubeUpload";
-
- private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
- private static final boolean mDevServer = false;
-
- private ArrayList<String> mCategoriesShort = new ArrayList<String>();
- private ArrayList<String> mCategoriesLong = new ArrayList<String>();
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- TextView tv = new TextView(this);
- tv.setText("");
- setContentView(tv);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final ProgressDialog pd = ProgressDialog.show(this, "please wait", "");
-
- final ImageManager.IImageList all = ImageManager.instance().allImages(
- YouTubeUpload.this,
- getContentResolver(),
- ImageManager.DataLocation.ALL,
- ImageManager.INCLUDE_VIDEOS,
- ImageManager.SORT_ASCENDING);
-
- android.net.Uri uri = getIntent().getData();
- if (uri == null) {
- uri = (Uri) getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
- }
- if (uri != null) {
- final ImageManager.VideoObject vid = (ImageManager.VideoObject) all.getImageForUri(uri);
- if (vid != null) {
- new Thread(new Runnable() {
- public void run() {
- getCategories();
- runOnUiThread(new Runnable() {
- public void run() {
- pd.cancel();
- MenuHelper.YouTubeUploadInfoDialog infoDialog = new MenuHelper.YouTubeUploadInfoDialog(
- YouTubeUpload.this,
- mCategoriesShort,
- mCategoriesLong,
- vid,
- new Runnable() {
- public void run() {
- finish();
- }
- });
- infoDialog.show();
- }
- });
- }
- }).start();
- }
- }
- }
-
- protected String getYouTubeBaseUrl() {
- if (mDevServer) {
- return "http://dev.gdata.youtube.com";
- } else {
- return "http://gdata.youtube.com";
- }
- }
-
- public void getCategories() {
- String uri = getYouTubeBaseUrl() + "/schemas/2007/categories.cat";
- AndroidHttpClient mClient = AndroidHttpClient.newInstance("Android-Camera/0.1");
-
- try {
- org.apache.http.HttpResponse r = mClient.execute(new org.apache.http.client.methods.HttpGet(uri));
- processReturnedData(r.getEntity().getContent());
- } catch (Exception ex) {
- Log.e(TAG, "got exception getting categories... " + ex.toString());
- }
- }
-
- public void processReturnedData(InputStream s) throws IOException, SAXException, XmlPullParserException {
- try {
- Xml.parse(s, Xml.findEncodingByName(null), new DefaultHandler() {
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- if (ATOM_NAMESPACE.equals(uri)) {
- if ("category".equals(localName)) {
- String catShortName = attributes.getValue("", "term");
- String catLongName = attributes.getValue("", "label");
- mCategoriesLong .add(catLongName);
- mCategoriesShort.add(catShortName);
- return;
- }
- }
- }
- });
- } catch (SAXException e) {
- e.printStackTrace();
- }
- }
-}