diff options
author | Chih-Chung Chang <chihchung@google.com> | 2012-03-15 16:38:45 +0800 |
---|---|---|
committer | Chih-Chung Chang <chihchung@google.com> | 2012-03-21 15:29:29 +0800 |
commit | 15b351a22d02e89d882fc9fe32b3f4c512080e0a (patch) | |
tree | 07a316c7f973bdb0173fc50b25837c50c65f6714 /src/com/android/gallery3d/app | |
parent | 8cab3e872dd95e55ba34fdb94269a0c5069e72ae (diff) | |
download | android_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.java | 117 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/PhotoDataAdapter.java | 57 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/PhotoPage.java | 53 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/ScreenNailBridge.java | 122 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/SinglePhotoDataAdapter.java | 10 |
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; } |