From 125efb44995fb3307572c2832b259307e8b7aadc Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Tue, 9 Apr 2013 15:02:59 -0700 Subject: Integrate FilmStripView. Change-Id: Ib9f280a4c58a5c120775d5e9340ea04d56c0343d --- src/com/android/camera/NewCameraActivity.java | 30 +++++- src/com/android/camera/NewPhotoUI.java | 14 +-- src/com/android/camera/data/CameraDataAdapter.java | 91 +++++++++++----- src/com/android/camera/ui/FilmStripView.java | 115 +++++++++++++++++++-- src/com/android/camera/ui/NewCameraRootView.java | 3 +- 5 files changed, 201 insertions(+), 52 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/camera/NewCameraActivity.java b/src/com/android/camera/NewCameraActivity.java index 46295d8f2..e8d2157da 100644 --- a/src/com/android/camera/NewCameraActivity.java +++ b/src/com/android/camera/NewCameraActivity.java @@ -24,9 +24,11 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.IBinder; import android.provider.Settings; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.View; @@ -34,7 +36,9 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import com.android.camera.data.CameraDataAdapter; import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; +import com.android.camera.ui.FilmStripView; import com.android.camera.ui.NewCameraRootView; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; @@ -56,10 +60,11 @@ public class NewCameraActivity extends Activity // panorama. If the extra is not set, it is in the normal camera mode. public static final String SECURE_CAMERA_EXTRA = "secure_camera"; - + private CameraDataAdapter mDataAdapter; private int mCurrentModuleIndex; private NewCameraModule mCurrentModule; private View mRootView; + private FilmStripView mFilmStripView; private int mResultCodeForTesting; private Intent mResultDataForTesting; private OnScreenHint mStorageHint; @@ -116,7 +121,7 @@ public class NewCameraActivity extends Activity @Override public void onCreate(Bundle state) { super.onCreate(state); - setContentView(R.layout.camera); + setContentView(R.layout.camera_filmstrip); if (ApiHelper.HAS_ROTATION_ANIMATION) { setRotationAnimation(); } @@ -140,7 +145,16 @@ public class NewCameraActivity extends Activity getApplicationContext().registerReceiver(sScreenOffReceiver, filter); } }*/ - mRootView = findViewById(R.id.camera_app_root); + LayoutInflater inflater = getLayoutInflater(); + View rootLayout = inflater.inflate(R.layout.camera, null, false); + mRootView = rootLayout.findViewById(R.id.camera_app_root); + mDataAdapter = new CameraDataAdapter( + new ColorDrawable(getResources().getColor(R.color.photo_placeholder))); + mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); + // Set up the camera preview first so the preview shows up ASAP. + mDataAdapter.setCameraPreviewInfo(rootLayout, + FilmStripView.ImageData.SIZE_FULL, FilmStripView.ImageData.SIZE_FULL); + mFilmStripView.setDataAdapter(mDataAdapter); mCurrentModule = new NewPhotoModule(); mCurrentModule.init(this, mRootView); mOrientationListener = new MyOrientationEventListener(this); @@ -184,6 +198,9 @@ public class NewCameraActivity extends Activity mCurrentModule.onResumeBeforeSuper(); super.onResume(); mCurrentModule.onResumeAfterSuper(); + + // The loading is done in background and will update the filmstrip later. + mDataAdapter.requestLoad(getContentResolver()); } @Override @@ -200,7 +217,10 @@ public class NewCameraActivity extends Activity @Override public boolean dispatchTouchEvent(MotionEvent m) { - return mCurrentModule.dispatchTouchEvent(m); + //if (mFilmStripView.isInCameraFullscreen()) { + // return mCurrentModule.dispatchTouchEvent(m); + //} + return mFilmStripView.dispatchTouchEvent(m); } public boolean isAutoRotateScreen() { return mAutoRotateScreen; @@ -323,4 +343,4 @@ public class NewCameraActivity extends Activity @Override public void onShowSwitcherPopup() { } -} \ No newline at end of file +} diff --git a/src/com/android/camera/NewPhotoUI.java b/src/com/android/camera/NewPhotoUI.java index 97f929288..d1470b2b6 100644 --- a/src/com/android/camera/NewPhotoUI.java +++ b/src/com/android/camera/NewPhotoUI.java @@ -270,7 +270,7 @@ public class NewPhotoUI implements PieListener, } private void initIndicators() { - mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators); + mOnScreenIndicators = mRootView.findViewById(R.id.on_screen_indicators); mExposureIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_exposure_indicator); mFlashIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_flash_indicator); mSceneIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_scenemode_indicator); @@ -333,8 +333,8 @@ public class NewPhotoUI implements PieListener, } public void initializeControlByIntent() { - mBlocker = mActivity.findViewById(R.id.blocker); - mMenuButton = mActivity.findViewById(R.id.menu); + mBlocker = mRootView.findViewById(R.id.blocker); + mMenuButton = mRootView.findViewById(R.id.menu); mMenuButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -343,12 +343,12 @@ public class NewPhotoUI implements PieListener, }); if (mController.isImageCaptureIntent()) { hideSwitcher(); - ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); + ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls); mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); - mReviewDoneButton = mActivity.findViewById(R.id.btn_done); - mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); - mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake); + mReviewDoneButton = mRootView.findViewById(R.id.btn_done); + mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel); + mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake); mReviewCancelButton.setVisibility(View.VISIBLE); mReviewDoneButton.setOnClickListener(new OnClickListener() { diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java index a55cc9d52..d1dad3ffb 100644 --- a/src/com/android/camera/data/CameraDataAdapter.java +++ b/src/com/android/camera/data/CameraDataAdapter.java @@ -22,7 +22,6 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.provider.MediaStore; @@ -43,10 +42,10 @@ import java.util.List; * A FilmStripDataProvider that provide data in the camera folder. * * The given view for camera preview won't be added until the preview info - * has been set by setPreviewInfo(int, int, int) + * has been set by setCameraPreviewInfo(int, int). */ public class CameraDataAdapter implements FilmStripView.DataAdapter { - private static final String TAG = "CamreaFilmStripDataProvider"; + private static final String TAG = CameraDataAdapter.class.getSimpleName(); private static final int DEFAULT_DECODE_SIZE = 3000; private static final String[] CAMERA_PATH = { Storage.DIRECTORY + "%" }; @@ -55,20 +54,25 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { private Listener mListener; private View mCameraPreviewView; - private ColorDrawable mPlaceHolder; + private Drawable mPlaceHolder; private int mSuggestedWidth = DEFAULT_DECODE_SIZE; private int mSuggestedHeight = DEFAULT_DECODE_SIZE; - public CameraDataAdapter(View cameraPreviewView, int placeHolderColor) { - mCameraPreviewView = cameraPreviewView; - mPlaceHolder = new ColorDrawable(placeHolderColor); + public CameraDataAdapter(Drawable placeHolder) { + mPlaceHolder = placeHolder; } - public void setCameraPreviewInfo(int width, int height) { + public void setCameraPreviewInfo(View cameraPreview, int width, int height) { + mCameraPreviewView = cameraPreview; addOrReplaceCameraData(buildCameraImageData(width, height)); } + public void requestLoad(ContentResolver resolver) { + QueryTask qtask = new QueryTask(); + qtask.execute(resolver); + } + @Override public int getTotalNumber() { return mImages.size(); @@ -90,11 +94,6 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { } } - public void requestLoad(ContentResolver resolver) { - QueryTask qtask = new QueryTask(); - qtask.execute(resolver); - } - @Override public View getView(Context c, int dataID) { if (dataID >= mImages.size() || dataID < 0) { @@ -108,6 +107,7 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { @Override public void setListener(Listener listener) { mListener = listener; + if (mImages != null) mListener.onDataLoaded(); } private LocalData buildCameraImageData(int width, int height) { @@ -118,15 +118,36 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { private void addOrReplaceCameraData(LocalData data) { if (mImages == null) mImages = new ArrayList(); if (mImages.size() == 0) { + // No data at all. mImages.add(0, data); + if (mListener != null) mListener.onDataLoaded(); return; } LocalData first = mImages.get(0); if (first.getType() == ImageData.TYPE_CAMERA_PREVIEW) { + // Replace the old camera data. mImages.set(0, data); + if (mListener != null) { + mListener.onDataUpdated(new StatusReporter() { + @Override + public boolean isDataRemoved(int id) { + return false; + } + + @Override + public boolean isDataUpdated(int id) { + if (id == 0) return true; + return false; + } + }); + } } else { + // Add a new camera data. mImages.add(0, data); + if (mListener != null) { + mListener.onDataLoaded(); + } } } @@ -161,15 +182,33 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { @Override protected void onPostExecute(List l) { boolean changed = (l != mImages); - LocalData first = null; + LocalData cameraData = null; if (mImages != null && mImages.size() > 0) { - first = mImages.get(0); - if (first.getType() != ImageData.TYPE_CAMERA_PREVIEW) first = null; + cameraData = mImages.get(0); + if (cameraData.getType() != ImageData.TYPE_CAMERA_PREVIEW) cameraData = null; } + mImages = l; - if (first != null) addOrReplaceCameraData(first); - // both might be null. - if (changed) mListener.onDataLoaded(); + if (cameraData != null) { + l.add(0, cameraData); + if (mListener != null) { + mListener.onDataUpdated(new StatusReporter() { + @Override + public boolean isDataRemoved(int id) { + return false; + } + + @Override + public boolean isDataUpdated(int id) { + if (id == 0) return false; + return true; + } + }); + } + } else { + // both might be null. + if (changed) mListener.onDataLoaded(); + } } } @@ -199,28 +238,25 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { } @Override - abstract public int getType(); + public abstract int getType(); abstract View getView(Context c, int width, int height, Drawable placeHolder); } private class CameraPreviewData extends LocalData { - private int mWidth; - private int mHeight; - CameraPreviewData(int w, int h) { - mWidth = w; - mHeight = h; + width = w; + height = h; } @Override public int getWidth() { - return mWidth; + return width; } @Override public int getHeight() { - return mHeight; + return height; } @Override @@ -380,6 +416,7 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { Log.e(TAG, "Cannot decode bitmap file:" + path); return; } + mView.setScaleType(ImageView.ScaleType.FIT_XY); mView.setImageBitmap(bitmap); } } diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index eea9f0155..0a19effb2 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -18,7 +18,6 @@ package com.android.camera.ui; import android.animation.Animator; import android.animation.ValueAnimator; -import android.content.ContentResolver; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; @@ -30,7 +29,7 @@ import android.view.animation.DecelerateInterpolator; import android.widget.Scroller; public class FilmStripView extends ViewGroup { - private static final String TAG = "FilmStripView"; + private static final String TAG = FilmStripView.class.getSimpleName(); private static final int BUFFER_SIZE = 5; // Horizontal padding of children. private static final int H_PADDING = 50; @@ -52,6 +51,13 @@ public class FilmStripView extends ViewGroup { private int mCenterPosition = -1; private ViewInfo[] mViewInfo = new ViewInfo[BUFFER_SIZE]; + // This is used to resolve the misalignment problem when the device + // orientation is changed. If the current item is in fullscreen, it might + // be shifted because mCenterPosition is not adjusted with the orientation. + // Set this to true when onSizeChanged is called to make sure we adjust + // mCenterPosition accordingly. + private boolean mAnchorPending; + public interface ImageData { public static final int TYPE_NONE = 0; public static final int TYPE_CAMERA_PREVIEW = 1; @@ -77,8 +83,18 @@ public class FilmStripView extends ViewGroup { } public interface DataAdapter { + public interface StatusReporter { + public boolean isDataRemoved(int id); + public boolean isDataUpdated(int id); + } + public interface Listener { + // Called when the whole data loading is done. No any assumption + // on previous data. public void onDataLoaded(); + // Only some of the data is changed. The listener should check + // if any thing needs to be updated. + public void onDataUpdated(StatusReporter reporter); public void onDataInserted(int dataID); public void onDataRemoved(int dataID); } @@ -170,6 +186,11 @@ public class FilmStripView extends ViewGroup { private void init(Context context) { mCurrentInfo = (BUFFER_SIZE - 1) / 2; + // This is for positioning camera controller at the same place in + // different orientations. + setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + setWillNotDraw(false); mContext = context; mScale = 1.0f; @@ -191,6 +212,7 @@ public class FilmStripView extends ViewGroup { } public int getCurrentType() { + if (mDataAdapter == null) return ImageData.TYPE_NONE; ViewInfo curr = mViewInfo[mCurrentInfo]; if (curr == null) return ImageData.TYPE_NONE; return mDataAdapter.getImageData(curr.getID()).getType(); @@ -271,8 +293,9 @@ public class FilmStripView extends ViewGroup { View v = mDataAdapter.getView(mContext, dataID); if (v == null) return null; v.setPadding(H_PADDING, 0, H_PADDING, 0); - addView(v); - return new ViewInfo(dataID, v); + ViewInfo info = new ViewInfo(dataID, v); + addView(info.getView()); + return info; } // We try to keep the one closest to the center of the screen at position mCurrentInfo. @@ -330,6 +353,11 @@ public class FilmStripView extends ViewGroup { } private void layoutChildren() { + if (mAnchorPending) { + mCenterPosition = mViewInfo[mCurrentInfo].getCenterX(); + mAnchorPending = false; + } + if (mGeometryAnimator.hasNewGeometry()) { mCenterPosition = mGeometryAnimator.getNewPosition(); mScale = mGeometryAnimator.getNewScale(); @@ -377,6 +405,15 @@ public class FilmStripView extends ViewGroup { layoutChildren(); } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + if (w == oldw && h == oldh) return; + if (mViewInfo[mCurrentInfo] != null && mScale == 1f + && isAnchoredTo(mViewInfo[mCurrentInfo].getID())) { + mAnchorPending = true; + } + } + public void setDataAdapter(DataAdapter adapter) { mDataAdapter = adapter; mDataAdapter.suggestSize(getMeasuredWidth(), getMeasuredHeight()); @@ -386,6 +423,11 @@ public class FilmStripView extends ViewGroup { reload(); } + @Override + public void onDataUpdated(DataAdapter.StatusReporter reporter) { + update(reporter); + } + @Override public void onDataInserted(int dataID) { } @@ -413,18 +455,69 @@ public class FilmStripView extends ViewGroup { return true; } - public void reload() { + private void updateViewInfo(int infoID) { + ViewInfo info = mViewInfo[infoID]; + removeView(info.getView()); + mViewInfo[infoID] = buildInfoFromData(info.getID()); + } + + // Some of the data is changed. + private void update(DataAdapter.StatusReporter reporter) { + // No data yet. + if (mViewInfo[mCurrentInfo] == null) { + reload(); + return; + } + + // Check the current one. + ViewInfo curr = mViewInfo[mCurrentInfo]; + int dataID = curr.getID(); + if (reporter.isDataRemoved(dataID)) { + mCenterPosition = -1; + reload(); + return; + } + if (reporter.isDataUpdated(dataID)) { + updateViewInfo(mCurrentInfo); + } + + // Check left + for (int i = mCurrentInfo - 1; i >= 0; i--) { + curr = mViewInfo[i]; + if (curr != null) { + dataID = curr.getID(); + if (reporter.isDataRemoved(dataID) || reporter.isDataUpdated(dataID)) { + updateViewInfo(i); + } + } else { + ViewInfo next = mViewInfo[i + 1]; + if (next != null) mViewInfo[i] = buildInfoFromData(next.getID() - 1); + } + } + + // Check right + for (int i = mCurrentInfo + 1; i < BUFFER_SIZE; i++) { + curr = mViewInfo[i]; + if (curr != null) { + dataID = curr.getID(); + if (reporter.isDataRemoved(dataID) || reporter.isDataUpdated(dataID)) { + updateViewInfo(i); + } + } else { + ViewInfo prev = mViewInfo[i - 1]; + if (prev != null) mViewInfo[i] = buildInfoFromData(prev.getID() + 1); + } + } + } + + // The whole data might be totally different. Flush all and load from the start. + private void reload() { removeAllViews(); int dataNumber = mDataAdapter.getTotalNumber(); if (dataNumber == 0) return; int currentData = 0; int currentLeft = 0; - // previous data exists. - if (mViewInfo[mCurrentInfo] != null) { - currentLeft = mViewInfo[mCurrentInfo].getLeftPosition(); - currentData = mViewInfo[mCurrentInfo].getID(); - } mViewInfo[mCurrentInfo] = buildInfoFromData(currentData); mViewInfo[mCurrentInfo].setLeftPosition(currentLeft); if (getCurrentType() == ImageData.TYPE_CAMERA_PREVIEW @@ -624,7 +717,7 @@ public class FilmStripView extends ViewGroup { @Override public boolean onScroll(float x, float y, float dx, float dy) { int deltaX = (int) (dx / mScale); - if (deltaX > 0 && isInCameraFullscreen() ) { + if (deltaX > 0 && isInCameraFullscreen()) { mGeometryAnimator.unlockPosition(); mGeometryAnimator.scaleTo(FILM_STRIP_SCALE, DURATION_GEOMETRY_ADJUST, false); } diff --git a/src/com/android/camera/ui/NewCameraRootView.java b/src/com/android/camera/ui/NewCameraRootView.java index 2d683bc3b..a507b147c 100644 --- a/src/com/android/camera/ui/NewCameraRootView.java +++ b/src/com/android/camera/ui/NewCameraRootView.java @@ -34,8 +34,7 @@ public class NewCameraRootView extends FrameLayout private int mOffset = 0; public NewCameraRootView(Context context, AttributeSet attrs) { super(context, attrs); - setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } -- cgit v1.2.3