TextureViewHelper.java revision 15b9961c5ca49fc6ac9d036e7a967797987e46ee
170da918464276b110c43868caa272c97baadb89eDoris Liu/* 270da918464276b110c43868caa272c97baadb89eDoris Liu * Copyright (C) 2013 The Android Open Source Project 370da918464276b110c43868caa272c97baadb89eDoris Liu * 470da918464276b110c43868caa272c97baadb89eDoris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 570da918464276b110c43868caa272c97baadb89eDoris Liu * you may not use this file except in compliance with the License. 670da918464276b110c43868caa272c97baadb89eDoris Liu * You may obtain a copy of the License at 770da918464276b110c43868caa272c97baadb89eDoris Liu * 870da918464276b110c43868caa272c97baadb89eDoris Liu * http://www.apache.org/licenses/LICENSE-2.0 970da918464276b110c43868caa272c97baadb89eDoris Liu * 1070da918464276b110c43868caa272c97baadb89eDoris Liu * Unless required by applicable law or agreed to in writing, software 1170da918464276b110c43868caa272c97baadb89eDoris Liu * distributed under the License is distributed on an "AS IS" BASIS, 1270da918464276b110c43868caa272c97baadb89eDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1370da918464276b110c43868caa272c97baadb89eDoris Liu * See the License for the specific language governing permissions and 1470da918464276b110c43868caa272c97baadb89eDoris Liu * limitations under the License. 1570da918464276b110c43868caa272c97baadb89eDoris Liu */ 1670da918464276b110c43868caa272c97baadb89eDoris Liu 1770da918464276b110c43868caa272c97baadb89eDoris Liupackage com.android.camera; 1870da918464276b110c43868caa272c97baadb89eDoris Liu 1970da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.Matrix; 2070da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.RectF; 2170da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.SurfaceTexture; 2270da918464276b110c43868caa272c97baadb89eDoris Liuimport android.util.Log; 2370da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.TextureView; 2470da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View; 2570da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View.OnLayoutChangeListener; 2670da918464276b110c43868caa272c97baadb89eDoris Liu 2770da918464276b110c43868caa272c97baadb89eDoris Liuimport com.android.camera.ui.PreviewStatusListener; 2870da918464276b110c43868caa272c97baadb89eDoris Liu 29482de029dc20e0a577388a602985fb31c3200309Doris Liuimport java.util.ArrayList; 30482de029dc20e0a577388a602985fb31c3200309Doris Liu 3170da918464276b110c43868caa272c97baadb89eDoris Liu/** 3270da918464276b110c43868caa272c97baadb89eDoris Liu * This class aims to automate TextureView transform change and notify listeners 3370da918464276b110c43868caa272c97baadb89eDoris Liu * (e.g. bottom bar) of the preview size change. 3470da918464276b110c43868caa272c97baadb89eDoris Liu */ 3570da918464276b110c43868caa272c97baadb89eDoris Liupublic class TextureViewHelper implements TextureView.SurfaceTextureListener, 3670da918464276b110c43868caa272c97baadb89eDoris Liu OnLayoutChangeListener { 3770da918464276b110c43868caa272c97baadb89eDoris Liu 3870da918464276b110c43868caa272c97baadb89eDoris Liu private static final String TAG = "TextureViewHelper"; 3970da918464276b110c43868caa272c97baadb89eDoris Liu private static final float UNSET = 0f; 4070da918464276b110c43868caa272c97baadb89eDoris Liu private TextureView mPreview; 4170da918464276b110c43868caa272c97baadb89eDoris Liu private int mWidth = 0; 4270da918464276b110c43868caa272c97baadb89eDoris Liu private int mHeight = 0; 4370da918464276b110c43868caa272c97baadb89eDoris Liu private float mAspectRatio = UNSET; 4470da918464276b110c43868caa272c97baadb89eDoris Liu private boolean mAutoAdjustTransform = true; 4570da918464276b110c43868caa272c97baadb89eDoris Liu private TextureView.SurfaceTextureListener mSurfaceTextureListener; 4670da918464276b110c43868caa272c97baadb89eDoris Liu 47482de029dc20e0a577388a602985fb31c3200309Doris Liu private final ArrayList<PreviewStatusListener.PreviewAreaSizeChangedListener> 48482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners = 49482de029dc20e0a577388a602985fb31c3200309Doris Liu new ArrayList<PreviewStatusListener.PreviewAreaSizeChangedListener>(); 5070da918464276b110c43868caa272c97baadb89eDoris Liu private OnLayoutChangeListener mOnLayoutChangeListener = null; 5170da918464276b110c43868caa272c97baadb89eDoris Liu 5270da918464276b110c43868caa272c97baadb89eDoris Liu public TextureViewHelper(TextureView preview) { 5370da918464276b110c43868caa272c97baadb89eDoris Liu mPreview = preview; 5470da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.addOnLayoutChangeListener(this); 5570da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setSurfaceTextureListener(this); 5670da918464276b110c43868caa272c97baadb89eDoris Liu } 5770da918464276b110c43868caa272c97baadb89eDoris Liu 5870da918464276b110c43868caa272c97baadb89eDoris Liu /** 5970da918464276b110c43868caa272c97baadb89eDoris Liu * If auto adjust transform is enabled, when there is a layout change, the 6070da918464276b110c43868caa272c97baadb89eDoris Liu * transform matrix will be automatically adjusted based on the preview stream 6170da918464276b110c43868caa272c97baadb89eDoris Liu * aspect ratio in the new layout. 6270da918464276b110c43868caa272c97baadb89eDoris Liu * 6370da918464276b110c43868caa272c97baadb89eDoris Liu * @param enable whether or not auto adjustment should be enabled 6470da918464276b110c43868caa272c97baadb89eDoris Liu */ 6570da918464276b110c43868caa272c97baadb89eDoris Liu public void setAutoAdjustTransform(boolean enable) { 6670da918464276b110c43868caa272c97baadb89eDoris Liu mAutoAdjustTransform = enable; 6770da918464276b110c43868caa272c97baadb89eDoris Liu } 6870da918464276b110c43868caa272c97baadb89eDoris Liu 6970da918464276b110c43868caa272c97baadb89eDoris Liu @Override 7070da918464276b110c43868caa272c97baadb89eDoris Liu public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 7170da918464276b110c43868caa272c97baadb89eDoris Liu int oldTop, int oldRight, int oldBottom) { 7270da918464276b110c43868caa272c97baadb89eDoris Liu int width = right - left; 7370da918464276b110c43868caa272c97baadb89eDoris Liu int height = bottom - top; 7470da918464276b110c43868caa272c97baadb89eDoris Liu if (mWidth != width || mHeight != height) { 7570da918464276b110c43868caa272c97baadb89eDoris Liu mWidth = width; 7670da918464276b110c43868caa272c97baadb89eDoris Liu mHeight = height; 7770da918464276b110c43868caa272c97baadb89eDoris Liu if (mAutoAdjustTransform) { 7870da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 7970da918464276b110c43868caa272c97baadb89eDoris Liu } 8070da918464276b110c43868caa272c97baadb89eDoris Liu } 8170da918464276b110c43868caa272c97baadb89eDoris Liu if (mOnLayoutChangeListener != null) { 8270da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, 8370da918464276b110c43868caa272c97baadb89eDoris Liu oldRight, oldBottom); 8470da918464276b110c43868caa272c97baadb89eDoris Liu } 8570da918464276b110c43868caa272c97baadb89eDoris Liu } 8670da918464276b110c43868caa272c97baadb89eDoris Liu 8770da918464276b110c43868caa272c97baadb89eDoris Liu public void updateAspectRatio(float aspectRatio) { 8870da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio <= 0) { 8970da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid aspect ratio: " + aspectRatio); 9070da918464276b110c43868caa272c97baadb89eDoris Liu return; 9170da918464276b110c43868caa272c97baadb89eDoris Liu } 9270da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio < 1f) { 9370da918464276b110c43868caa272c97baadb89eDoris Liu aspectRatio = 1f / aspectRatio; 9470da918464276b110c43868caa272c97baadb89eDoris Liu } 9570da918464276b110c43868caa272c97baadb89eDoris Liu mAspectRatio = aspectRatio; 9670da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 9770da918464276b110c43868caa272c97baadb89eDoris Liu } 9870da918464276b110c43868caa272c97baadb89eDoris Liu 9970da918464276b110c43868caa272c97baadb89eDoris Liu public void updateTransform(Matrix matrix) { 10070da918464276b110c43868caa272c97baadb89eDoris Liu RectF previewRect = new RectF(0, 0, mWidth, mHeight); 10170da918464276b110c43868caa272c97baadb89eDoris Liu matrix.mapRect(previewRect); 10270da918464276b110c43868caa272c97baadb89eDoris Liu 10370da918464276b110c43868caa272c97baadb89eDoris Liu float previewWidth = previewRect.width(); 10470da918464276b110c43868caa272c97baadb89eDoris Liu float previewHeight = previewRect.height(); 10570da918464276b110c43868caa272c97baadb89eDoris Liu if (previewHeight == 0 || previewWidth == 0) { 10670da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); 10770da918464276b110c43868caa272c97baadb89eDoris Liu return; 10870da918464276b110c43868caa272c97baadb89eDoris Liu } 10970da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 11070da918464276b110c43868caa272c97baadb89eDoris Liu 11170da918464276b110c43868caa272c97baadb89eDoris Liu onPreviewSizeChanged(previewWidth, previewHeight); 11270da918464276b110c43868caa272c97baadb89eDoris Liu } 11370da918464276b110c43868caa272c97baadb89eDoris Liu 11470da918464276b110c43868caa272c97baadb89eDoris Liu public void setOnLayoutChangeListener(OnLayoutChangeListener listener) { 11570da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener = listener; 11670da918464276b110c43868caa272c97baadb89eDoris Liu } 11770da918464276b110c43868caa272c97baadb89eDoris Liu 11870da918464276b110c43868caa272c97baadb89eDoris Liu public void setSurfaceTextureListener(TextureView.SurfaceTextureListener listener) { 11970da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener = listener; 12070da918464276b110c43868caa272c97baadb89eDoris Liu } 12170da918464276b110c43868caa272c97baadb89eDoris Liu 12270da918464276b110c43868caa272c97baadb89eDoris Liu /** 12370da918464276b110c43868caa272c97baadb89eDoris Liu * Updates the transform matrix based current width and height of TextureView 12470da918464276b110c43868caa272c97baadb89eDoris Liu * and preview stream aspect ratio. 12570da918464276b110c43868caa272c97baadb89eDoris Liu */ 12670da918464276b110c43868caa272c97baadb89eDoris Liu private void updateTransform() { 12770da918464276b110c43868caa272c97baadb89eDoris Liu if (mAspectRatio == UNSET || mAspectRatio < 0 || mWidth == 0 || mHeight == 0) { 12870da918464276b110c43868caa272c97baadb89eDoris Liu return; 12970da918464276b110c43868caa272c97baadb89eDoris Liu } 13070da918464276b110c43868caa272c97baadb89eDoris Liu 13170da918464276b110c43868caa272c97baadb89eDoris Liu Matrix matrix = mPreview.getTransform(null); 13270da918464276b110c43868caa272c97baadb89eDoris Liu float scaledTextureWidth, scaledTextureHeight; 13370da918464276b110c43868caa272c97baadb89eDoris Liu if (mWidth > mHeight) { 13470da918464276b110c43868caa272c97baadb89eDoris Liu scaledTextureWidth = Math.min(mWidth, 13570da918464276b110c43868caa272c97baadb89eDoris Liu (int) (mHeight * mAspectRatio)); 13670da918464276b110c43868caa272c97baadb89eDoris Liu scaledTextureHeight = Math.min(mHeight, 13770da918464276b110c43868caa272c97baadb89eDoris Liu (int) (mWidth / mAspectRatio)); 13870da918464276b110c43868caa272c97baadb89eDoris Liu } else { 13970da918464276b110c43868caa272c97baadb89eDoris Liu scaledTextureWidth = Math.min(mWidth, 14070da918464276b110c43868caa272c97baadb89eDoris Liu (int) (mHeight / mAspectRatio)); 14170da918464276b110c43868caa272c97baadb89eDoris Liu scaledTextureHeight = Math.min(mHeight, 14270da918464276b110c43868caa272c97baadb89eDoris Liu (int) (mWidth * mAspectRatio)); 14370da918464276b110c43868caa272c97baadb89eDoris Liu } 14470da918464276b110c43868caa272c97baadb89eDoris Liu 14570da918464276b110c43868caa272c97baadb89eDoris Liu float scaleX = scaledTextureWidth / mWidth; 14670da918464276b110c43868caa272c97baadb89eDoris Liu float scaleY = scaledTextureHeight / mHeight; 14770da918464276b110c43868caa272c97baadb89eDoris Liu 14870da918464276b110c43868caa272c97baadb89eDoris Liu boolean landscape = mWidth > mHeight; 14970da918464276b110c43868caa272c97baadb89eDoris Liu if (landscape) { 15070da918464276b110c43868caa272c97baadb89eDoris Liu matrix.setScale(scaleX, scaleY, 0f, (float) mHeight / 2); 15170da918464276b110c43868caa272c97baadb89eDoris Liu } else { 15270da918464276b110c43868caa272c97baadb89eDoris Liu matrix.setScale(scaleX, scaleY, (float) mWidth / 2, 0.0f); 15370da918464276b110c43868caa272c97baadb89eDoris Liu } 15470da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 15570da918464276b110c43868caa272c97baadb89eDoris Liu onPreviewSizeChanged(scaledTextureWidth, scaledTextureHeight); 15670da918464276b110c43868caa272c97baadb89eDoris Liu } 15770da918464276b110c43868caa272c97baadb89eDoris Liu 15870da918464276b110c43868caa272c97baadb89eDoris Liu private void onPreviewSizeChanged(float scaledTextureWidth, float scaledTextureHeight) { 15970da918464276b110c43868caa272c97baadb89eDoris Liu // Notify listeners of preview size change 16015b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu for (PreviewStatusListener.PreviewAreaSizeChangedListener listener 16115b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu : mPreviewSizeChangedListeners) { 162482de029dc20e0a577388a602985fb31c3200309Doris Liu listener.onPreviewAreaSizeChanged(scaledTextureWidth, scaledTextureHeight); 16370da918464276b110c43868caa272c97baadb89eDoris Liu } 16470da918464276b110c43868caa272c97baadb89eDoris Liu } 16570da918464276b110c43868caa272c97baadb89eDoris Liu 16670da918464276b110c43868caa272c97baadb89eDoris Liu /** 167482de029dc20e0a577388a602985fb31c3200309Doris Liu * Adds a listener that will get notified when the preview size changed. This 16870da918464276b110c43868caa272c97baadb89eDoris Liu * can be useful for UI elements or focus overlay to adjust themselves according 16970da918464276b110c43868caa272c97baadb89eDoris Liu * to the preview size change. 17070da918464276b110c43868caa272c97baadb89eDoris Liu * 17115b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * Note that a listener will only be added once. A newly added listener will receive 17215b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * a notification of current preview size immediately after being added. 17315b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * 17415b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * This function should be called on the UI thread and listeners will be notified 17515b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * on the UI thread. 17615b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * 17770da918464276b110c43868caa272c97baadb89eDoris Liu * @param listener the listener that will get notified of preview size change 17870da918464276b110c43868caa272c97baadb89eDoris Liu */ 179482de029dc20e0a577388a602985fb31c3200309Doris Liu public void addPreviewAreaSizeChangedListener( 180482de029dc20e0a577388a602985fb31c3200309Doris Liu PreviewStatusListener.PreviewAreaSizeChangedListener listener) { 181482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && !mPreviewSizeChangedListeners.contains(listener)) { 182482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.add(listener); 183482de029dc20e0a577388a602985fb31c3200309Doris Liu listener.onPreviewAreaSizeChanged(mWidth, mHeight); 184482de029dc20e0a577388a602985fb31c3200309Doris Liu } 185482de029dc20e0a577388a602985fb31c3200309Doris Liu } 186482de029dc20e0a577388a602985fb31c3200309Doris Liu 187482de029dc20e0a577388a602985fb31c3200309Doris Liu /** 188482de029dc20e0a577388a602985fb31c3200309Doris Liu * Removes a listener that gets notified when the preview size changed. 189482de029dc20e0a577388a602985fb31c3200309Doris Liu * 190482de029dc20e0a577388a602985fb31c3200309Doris Liu * @param listener the listener that gets notified of preview size change 191482de029dc20e0a577388a602985fb31c3200309Doris Liu */ 192482de029dc20e0a577388a602985fb31c3200309Doris Liu public void removePreviewAreaSizeChangedListener( 193482de029dc20e0a577388a602985fb31c3200309Doris Liu PreviewStatusListener.PreviewAreaSizeChangedListener listener) { 194482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && mPreviewSizeChangedListeners.contains(listener)) { 195482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.remove(listener); 196482de029dc20e0a577388a602985fb31c3200309Doris Liu } 19770da918464276b110c43868caa272c97baadb89eDoris Liu } 19870da918464276b110c43868caa272c97baadb89eDoris Liu 19970da918464276b110c43868caa272c97baadb89eDoris Liu @Override 20070da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 20170da918464276b110c43868caa272c97baadb89eDoris Liu // Workaround for b/11168275, see b/10981460 for more details 20270da918464276b110c43868caa272c97baadb89eDoris Liu if (mWidth != 0 && mHeight != 0) { 20370da918464276b110c43868caa272c97baadb89eDoris Liu // Re-apply transform matrix for new surface texture 20470da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 20570da918464276b110c43868caa272c97baadb89eDoris Liu } 20670da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 20770da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureAvailable(surface, width, height); 20870da918464276b110c43868caa272c97baadb89eDoris Liu } 20970da918464276b110c43868caa272c97baadb89eDoris Liu } 21070da918464276b110c43868caa272c97baadb89eDoris Liu 21170da918464276b110c43868caa272c97baadb89eDoris Liu @Override 21270da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 21370da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 21470da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height); 21570da918464276b110c43868caa272c97baadb89eDoris Liu } 21670da918464276b110c43868caa272c97baadb89eDoris Liu } 21770da918464276b110c43868caa272c97baadb89eDoris Liu 21870da918464276b110c43868caa272c97baadb89eDoris Liu @Override 21970da918464276b110c43868caa272c97baadb89eDoris Liu public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 22070da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 22170da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureDestroyed(surface); 22270da918464276b110c43868caa272c97baadb89eDoris Liu } 22370da918464276b110c43868caa272c97baadb89eDoris Liu return false; 22470da918464276b110c43868caa272c97baadb89eDoris Liu } 22570da918464276b110c43868caa272c97baadb89eDoris Liu 22670da918464276b110c43868caa272c97baadb89eDoris Liu @Override 22770da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureUpdated(SurfaceTexture surface) { 22870da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 22970da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureUpdated(surface); 23070da918464276b110c43868caa272c97baadb89eDoris Liu } 23170da918464276b110c43868caa272c97baadb89eDoris Liu 23270da918464276b110c43868caa272c97baadb89eDoris Liu } 23370da918464276b110c43868caa272c97baadb89eDoris Liu} 234