diff options
author | Doris Liu <tianliu@google.com> | 2013-12-17 18:41:15 -0800 |
---|---|---|
committer | Doris Liu <tianliu@google.com> | 2013-12-17 23:33:29 -0800 |
commit | 70da918464276b110c43868caa272c97baadb89e (patch) | |
tree | a5c9b99ca860e3e6be32cd36fefb5fcc5f1e3511 | |
parent | db44ef57cdb576704b1aafb2b81e30bf9ff261ad (diff) | |
download | android_packages_apps_Camera2-70da918464276b110c43868caa272c97baadb89e.tar.gz android_packages_apps_Camera2-70da918464276b110c43868caa272c97baadb89e.tar.bz2 android_packages_apps_Camera2-70da918464276b110c43868caa272c97baadb89e.zip |
Centralized TextureView transform logic
Automated transform matrix adjustment and bottom bar adjustment for
orientation or preview size change.
Bug: 12177718
Bug: 12179046
Change-Id: I4cd6fc90bb549774cfd83aaf8ac9654711a5c752
-rw-r--r-- | res/layout-land/bottom_bar.xml | 2 | ||||
-rw-r--r-- | res/layout-port/bottom_bar.xml | 2 | ||||
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 11 | ||||
-rw-r--r-- | src/com/android/camera/PhotoController.java | 3 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 5 | ||||
-rw-r--r-- | src/com/android/camera/PhotoUI.java | 54 | ||||
-rw-r--r-- | src/com/android/camera/TextureViewHelper.java | 208 | ||||
-rw-r--r-- | src/com/android/camera/VideoController.java | 2 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 5 | ||||
-rw-r--r-- | src/com/android/camera/VideoUI.java | 55 | ||||
-rw-r--r-- | src/com/android/camera/app/AppController.java | 18 | ||||
-rw-r--r-- | src/com/android/camera/app/CameraAppUI.java | 137 | ||||
-rw-r--r-- | src/com/android/camera/ui/BottomBar.java | 107 | ||||
-rw-r--r-- | src/com/android/camera/ui/PreviewStatusListener.java | 26 |
14 files changed, 414 insertions, 221 deletions
diff --git a/res/layout-land/bottom_bar.xml b/res/layout-land/bottom_bar.xml index 1d2ca0b25..e7b44c5ed 100644 --- a/res/layout-land/bottom_bar.xml +++ b/res/layout-land/bottom_bar.xml @@ -20,7 +20,7 @@ <com.android.camera.ui.BottomBar android:id="@+id/bottom_bar" android:layout_height="match_parent" - android:layout_width="@dimen/bottom_bar_height_optimal" + android:layout_width="match_parent" android:layout_gravity="right" android:paddingTop="@dimen/camera_controls_padding_start" android:paddingBottom="@dimen/camera_controls_padding_end" diff --git a/res/layout-port/bottom_bar.xml b/res/layout-port/bottom_bar.xml index 01fe00160..9102bc6b9 100644 --- a/res/layout-port/bottom_bar.xml +++ b/res/layout-port/bottom_bar.xml @@ -20,7 +20,7 @@ <com.android.camera.ui.BottomBar android:id="@+id/bottom_bar" android:layout_width="match_parent" - android:layout_height="@dimen/bottom_bar_height_optimal" + android:layout_height="match_parent" android:layout_gravity="bottom" android:paddingLeft="@dimen/camera_controls_padding_start" android:paddingRight="@dimen/camera_controls_padding_end" diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 55d1c9021..8579b3d8d 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -32,6 +32,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.SurfaceTexture; import android.graphics.drawable.ColorDrawable; import android.net.Uri; @@ -668,6 +669,16 @@ public class CameraActivity extends Activity } @Override + public void updatePreviewAspectRatio(float aspectRatio) { + mCameraAppUI.updatePreviewAspectRatio(aspectRatio); + } + + @Override + public void updatePreviewTransform(Matrix matrix) { + mCameraAppUI.updatePreviewTransform(matrix); + } + + @Override public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) { mCameraAppUI.setPreviewStatusListener(previewStatusListener); } diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index bb80d62fa..1de9d130e 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -55,6 +55,8 @@ public interface PhotoController extends OnShutterButtonListener { public void onPreviewRectChanged(Rect previewRect); + public void updatePreviewAspectRatio(float aspectRatio); + public void updateCameraOrientation(); /** @@ -78,4 +80,5 @@ public interface PhotoController extends OnShutterButtonListener { * Starts the pre-capture animation. */ public void startPreCaptureAnimation(); + } diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index c4c7a4ef9..891b814c2 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -517,6 +517,11 @@ public class PhotoModule mFocusManager.setPreviewRect(previewRect); } + @Override + public void updatePreviewAspectRatio(float aspectRatio) { + mAppController.updatePreviewAspectRatio(aspectRatio); + } + private void resetExposureCompensation() { SettingsManager settingsManager = mActivity.getSettingsManager(); if (settingsManager == null) { diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index dc790ddac..ed15407e3 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -29,13 +29,8 @@ import android.view.MotionEvent; import android.view.TextureView; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.view.ViewStub; -import android.widget.CompoundButton; -import android.widget.FrameLayout.LayoutParams; -import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.Toast; import com.android.camera.FocusOverlayManager.FocusUI; @@ -57,6 +52,7 @@ public class PhotoUI implements private static final String TAG = "PhotoUI"; private static final int DOWN_SAMPLE_FACTOR = 4; + private static final float UNSET = 0f; private final PreviewOverlay mPreviewOverlay; private CameraActivity mActivity; @@ -80,11 +76,9 @@ public class PhotoUI implements private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener; private TextureView mTextureView; private Matrix mMatrix = null; - private float mAspectRatio = 4f / 3f; + private float mAspectRatio = UNSET; private final Object mSurfaceTextureLock = new Object(); private BottomBar mBottomBar; - private final int mBottomBarMinHeight; - private final int mBottomBarOptimalHeight; private ButtonManager.ButtonCallback mCameraCallback; private ButtonManager.ButtonCallback mHdrCallback; @@ -135,10 +129,19 @@ public class PhotoUI implements if (mPreviewWidth != width || mPreviewHeight != height) { mPreviewWidth = width; mPreviewHeight = height; - setTransformMatrix(width, height); } } + @Override + public boolean shouldAutoAdjustTransformMatrixOnLayout() { + return true; + } + + @Override + public boolean shouldAutoAdjustBottomBar() { + return true; + } + private class DecodeTask extends AsyncTask<Void, Void, Bitmap> { private final byte [] mData; private int mOrientation; @@ -194,17 +197,8 @@ public class PhotoUI implements mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); initIndicators(); - mBottomBar = (BottomBar) mRootView.findViewById(R.id.bottom_bar); - mBottomBarMinHeight = activity.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_min); - mBottomBarOptimalHeight = activity.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); - mSurfaceTexture = mTextureView.getSurfaceTexture(); - if (mSurfaceTexture != null) { - setTransformMatrix(mTextureView.getWidth(), mTextureView.getHeight()); - } - + mBottomBar = (BottomBar) mRootView.findViewById(R.id.bottom_bar); mBottomBar.setBackgroundColor(activity.getResources().getColor(R.color.camera_mode_color)); ViewStub faceViewStub = (ViewStub) mRootView .findViewById(R.id.face_view_stub); @@ -233,17 +227,10 @@ public class PhotoUI implements if (mAspectRatio != aspectRatio) { mAspectRatio = aspectRatio; // Update transform matrix with the new aspect ratio. - if (mPreviewWidth != 0 && mPreviewHeight != 0) { - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } + mController.updatePreviewAspectRatio(mAspectRatio); } } - private void setTransformMatrix(int width, int height) { - mActivity.getCameraAppUI().adjustPreviewAndBottomBarSize(width, height, mBottomBar, - mAspectRatio, mBottomBarMinHeight, mBottomBarOptimalHeight); - } - protected Object getSurfaceTextureLock() { return mSurfaceTextureLock; } @@ -254,11 +241,6 @@ public class PhotoUI implements Log.v(TAG, "SurfaceTexture ready."); mSurfaceTexture = surface; mController.onPreviewUIReady(); - // Workaround for b/11168275, see b/10981460 for more details - if (mPreviewWidth != 0 && mPreviewHeight != 0) { - // Re-apply transform matrix for new surface texture - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } } } @@ -468,14 +450,6 @@ public class PhotoUI implements return mSurfaceTexture; } - public void showPreferencesToast() { - if (mNotSelectableToast == null) { - String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); - mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); - } - mNotSelectableToast.show(); - } - public void onPause() { if (mFaceView != null) mFaceView.clear(); } diff --git a/src/com/android/camera/TextureViewHelper.java b/src/com/android/camera/TextureViewHelper.java new file mode 100644 index 000000000..fbd4e7407 --- /dev/null +++ b/src/com/android/camera/TextureViewHelper.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2013 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.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.SurfaceTexture; +import android.util.Log; +import android.view.TextureView; +import android.view.View; +import android.view.View.OnLayoutChangeListener; + +import com.android.camera.ui.PreviewStatusListener; + +/** + * This class aims to automate TextureView transform change and notify listeners + * (e.g. bottom bar) of the preview size change. + */ +public class TextureViewHelper implements TextureView.SurfaceTextureListener, + OnLayoutChangeListener { + + private static final String TAG = "TextureViewHelper"; + private static final float UNSET = 0f; + private TextureView mPreview; + private int mWidth = 0; + private int mHeight = 0; + private float mAspectRatio = UNSET; + private boolean mAutoAdjustTransform = true; + private TextureView.SurfaceTextureListener mSurfaceTextureListener; + + private PreviewStatusListener.PreviewSizeChangedListener mPreviewSizeChangedListener; + private OnLayoutChangeListener mOnLayoutChangeListener = null; + + public TextureViewHelper(TextureView preview) { + mPreview = preview; + mPreview.addOnLayoutChangeListener(this); + mPreview.setSurfaceTextureListener(this); + } + + /** + * If auto adjust transform is enabled, when there is a layout change, the + * transform matrix will be automatically adjusted based on the preview stream + * aspect ratio in the new layout. + * + * @param enable whether or not auto adjustment should be enabled + */ + public void setAutoAdjustTransform(boolean enable) { + mAutoAdjustTransform = enable; + } + + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, + int oldTop, int oldRight, int oldBottom) { + int width = right - left; + int height = bottom - top; + if (mWidth != width || mHeight != height) { + mWidth = width; + mHeight = height; + if (mAutoAdjustTransform) { + updateTransform(); + } + } + if (mOnLayoutChangeListener != null) { + mOnLayoutChangeListener.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, + oldRight, oldBottom); + } + } + + public void updateAspectRatio(float aspectRatio) { + if (aspectRatio <= 0) { + Log.e(TAG, "Invalid aspect ratio: " + aspectRatio); + return; + } + if (aspectRatio < 1f) { + aspectRatio = 1f / aspectRatio; + } + mAspectRatio = aspectRatio; + updateTransform(); + } + + public void updateTransform(Matrix matrix) { + RectF previewRect = new RectF(0, 0, mWidth, mHeight); + matrix.mapRect(previewRect); + + float previewWidth = previewRect.width(); + float previewHeight = previewRect.height(); + if (previewHeight == 0 || previewWidth == 0) { + Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); + return; + } + mPreview.setTransform(matrix); + + onPreviewSizeChanged(previewWidth, previewHeight); + } + + public void setOnLayoutChangeListener(OnLayoutChangeListener listener) { + mOnLayoutChangeListener = listener; + } + + public void setSurfaceTextureListener(TextureView.SurfaceTextureListener listener) { + mSurfaceTextureListener = listener; + } + + /** + * Updates the transform matrix based current width and height of TextureView + * and preview stream aspect ratio. + */ + private void updateTransform() { + if (mAspectRatio == UNSET || mAspectRatio < 0 || mWidth == 0 || mHeight == 0) { + return; + } + + Matrix matrix = mPreview.getTransform(null); + float scaledTextureWidth, scaledTextureHeight; + if (mWidth > mHeight) { + scaledTextureWidth = Math.min(mWidth, + (int) (mHeight * mAspectRatio)); + scaledTextureHeight = Math.min(mHeight, + (int) (mWidth / mAspectRatio)); + } else { + scaledTextureWidth = Math.min(mWidth, + (int) (mHeight / mAspectRatio)); + scaledTextureHeight = Math.min(mHeight, + (int) (mWidth * mAspectRatio)); + } + + float scaleX = scaledTextureWidth / mWidth; + float scaleY = scaledTextureHeight / mHeight; + + boolean landscape = mWidth > mHeight; + if (landscape) { + matrix.setScale(scaleX, scaleY, 0f, (float) mHeight / 2); + } else { + matrix.setScale(scaleX, scaleY, (float) mWidth / 2, 0.0f); + } + mPreview.setTransform(matrix); + onPreviewSizeChanged(scaledTextureWidth, scaledTextureHeight); + } + + private void onPreviewSizeChanged(float scaledTextureWidth, float scaledTextureHeight) { + // Notify listeners of preview size change + if (mPreviewSizeChangedListener == null) { + return; + } + mPreviewSizeChangedListener.onPreviewSizeChanged(scaledTextureWidth, scaledTextureHeight); + } + + /** + * Sets a listener that will get notified when the preview size changed. This + * can be useful for UI elements or focus overlay to adjust themselves according + * to the preview size change. + * + * @param listener the listener that will get notified of preview size change + */ + public void setPreviewSizeChangedListener( + PreviewStatusListener.PreviewSizeChangedListener listener) { + mPreviewSizeChangedListener = listener; + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + // Workaround for b/11168275, see b/10981460 for more details + if (mWidth != 0 && mHeight != 0) { + // Re-apply transform matrix for new surface texture + updateTransform(); + } + if (mSurfaceTextureListener != null) { + mSurfaceTextureListener.onSurfaceTextureAvailable(surface, width, height); + } + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + if (mSurfaceTextureListener != null) { + mSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height); + } + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + if (mSurfaceTextureListener != null) { + mSurfaceTextureListener.onSurfaceTextureDestroyed(surface); + } + return false; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + if (mSurfaceTextureListener != null) { + mSurfaceTextureListener.onSurfaceTextureUpdated(surface); + } + + } +} diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java index 978b43862..5e17f4959 100644 --- a/src/com/android/camera/VideoController.java +++ b/src/com/android/camera/VideoController.java @@ -35,6 +35,7 @@ public interface VideoController extends OnShutterButtonListener { public void stopPreview(); public void updateCameraOrientation(); + public void updatePreviewAspectRatio(float aspectRatio); // Callbacks for camera preview UI events. public void onPreviewUIReady(); @@ -46,4 +47,5 @@ public interface VideoController extends OnShutterButtonListener { * Starts the pre-capture animation. */ public void startPreCaptureAnimation(); + } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 6153ae9fc..566d53cd8 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -611,6 +611,11 @@ public class VideoModule extends CameraModule } @Override + public void updatePreviewAspectRatio(float aspectRatio) { + mAppController.updatePreviewAspectRatio(aspectRatio); + } + + @Override public int onZoomChanged(int index) { // Not useful to change zoom value when the activity is paused. if (mPaused) return index; diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java index 802f396cf..127f7a03d 100644 --- a/src/com/android/camera/VideoUI.java +++ b/src/com/android/camera/VideoUI.java @@ -27,7 +27,6 @@ import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; @@ -46,6 +45,7 @@ import java.util.List; public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { private static final String TAG = "CAM_VideoUI"; + private final static float UNSET = 0f; private final PreviewOverlay mPreviewOverlay; // module fields private final CameraActivity mActivity; @@ -68,15 +68,10 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { private List<Integer> mZoomRatios; private final BottomBar mBottomBar; - private final int mBottomBarMinHeight; - private final int mBottomBarOptimalHeight; private SurfaceView mSurfaceView = null; - private int mPreviewWidth = 0; - private int mPreviewHeight = 0; private float mSurfaceTextureUncroppedWidth; private float mSurfaceTextureUncroppedHeight; - private float mAspectRatio = 16f / 9f; private ButtonManager.ButtonCallback mFlashCallback; private ButtonManager.ButtonCallback mCameraCallback; @@ -101,25 +96,22 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { } }; + private float mAspectRatio = UNSET; private final AnimationManager mAnimationManager; @Override public void onPreviewLayoutChanged(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - int width = right - left; - int height = bottom - top; - // Full-screen screennail - int w = width; - int h = height; - if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) { - w = height; - h = width; - } - if (mPreviewWidth != width || mPreviewHeight != height) { - mPreviewWidth = width; - mPreviewHeight = height; - onScreenSizeChanged(width, height, w, h); - } + } + + @Override + public boolean shouldAutoAdjustTransformMatrixOnLayout() { + return true; + } + + @Override + public boolean shouldAutoAdjustBottomBar() { + return true; } private final GestureDetector.OnGestureListener mPreviewGestureListener @@ -141,23 +133,13 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { moduleRoot, true); mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay); - mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); - mPreviewWidth = mTextureView.getWidth(); - mPreviewHeight = mTextureView.getHeight(); mBottomBar = (BottomBar) mRootView.findViewById(R.id.bottom_bar); mBottomBar.setButtonLayout(R.layout.video_bottombar_buttons); - mBottomBarMinHeight = activity.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_min); - mBottomBarOptimalHeight = activity.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); mBottomBar.setBackgroundColor(activity.getResources().getColor(R.color.video_mode_color)); mSurfaceTexture = mTextureView.getSurfaceTexture(); - if (mSurfaceTexture != null) { - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } initializeMiscControls(); initializeControlByIntent(); @@ -230,15 +212,6 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { setAspectRatio(aspectRatio); } - public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - setTransformMatrix(width, height); - } - - private void setTransformMatrix(int width, int height) { - mActivity.getCameraAppUI().adjustPreviewAndBottomBarSize(width, height, mBottomBar, - mAspectRatio, mBottomBarMinHeight, mBottomBarOptimalHeight); - } - /** * Starts a flash animation */ @@ -296,13 +269,11 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { public void hideSurfaceView() { mSurfaceView.setVisibility(View.GONE); mTextureView.setVisibility(View.VISIBLE); - setTransformMatrix(mPreviewWidth, mPreviewHeight); } public void showSurfaceView() { mSurfaceView.setVisibility(View.VISIBLE); mTextureView.setVisibility(View.GONE); - setTransformMatrix(mPreviewWidth, mPreviewHeight); } public void onCameraOpened(ButtonManager.ButtonCallback flashCallback, @@ -337,7 +308,7 @@ public class VideoUI implements PreviewStatusListener, SurfaceHolder.Callback { float aspectRatio = ratio > 1 ? ratio : 1 / ratio; if (aspectRatio != mAspectRatio) { mAspectRatio = aspectRatio; - setTransformMatrix(mPreviewWidth, mPreviewHeight); + mController.updatePreviewAspectRatio(mAspectRatio); } } diff --git a/src/com/android/camera/app/AppController.java b/src/com/android/camera/app/AppController.java index b9976f4b6..42046f033 100644 --- a/src/com/android/camera/app/AppController.java +++ b/src/com/android/camera/app/AppController.java @@ -19,6 +19,7 @@ package com.android.camera.app; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.Matrix; import android.graphics.SurfaceTexture; import android.net.Uri; import android.widget.FrameLayout; @@ -101,6 +102,23 @@ public interface AppController { public void onPreviewStarted(); /** + * Gets called from module when preview aspect ratio has changed. + * + * @param aspectRatio aspect ratio of preview stream + */ + public void updatePreviewAspectRatio(float aspectRatio); + + /** + * Gets called from module when the module needs to change the transform matrix + * of the preview TextureView. It is encouraged to use + * {@link #updatePreviewAspectRatio(float)} over this function, unless the module + * needs to rotate the surface texture using transform matrix. + * + * @param matrix transform matrix to be set on preview TextureView + */ + public void updatePreviewTransform(Matrix matrix); + + /** * Sets the preview status listener, which will get notified when TextureView * surface has changed * diff --git a/src/com/android/camera/app/CameraAppUI.java b/src/com/android/camera/app/CameraAppUI.java index 1109ee6af..169a31cf3 100644 --- a/src/com/android/camera/app/CameraAppUI.java +++ b/src/com/android/camera/app/CameraAppUI.java @@ -32,6 +32,7 @@ import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import com.android.camera.AnimationManager; +import com.android.camera.TextureViewHelper; import com.android.camera.filmstrip.FilmstripContentPanel; import com.android.camera.ui.BottomBar; import com.android.camera.ui.CaptureAnimationOverlay; @@ -206,9 +207,10 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, private final ModeListView mModeListView; private final FilmstripLayout mFilmstripLayout; private TextureView mTextureView; - private View mFlashOverlay; private FrameLayout mModuleUI; + private BottomBar mBottomBar; + private TextureViewHelper mTextureViewHelper; private final GestureDetector mGestureDetector; private int mSwipeState = IDLE; private PreviewOverlay mPreviewOverlay; @@ -230,114 +232,18 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, } }; - // TODO this isn't used by all modules universally, should be part of a util class or something - /** - * Resizes the preview texture and given bottom bar for 100% preview size - */ - public void adjustPreviewAndBottomBarSize(int width, int height, - BottomBar bottomBar, float aspectRatio, - int bottomBarMinHeight, int bottomBarOptimalHeight) { - Matrix matrix = mTextureView.getTransform(null); - - float scaleX = 1f, scaleY = 1f; - float scaledTextureWidth, scaledTextureHeight; - if (width > height) { - scaledTextureWidth = Math.min(width, - (int) (height * aspectRatio)); - scaledTextureHeight = Math.min(height, - (int) (width / aspectRatio)); - } else { - scaledTextureWidth = Math.min(width, - (int) (height / aspectRatio)); - scaledTextureHeight = Math.min(height, - (int) (width * aspectRatio)); - } - - scaleX = scaledTextureWidth / width; - scaleY = scaledTextureHeight / height; - - // TODO: Need a better way to find out whether currently in landscape - boolean landscape = width > height; - if (landscape) { - matrix.setScale(scaleX, scaleY, 0f, (float) height / 2); - } else { - matrix.setScale(scaleX, scaleY, (float) width / 2, 0.0f); - } - setPreviewTransformMatrix(matrix); - adjustBottomBar(width, height, bottomBar, bottomBarOptimalHeight, scaledTextureWidth, - scaledTextureHeight, landscape); - } - - private void adjustBottomBar(int width, int height, BottomBar bottomBar, - int bottomBarOptimalHeight, float scaledTextureWidth, - float scaledTextureHeight, boolean landscape) { - float previewAspectRatio = - scaledTextureWidth / scaledTextureHeight; - if (previewAspectRatio < 1.0) { - previewAspectRatio = 1.0f/previewAspectRatio; - } - float screenAspectRatio = (float)width / (float)height; - if (screenAspectRatio < 1.0) { - screenAspectRatio = 1.0f/screenAspectRatio; - } - - if(bottomBar != null) { - LayoutParams lp = (LayoutParams) bottomBar.getLayoutParams(); - // TODO accoount for cases where resizes bar height would be < bottomBarMinHeight - if (previewAspectRatio >= screenAspectRatio) { - bottomBar.setAlpha(0.5f); - if (landscape) { - lp.width = bottomBarOptimalHeight; - lp.height = LayoutParams.MATCH_PARENT; - } else { - lp.height = bottomBarOptimalHeight; - lp.width = LayoutParams.MATCH_PARENT; - } - } else { - bottomBar.setAlpha(1.0f); - if (landscape) { - lp.width = (int)(width - scaledTextureWidth); - lp.height = LayoutParams.MATCH_PARENT; - } else { - lp.height = (int)(height - scaledTextureHeight); - lp.width = LayoutParams.MATCH_PARENT; - } - } - bottomBar.setLayoutParams(lp); - } + public void updatePreviewAspectRatio(float aspectRatio) { + mTextureViewHelper.updateAspectRatio(aspectRatio); } /** * This is to support modules that calculate their own transform matrix because * they need to use a transform matrix to rotate the preview. * - * @param width width of the TextureView where preview is hosted - * @param height height of the TextureView where preview is hosted * @param matrix transform matrix to be set on the TextureView */ - public void updatePreviewTransform(int width, int height, Matrix matrix) { - if (width == 0 || height == 0) { - Log.e(TAG, "Invalid screen size: " + width + " x " + height); - return; - } - int bottomBarMinHeight = mCameraRootView.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_min); - int bottomBarOptimalHeight = mCameraRootView.getResources() - .getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); - RectF previewRect = new RectF(0, 0, width, height); - matrix.mapRect(previewRect); - - float previewWidth = previewRect.width(); - float previewHeight = previewRect.height(); - if (previewHeight == 0 || previewWidth == 0) { - Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); - return; - } - - BottomBar bottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar); - setPreviewTransformMatrix(matrix); - adjustBottomBar(width, height, bottomBar, bottomBarOptimalHeight, previewWidth, - previewHeight, width > height); + public void updatePreviewTransform(Matrix matrix) { + mTextureViewHelper.updateTransform(matrix); } public interface AnimationFinishedListener { @@ -561,6 +467,12 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, if (gestureListener != null) { mPreviewOverlay.setGestureListener(gestureListener); } + mTextureViewHelper.setAutoAdjustTransform( + mPreviewStatusListener.shouldAutoAdjustTransformMatrixOnLayout()); + if (mPreviewStatusListener.shouldAutoAdjustBottomBar()) { + mBottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar); + mTextureViewHelper.setPreviewSizeChangedListener(mBottomBar); + } } } @@ -579,8 +491,10 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout); mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content); - mTextureView.addOnLayoutChangeListener(mPreviewLayoutChangeListener); - mTextureView.setSurfaceTextureListener(this); + mTextureViewHelper = new TextureViewHelper(mTextureView); + mTextureViewHelper.setSurfaceTextureListener(this); + mTextureViewHelper.setOnLayoutChangeListener(mPreviewLayoutChangeListener); + mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay); mPreviewOverlay.setOnTouchListener(new MyTouchListener()); mCaptureOverlay = (CaptureAnimationOverlay) @@ -592,10 +506,8 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, public void clearCameraUI() { mCameraRootView.removeAllViews(); mModuleUI = null; - mTextureView.removeOnLayoutChangeListener(mPreviewLayoutChangeListener); mTextureView = null; mPreviewOverlay = null; - mFlashOverlay = null; } /** @@ -616,6 +528,9 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, if (mModuleUI != null) { mModuleUI.removeAllViews(); } + // TODO: Remove this when bottom bar is at the app level + mBottomBar = null; + mTextureViewHelper.setPreviewSizeChangedListener(null); mPreviewStatusListener = null; mPreviewOverlay.reset(); @@ -663,18 +578,6 @@ public class CameraAppUI implements ModeListView.ModeSwitchListener, } } - /** - * Sets the transform matrix on the preview TextureView - */ - public void setPreviewTransformMatrix(Matrix transformMatrix) { - if (mTextureView == null) { - throw new UnsupportedOperationException("Cannot set transform matrix on a null" + - " TextureView"); - } - mTextureView.setTransform(transformMatrix); - } - - /********************** Capture animation **********************/ /* TODO: This session is subject to UX changes. In addition to the generic flash animation and post capture animation, consider designating a parameter diff --git a/src/com/android/camera/ui/BottomBar.java b/src/com/android/camera/ui/BottomBar.java index 84dbb8727..9d1307bc8 100644 --- a/src/com/android/camera/ui/BottomBar.java +++ b/src/com/android/camera/ui/BottomBar.java @@ -19,6 +19,7 @@ package com.android.camera.ui; import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; +import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -27,6 +28,8 @@ import android.widget.GridLayout; import android.widget.LinearLayout; import android.view.MotionEvent; +import com.android.camera2.R; + /** * BottomBar swaps its width and height on rotation. In addition, it also changes * gravity and layout orientation based on the new orientation. Specifically, in @@ -37,9 +40,18 @@ import android.view.MotionEvent; * In addition to adjusting itself, this class also makes sure its children are * always spaced evenly in the new orientation. */ -public class BottomBar extends FrameLayout { +public class BottomBar extends FrameLayout + implements PreviewStatusListener.PreviewSizeChangedListener { + private static final String TAG = "BottomBar"; private final int mPaddingStart; private final int mPaddingEnd; + private int mWidth; + private int mHeight; + private float mOffsetShorterEdge; + private float mOffsetLongerEdge; + + private final int mOptimalHeight; + private boolean mOverLayBottomBar; public BottomBar(Context context, AttributeSet attrs) { super(context, attrs); @@ -52,6 +64,7 @@ public class BottomBar extends FrameLayout { mPaddingStart = getPaddingLeft(); mPaddingEnd = getPaddingRight(); } + mOptimalHeight = getResources().getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); } /** @@ -64,34 +77,88 @@ public class BottomBar extends FrameLayout { inflater.inflate(buttonLayoutId, this, true); } - /** - * Adjust layout orientation, width, height and gravity based on new orientation. - */ - private void adjustSelf(Configuration configuration) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - int shortEdge; - if (lp.width != FrameLayout.LayoutParams.MATCH_PARENT) { - shortEdge = lp.width; + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + mWidth = MeasureSpec.getSize(widthMeasureSpec); + mHeight = MeasureSpec.getSize(heightMeasureSpec); + if (mWidth == 0 || mHeight == 0) { + return; + } + + if (mOffsetShorterEdge != 0 && mOffsetLongerEdge != 0) { + float previewAspectRatio = + mOffsetLongerEdge / mOffsetShorterEdge; + if (previewAspectRatio < 1.0) { + previewAspectRatio = 1.0f/previewAspectRatio; + } + float screenAspectRatio = (float) mWidth / (float) mHeight; + if (screenAspectRatio < 1.0) { + screenAspectRatio = 1.0f/screenAspectRatio; + } + if (previewAspectRatio >= screenAspectRatio) { + mOverLayBottomBar = true; + setAlpha(0.5f); + } else { + mOverLayBottomBar = false; + setAlpha(1.0f); + } + } + + // Calculates the width and height needed for the bar. + int barWidth, barHeight; + if (mWidth > mHeight) { + ((LayoutParams) getLayoutParams()).gravity = Gravity.RIGHT; + if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) { + barWidth = mOptimalHeight; + barHeight = mHeight; + } else { + barWidth = (int) (mWidth - mOffsetLongerEdge); + barHeight = mHeight; + } } else { - shortEdge = lp.height; + ((LayoutParams) getLayoutParams()).gravity = Gravity.BOTTOM; + if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) { + barWidth = mWidth; + barHeight = mOptimalHeight; + } else { + barWidth = mWidth; + barHeight = (int) (mHeight - mOffsetLongerEdge); + } } - if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { - lp.width = FrameLayout.LayoutParams.MATCH_PARENT; - lp.height = shortEdge; - lp.gravity = Gravity.BOTTOM; - setLayoutParams(lp); + super.onMeasure(MeasureSpec.makeMeasureSpec(barWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(barHeight, MeasureSpec.EXACTLY)); + } + + private void adjustBottomBar(float scaledTextureWidth, + float scaledTextureHeight) { + setOffset(scaledTextureWidth, scaledTextureHeight); + } + + @Override + public void onPreviewSizeChanged(float scaledTextureWidth, + float scaledTextureHeight) { + adjustBottomBar(scaledTextureWidth, scaledTextureHeight); + } + + private void setOffset(float scaledTextureWidth, float scaledTextureHeight) { + float offsetLongerEdge, offsetShorterEdge; + if (scaledTextureHeight > scaledTextureWidth) { + offsetLongerEdge = scaledTextureHeight; + offsetShorterEdge = scaledTextureWidth; } else { - lp.height = FrameLayout.LayoutParams.MATCH_PARENT; - lp.width = shortEdge; - lp.gravity = Gravity.RIGHT; - setLayoutParams(lp); + offsetLongerEdge = scaledTextureWidth; + offsetShorterEdge = scaledTextureHeight; + } + if (mOffsetLongerEdge != offsetLongerEdge || mOffsetShorterEdge != offsetShorterEdge) { + mOffsetLongerEdge = offsetLongerEdge; + mOffsetShorterEdge = offsetShorterEdge; + requestLayout(); } } @Override protected void onConfigurationChanged(Configuration config) { super.onConfigurationChanged(config); - adjustSelf(config); } /** diff --git a/src/com/android/camera/ui/PreviewStatusListener.java b/src/com/android/camera/ui/PreviewStatusListener.java index d9d23ed25..54615abd0 100644 --- a/src/com/android/camera/ui/PreviewStatusListener.java +++ b/src/com/android/camera/ui/PreviewStatusListener.java @@ -39,4 +39,30 @@ public interface PreviewStatusListener extends TextureView.SurfaceTextureListene */ public void onPreviewLayoutChanged(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom); + + /** + * This listener gets notified when the actual preview frame changes size due + * to a transform matrix being applied to the TextureView + */ + public interface PreviewSizeChangedListener { + public void onPreviewSizeChanged(float previewWidth, float previewHeight); + } + + /** + * The preview status listener needs to know for the specific module whether + * preview TextureView should automatically adjust its transform matrix based + * on the current aspect ratio, width and height of the TextureView. + * + * @return whether transform matrix should be automatically adjusted + */ + public boolean shouldAutoAdjustTransformMatrixOnLayout(); + + /** + * The preview status listener needs to know for the specific module whether + * bottom bar should be automatically adjusted when preview has changed size + * or orientation. + * + * @return whether bottom bar should be automatically adjusted + */ + public boolean shouldAutoAdjustBottomBar(); } |