summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/app
diff options
context:
space:
mode:
authorChih-Chung Chang <chihchung@google.com>2012-03-15 16:38:45 +0800
committerChih-Chung Chang <chihchung@google.com>2012-03-21 15:29:29 +0800
commit15b351a22d02e89d882fc9fe32b3f4c512080e0a (patch)
tree07a316c7f973bdb0173fc50b25837c50c65f6714 /src/com/android/gallery3d/app
parent8cab3e872dd95e55ba34fdb94269a0c5069e72ae (diff)
downloadandroid_packages_apps_Gallery2-15b351a22d02e89d882fc9fe32b3f4c512080e0a.tar.gz
android_packages_apps_Gallery2-15b351a22d02e89d882fc9fe32b3f4c512080e0a.tar.bz2
android_packages_apps_Gallery2-15b351a22d02e89d882fc9fe32b3f4c512080e0a.zip
Create a ScreenNail interface so we can add other types of screenails.
Add a new MediaItem type to contain a ScreenNail. Change-Id: Ia303949f3013dd48ded204eaf9ec69a102b8503e
Diffstat (limited to 'src/com/android/gallery3d/app')
-rw-r--r--src/com/android/gallery3d/app/CameraView.java117
-rw-r--r--src/com/android/gallery3d/app/PhotoDataAdapter.java57
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java53
-rw-r--r--src/com/android/gallery3d/app/ScreenNailBridge.java122
-rw-r--r--src/com/android/gallery3d/app/SinglePhotoDataAdapter.java10
5 files changed, 326 insertions, 33 deletions
diff --git a/src/com/android/gallery3d/app/CameraView.java b/src/com/android/gallery3d/app/CameraView.java
new file mode 100644
index 000000000..a6c233291
--- /dev/null
+++ b/src/com/android/gallery3d/app/CameraView.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.app;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.View;
+
+import java.io.IOException;
+
+// This is a sample View which demos the usage of ScreenNailBridge. It
+// is not intended for production use.
+public class CameraView extends TextureView implements
+ TextureView.SurfaceTextureListener, ScreenNailBridge.Listener {
+ private static final String TAG = "CameraView";
+ private static final int PREVIEW_WIDTH = 960;
+ private static final int PREVIEW_HEIGHT = 720;
+ private Camera mCamera;
+ private ScreenNailBridge mScreenNailBridge;
+
+ public CameraView(Context context) {
+ super(context);
+ init();
+ }
+
+ public CameraView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setVisibility(View.INVISIBLE);
+ setSurfaceTextureListener(this);
+ }
+
+ public void setScreenNailBridge(ScreenNailBridge s) {
+ mScreenNailBridge = s;
+ }
+
+ @Override
+ public void onMeasure(int widthSpec, int heightSpec) {
+ int width = getDefaultSize(PREVIEW_WIDTH, widthSpec);
+ int height = getDefaultSize(PREVIEW_HEIGHT, heightSpec);
+ // Keep aspect ratio
+ if (width * PREVIEW_HEIGHT > PREVIEW_WIDTH * height) {
+ width = PREVIEW_WIDTH * height / PREVIEW_HEIGHT;
+ } else {
+ height = PREVIEW_HEIGHT * width / PREVIEW_WIDTH;
+ }
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ public void onSizeChanged(int w, int h, int oldw, int oldh) {
+ mScreenNailBridge.setSize(w, h);
+ }
+
+ @Override
+ public void updateView(boolean visible, int x, int y, int w, int h) {
+ if (!visible) {
+ setVisibility(View.INVISIBLE);
+ } else {
+ setVisibility(View.VISIBLE);
+ setTranslationX(x);
+ setTranslationY(y);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ try {
+ mCamera = Camera.open();
+
+ Camera.Parameters param = mCamera.getParameters();
+ param.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
+ mCamera.setParameters(param);
+
+ mCamera.setPreviewTexture(surface);
+ mCamera.startPreview();
+ } catch (Throwable ex) {
+ Log.e(TAG, "failed to open camera", ex);
+ }
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ mCamera.stopPreview();
+ mCamera.release();
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
+}
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index 0b544b95a..82225d919 100644
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -29,8 +29,9 @@ import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.Path;
+import com.android.gallery3d.ui.BitmapScreenNail;
import com.android.gallery3d.ui.PhotoView;
-import com.android.gallery3d.ui.PhotoView.ImageData;
+import com.android.gallery3d.ui.ScreenNail;
import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.ui.TileImageViewAdapter;
import com.android.gallery3d.util.Future;
@@ -215,20 +216,22 @@ public class PhotoDataAdapter implements PhotoPage.Model {
mDataListener = listener;
}
- private void updateScreenNail(long version, Future<Bitmap> future) {
+ private void updateScreenNail(long version, Future<ScreenNail> future) {
ImageEntry entry = mImageCache.get(version);
+ ScreenNail screenNail = future.get();
+
if (entry == null || entry.screenNailTask != future) {
- Bitmap screenNail = future.get();
if (screenNail != null) screenNail.recycle();
return;
}
entry.screenNailTask = null;
- entry.screenNail = future.get();
+ entry.screenNail = screenNail;
- if (entry.screenNail == null) {
+ if (screenNail == null) {
entry.failToLoad = true;
}
+
if (mDataListener != null) {
mDataListener.onPhotoAvailable(version, false);
}
@@ -291,24 +294,19 @@ public class PhotoDataAdapter implements PhotoPage.Model {
mTileProvider.clear();
}
- private ImageData getImage(int index) {
+ private ScreenNail getImage(int index) {
if (index < 0 || index >= mSize || !mIsActive) return null;
Utils.assertTrue(index >= mActiveStart && index < mActiveEnd);
ImageEntry entry = mImageCache.get(getVersion(index));
- Bitmap screennail = entry == null ? null : entry.screenNail;
- if (screennail != null) {
- return new ImageData(screennail, entry.rotation);
- } else {
- return new ImageData(null, 0);
- }
+ return entry == null ? null : entry.screenNail;
}
- public ImageData getPreviousImage() {
+ public ScreenNail getPrevScreenNail() {
return getImage(mCurrentIndex - 1);
}
- public ImageData getNextImage() {
+ public ScreenNail getNextScreenNail() {
return getImage(mCurrentIndex + 1);
}
@@ -343,8 +341,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
updateCurrentIndex(index);
}
- public Bitmap getBackupImage() {
- return mTileProvider.getBackupImage();
+ public ScreenNail getScreenNail() {
+ return mTileProvider.getScreenNail();
}
public int getImageHeight() {
@@ -409,17 +407,17 @@ public class PhotoDataAdapter implements PhotoPage.Model {
}
private void updateTileProvider(ImageEntry entry) {
- Bitmap screenNail = entry.screenNail;
+ ScreenNail screenNail = entry.screenNail;
BitmapRegionDecoder fullImage = entry.fullImage;
if (screenNail != null) {
if (fullImage != null) {
- mTileProvider.setBackupImage(screenNail,
+ mTileProvider.setScreenNail(screenNail,
fullImage.getWidth(), fullImage.getHeight());
mTileProvider.setRegionDecoder(fullImage);
} else {
int width = screenNail.getWidth();
int height = screenNail.getHeight();
- mTileProvider.setBackupImage(screenNail, width, height);
+ mTileProvider.setScreenNail(screenNail, width, height);
}
} else {
mTileProvider.clear();
@@ -489,7 +487,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
}
}
- private static class ScreenNailJob implements Job<Bitmap> {
+ private static class ScreenNailJob implements Job<ScreenNail> {
private MediaItem mItem;
public ScreenNailJob(MediaItem item) {
@@ -497,14 +495,19 @@ public class PhotoDataAdapter implements PhotoPage.Model {
}
@Override
- public Bitmap run(JobContext jc) {
+ public ScreenNail run(JobContext jc) {
+ // We try to get a ScreenNail first, if it fails, we fallback to get
+ // a Bitmap and then wrap it in a BitmapScreenNail instead.
+ ScreenNail s = mItem.getScreenNail();
+ if (s != null) return s;
+
Bitmap bitmap = mItem.requestImage(MediaItem.TYPE_THUMBNAIL).run(jc);
if (jc.isCancelled()) return null;
if (bitmap != null) {
bitmap = BitmapUtils.rotateBitmap(bitmap,
mItem.getRotation() - mItem.getFullImageRotation(), true);
}
- return bitmap;
+ return new BitmapScreenNail(bitmap, mItem.getFullImageRotation());
}
}
@@ -604,16 +607,16 @@ public class PhotoDataAdapter implements PhotoPage.Model {
}
private class ScreenNailListener
- implements Runnable, FutureListener<Bitmap> {
+ implements Runnable, FutureListener<ScreenNail> {
private final long mVersion;
- private Future<Bitmap> mFuture;
+ private Future<ScreenNail> mFuture;
public ScreenNailListener(long version) {
mVersion = version;
}
@Override
- public void onFutureDone(Future<Bitmap> future) {
+ public void onFutureDone(Future<ScreenNail> future) {
mFuture = future;
mMainHandler.sendMessage(
mMainHandler.obtainMessage(MSG_RUN_OBJECT, this));
@@ -629,8 +632,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
public int requestedBits = 0;
public int rotation;
public BitmapRegionDecoder fullImage;
- public Bitmap screenNail;
- public Future<Bitmap> screenNailTask;
+ public ScreenNail screenNail;
+ public Future<ScreenNail> screenNailTask;
public Future<BitmapRegionDecoder> fullImageTask;
public boolean failToLoad = false;
}
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index 502530a42..df5b98ada 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -30,6 +30,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.view.View.MeasureSpec;
import android.view.WindowManager;
import android.widget.ShareActionProvider;
@@ -43,6 +44,7 @@ import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.MtpDevice;
import com.android.gallery3d.data.Path;
+import com.android.gallery3d.data.SnailSource;
import com.android.gallery3d.picasasource.PicasaSource;
import com.android.gallery3d.ui.DetailsHelper;
import com.android.gallery3d.ui.DetailsHelper.CloseListener;
@@ -106,6 +108,11 @@ public class PhotoPage extends ActivityState
private ShareActionProvider mShareActionProvider;
private String mSetPathString;
+ // This is for testing only. It should be removed once we have the real
+ // Camera view.
+ private CameraView mCameraView;
+ private ScreenNailBridge mScreenNail;
+
public static interface Model extends PhotoView.Model {
public void resume();
public void pause();
@@ -180,6 +187,14 @@ public class PhotoPage extends ActivityState
Path itemPath = Path.fromString(data.getString(KEY_MEDIA_ITEM_PATH));
if (mSetPathString != null) {
+ // Uncomment the block below to test camera screennail.
+ /*
+ Path cameraScreenNailSetPath = addCameraScreenNail();
+
+ // Combine the original MediaSet with the one for camera ScreenNail.
+ mSetPathString = "/combo/item/{" + cameraScreenNailSetPath + "," +
+ mSetPathString + "}";
+ */
mMediaSet = mActivity.getDataManager().getMediaSet(mSetPathString);
mCurrentIndex = data.getInt(KEY_INDEX_HINT, 0);
mMediaSet = (MediaSet)
@@ -259,6 +274,34 @@ public class PhotoPage extends ActivityState
mPhotoView.setOpenedItem(itemPath);
}
+ // We create a Camera View and a ScreenNail. The two work together
+ // to present the view together with other pictures. Returns the
+ // Path of the MediaItem hosting the ScreenNail.
+ private Path addCameraScreenNail() {
+ // Create a camera view and add it to the root.
+ Activity activity = (Activity) mActivity;
+ mCameraView = new CameraView(activity);
+ ViewGroup galleryRoot = (ViewGroup) activity.findViewById(R.id.gallery_root);
+ galleryRoot.addView(mCameraView);
+
+ // Create a ScreenNail and register it.
+ mScreenNail = new ScreenNailBridge(mCameraView);
+ mCameraView.setScreenNailBridge(mScreenNail);
+ return SnailSource.registerScreenNail(mScreenNail);
+ }
+
+ private void removeCameraScreenNail() {
+ if (mCameraView == null) return;
+
+ // Remove the camera view.
+ ((ViewGroup) mCameraView.getParent()).removeView(mCameraView);
+ mCameraView = null;
+
+ // Unregister the ScreenNail.
+ SnailSource.unregisterScreenNail(mScreenNail);
+ mScreenNail = null;
+ }
+
private void updateShareURI(Path path) {
if (mShareActionProvider != null) {
DataManager manager = mActivity.getDataManager();
@@ -296,7 +339,9 @@ public class PhotoPage extends ActivityState
mPhotoView.showVideoPlayIcon(
photo.getMediaType() == MediaObject.MEDIA_TYPE_VIDEO);
- updateShareURI(photo.getPath());
+ if ((photo.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) {
+ updateShareURI(photo.getPath());
+ }
}
private void updateMenuOperations() {
@@ -633,6 +678,12 @@ public class PhotoPage extends ActivityState
onUserInteraction();
}
+ @Override
+ protected void onDestroy() {
+ removeCameraScreenNail();
+ super.onDestroy();
+ }
+
private class MyDetailsSource implements DetailsSource {
private int mIndex;
diff --git a/src/com/android/gallery3d/app/ScreenNailBridge.java b/src/com/android/gallery3d/app/ScreenNailBridge.java
new file mode 100644
index 000000000..9da197dca
--- /dev/null
+++ b/src/com/android/gallery3d/app/ScreenNailBridge.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.app;
+
+import android.graphics.RectF;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.gallery3d.ui.GLCanvas;
+import com.android.gallery3d.ui.ScreenNail;
+
+// This is a ScreenNail whose actually display is done by an foreign component.
+// The foreign component tells the ScreenNail its size by setSize(). The
+// ScreenNail tells the foreign component the position to display by
+// updateView().
+class ScreenNailBridge implements ScreenNail {
+ private static final String TAG = "ScreenNailBridge";
+ private int mWidth, mHeight;
+ private boolean mVisible = false;
+ private int mDrawX, mDrawY, mDrawWidth, mDrawHeight;
+ private Listener mListener;
+ private Handler mMainHandler;
+
+ public interface Listener {
+ // This is called from the main thread.
+ void updateView(boolean visible, int x, int y, int width, int height);
+ };
+
+ // The constructor should be called from the main thread.
+ public ScreenNailBridge(Listener listener) {
+ mListener = listener;
+ mMainHandler = new Handler();
+ }
+
+ // This can be called from any thread. (We expect it to be called from the
+ // main thread).
+ public synchronized void setSize(int w, int h) {
+ mWidth = w;
+ mHeight = h;
+ }
+
+ // This can be called from any thread. (We expect it to be called from GL
+ // thread)
+ @Override
+ public synchronized int getWidth() {
+ return mWidth;
+ }
+
+ // This can be called from any thread. (We expect it to be called from GL
+ // thread)
+ @Override
+ public synchronized int getHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public int getRotation() {
+ return 0;
+ }
+
+ // This is run in the main thread.
+ private Runnable mUpdateViewRunnable = new Runnable() {
+ public void run() {
+ boolean v;
+ int x, y, width, height;
+ synchronized (ScreenNailBridge.this) {
+ v = mVisible;
+ x = mDrawX;
+ y = mDrawY;
+ width = mDrawWidth;
+ height = mDrawHeight;
+ }
+ mListener.updateView(v, x, y, width, height);
+ }
+ };
+
+ @Override
+ public synchronized void draw(GLCanvas canvas, int x, int y, int width, int height) {
+ if (mVisible && mDrawX == x && mDrawY == y && mDrawWidth == width &&
+ mDrawHeight == height) {
+ return;
+ }
+ mVisible = true;
+ mDrawX = x;
+ mDrawY = y;
+ mDrawWidth = width;
+ mDrawHeight = height;
+ mMainHandler.post(mUpdateViewRunnable);
+ }
+
+ @Override
+ public synchronized void disableDraw() {
+ if (!mVisible) return;
+ mVisible = false;
+ mMainHandler.post(mUpdateViewRunnable);
+ }
+
+ @Override
+ public void recycle() {
+ // Make sure we will not draw anymore.
+ disableDraw();
+ }
+
+ @Override
+ public void draw(GLCanvas canvas, RectF source, RectF dest) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
index adad8fdf4..66e7c20df 100644
--- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
@@ -28,7 +28,7 @@ import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.Path;
import com.android.gallery3d.ui.PhotoView;
-import com.android.gallery3d.ui.PhotoView.ImageData;
+import com.android.gallery3d.ui.ScreenNail;
import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.ui.TileImageViewAdapter;
import com.android.gallery3d.util.Future;
@@ -115,7 +115,7 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
private void onDecodeLargeComplete(ImageBundle bundle) {
try {
- setBackupImage(bundle.backupImage,
+ setScreenNail(bundle.backupImage,
bundle.decoder.getWidth(), bundle.decoder.getHeight());
setRegionDecoder(bundle.decoder);
mPhotoView.notifyImageInvalidated(0);
@@ -128,7 +128,7 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
try {
Bitmap backup = future.get();
if (backup == null) return;
- setBackupImage(backup, backup.getWidth(), backup.getHeight());
+ setScreenNail(backup, backup.getWidth(), backup.getHeight());
mPhotoView.notifyOnNewImage();
mPhotoView.notifyImageInvalidated(0); // the current image
} catch (Throwable t) {
@@ -158,11 +158,11 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
}
}
- public ImageData getNextImage() {
+ public ScreenNail getNextScreenNail() {
return null;
}
- public ImageData getPreviousImage() {
+ public ScreenNail getPrevScreenNail() {
return null;
}