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 198c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport android.content.res.Configuration; 20274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphaelimport android.graphics.Bitmap; 2170da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.Matrix; 2270da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.RectF; 2370da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.SurfaceTexture; 2470da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.TextureView; 2570da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View; 2670da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View.OnLayoutChangeListener; 2770da918464276b110c43868caa272c97baadb89eDoris Liu 288c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.app.CameraProvider; 292bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 308c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.settings.Keys; 318c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.settings.ResolutionUtil; 328c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.settings.SettingsManager; 338c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.settings.SettingsUtil; 3470da918464276b110c43868caa272c97baadb89eDoris Liuimport com.android.camera.ui.PreviewStatusListener; 35344320c90639f823451ddac42e8f39b74727787cDoris Liuimport com.android.camera.util.CameraUtil; 368c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.ex.camera2.portability.CameraDeviceInfo; 378c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.ex.camera2.portability.Size; 3870da918464276b110c43868caa272c97baadb89eDoris Liu 39482de029dc20e0a577388a602985fb31c3200309Doris Liuimport java.util.ArrayList; 40fe60979d7d7ce78de503404da8e91e118242071aAngus Kongimport java.util.List; 41482de029dc20e0a577388a602985fb31c3200309Doris Liu 4270da918464276b110c43868caa272c97baadb89eDoris Liu/** 4370da918464276b110c43868caa272c97baadb89eDoris Liu * This class aims to automate TextureView transform change and notify listeners 4470da918464276b110c43868caa272c97baadb89eDoris Liu * (e.g. bottom bar) of the preview size change. 4570da918464276b110c43868caa272c97baadb89eDoris Liu */ 4670da918464276b110c43868caa272c97baadb89eDoris Liupublic class TextureViewHelper implements TextureView.SurfaceTextureListener, 4770da918464276b110c43868caa272c97baadb89eDoris Liu OnLayoutChangeListener { 4870da918464276b110c43868caa272c97baadb89eDoris Liu 492bca210e5fc8a77685775ffb403096167b017dceAngus Kong private static final Log.Tag TAG = new Log.Tag("TexViewHelper"); 5028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu public static final float MATCH_SCREEN = 0f; 51344320c90639f823451ddac42e8f39b74727787cDoris Liu private static final int UNSET = -1; 52ee36c5f591ac181a10692b2ec2b96de5251c4abbSascha Haeberling private final TextureView mPreview; 538c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher private final CameraProvider mCameraProvider; 5470da918464276b110c43868caa272c97baadb89eDoris Liu private int mWidth = 0; 5570da918464276b110c43868caa272c97baadb89eDoris Liu private int mHeight = 0; 56a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu private RectF mPreviewArea = new RectF(); 5728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private float mAspectRatio = MATCH_SCREEN; 5870da918464276b110c43868caa272c97baadb89eDoris Liu private boolean mAutoAdjustTransform = true; 5970da918464276b110c43868caa272c97baadb89eDoris Liu private TextureView.SurfaceTextureListener mSurfaceTextureListener; 6028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 6128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private final ArrayList<PreviewStatusListener.PreviewAspectRatioChangedListener> 6228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatioChangedListeners = 6328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu new ArrayList<PreviewStatusListener.PreviewAspectRatioChangedListener>(); 6470da918464276b110c43868caa272c97baadb89eDoris Liu 652bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong private final ArrayList<PreviewStatusListener.PreviewAreaChangedListener> 66482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners = 672bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong new ArrayList<PreviewStatusListener.PreviewAreaChangedListener>(); 6870da918464276b110c43868caa272c97baadb89eDoris Liu private OnLayoutChangeListener mOnLayoutChangeListener = null; 6928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private CaptureLayoutHelper mCaptureLayoutHelper = null; 70344320c90639f823451ddac42e8f39b74727787cDoris Liu private int mOrientation = UNSET; 7170da918464276b110c43868caa272c97baadb89eDoris Liu 728c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher public TextureViewHelper(TextureView preview, CaptureLayoutHelper helper, 738c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher CameraProvider cameraProvider) { 7470da918464276b110c43868caa272c97baadb89eDoris Liu mPreview = preview; 758c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher mCameraProvider = cameraProvider; 7670da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.addOnLayoutChangeListener(this); 7770da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setSurfaceTextureListener(this); 7828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper = helper; 7970da918464276b110c43868caa272c97baadb89eDoris Liu } 8070da918464276b110c43868caa272c97baadb89eDoris Liu 8170da918464276b110c43868caa272c97baadb89eDoris Liu /** 8270da918464276b110c43868caa272c97baadb89eDoris Liu * If auto adjust transform is enabled, when there is a layout change, the 8370da918464276b110c43868caa272c97baadb89eDoris Liu * transform matrix will be automatically adjusted based on the preview stream 8470da918464276b110c43868caa272c97baadb89eDoris Liu * aspect ratio in the new layout. 8570da918464276b110c43868caa272c97baadb89eDoris Liu * 8670da918464276b110c43868caa272c97baadb89eDoris Liu * @param enable whether or not auto adjustment should be enabled 8770da918464276b110c43868caa272c97baadb89eDoris Liu */ 8870da918464276b110c43868caa272c97baadb89eDoris Liu public void setAutoAdjustTransform(boolean enable) { 8970da918464276b110c43868caa272c97baadb89eDoris Liu mAutoAdjustTransform = enable; 9070da918464276b110c43868caa272c97baadb89eDoris Liu } 9170da918464276b110c43868caa272c97baadb89eDoris Liu 9270da918464276b110c43868caa272c97baadb89eDoris Liu @Override 9370da918464276b110c43868caa272c97baadb89eDoris Liu public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 9470da918464276b110c43868caa272c97baadb89eDoris Liu int oldTop, int oldRight, int oldBottom) { 957351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "onLayoutChange"); 9670da918464276b110c43868caa272c97baadb89eDoris Liu int width = right - left; 9770da918464276b110c43868caa272c97baadb89eDoris Liu int height = bottom - top; 98344320c90639f823451ddac42e8f39b74727787cDoris Liu int rotation = CameraUtil.getDisplayRotation(mPreview.getContext()); 99344320c90639f823451ddac42e8f39b74727787cDoris Liu if (mWidth != width || mHeight != height || mOrientation != rotation) { 10070da918464276b110c43868caa272c97baadb89eDoris Liu mWidth = width; 10170da918464276b110c43868caa272c97baadb89eDoris Liu mHeight = height; 102344320c90639f823451ddac42e8f39b74727787cDoris Liu mOrientation = rotation; 1038c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher if (!updateTransform()) { 104d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren clearTransform(); 10570da918464276b110c43868caa272c97baadb89eDoris Liu } 10670da918464276b110c43868caa272c97baadb89eDoris Liu } 10770da918464276b110c43868caa272c97baadb89eDoris Liu if (mOnLayoutChangeListener != null) { 10870da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, 10970da918464276b110c43868caa272c97baadb89eDoris Liu oldRight, oldBottom); 11070da918464276b110c43868caa272c97baadb89eDoris Liu } 11170da918464276b110c43868caa272c97baadb89eDoris Liu } 11270da918464276b110c43868caa272c97baadb89eDoris Liu 113d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren /** 114d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren * Transforms the preview with the identity matrix, ensuring there 115d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren * is no scaling on the preview. It also calls onPreviewSizeChanged, to 116d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren * trigger any necessary preview size changing callbacks. 117d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren */ 118d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren public void clearTransform() { 119d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren mPreview.setTransform(new Matrix()); 120d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren mPreviewArea.set(0, 0, mWidth, mHeight); 1212bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong onPreviewAreaChanged(mPreviewArea); 12228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(MATCH_SCREEN); 123d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren } 124d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren 12570da918464276b110c43868caa272c97baadb89eDoris Liu public void updateAspectRatio(float aspectRatio) { 1267351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "updateAspectRatio"); 12770da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio <= 0) { 12870da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid aspect ratio: " + aspectRatio); 12970da918464276b110c43868caa272c97baadb89eDoris Liu return; 13070da918464276b110c43868caa272c97baadb89eDoris Liu } 13170da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio < 1f) { 13270da918464276b110c43868caa272c97baadb89eDoris Liu aspectRatio = 1f / aspectRatio; 13370da918464276b110c43868caa272c97baadb89eDoris Liu } 13428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(aspectRatio); 13570da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 13670da918464276b110c43868caa272c97baadb89eDoris Liu } 13770da918464276b110c43868caa272c97baadb89eDoris Liu 13828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void setAspectRatio(float aspectRatio) { 1397351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "setAspectRatio: " + aspectRatio); 14028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mAspectRatio != aspectRatio) { 1417351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "aspect ratio changed from: " + mAspectRatio); 14228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatio = aspectRatio; 14328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu onAspectRatioChanged(); 14428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 14528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 14628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 14728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void onAspectRatioChanged() { 14828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper.onPreviewAspectRatioChanged(mAspectRatio); 14928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu for (PreviewStatusListener.PreviewAspectRatioChangedListener listener 15028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu : mAspectRatioChangedListeners) { 15128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu listener.onPreviewAspectRatioChanged(mAspectRatio); 15228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 15328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 15428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 15528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu public void addAspectRatioChangedListener( 15628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu PreviewStatusListener.PreviewAspectRatioChangedListener listener) { 15728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (listener != null && !mAspectRatioChangedListeners.contains(listener)) { 15828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatioChangedListeners.add(listener); 15928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 16028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 16128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 16202c129a598b6a165885fe950275675d62993d2eeSeth Raphael 16302c129a598b6a165885fe950275675d62993d2eeSeth Raphael /** 16402c129a598b6a165885fe950275675d62993d2eeSeth Raphael * This returns the rect that is available to display the preview, and 16502c129a598b6a165885fe950275675d62993d2eeSeth Raphael * capture buttons 16602c129a598b6a165885fe950275675d62993d2eeSeth Raphael * 16702c129a598b6a165885fe950275675d62993d2eeSeth Raphael * @return the rect. 16802c129a598b6a165885fe950275675d62993d2eeSeth Raphael */ 16902c129a598b6a165885fe950275675d62993d2eeSeth Raphael public RectF getFullscreenRect() { 17002c129a598b6a165885fe950275675d62993d2eeSeth Raphael return mCaptureLayoutHelper.getFullscreenRect(); 17102c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 17202c129a598b6a165885fe950275675d62993d2eeSeth Raphael 17302c129a598b6a165885fe950275675d62993d2eeSeth Raphael /** 17402c129a598b6a165885fe950275675d62993d2eeSeth Raphael * This takes a matrix to apply to the texture view and uses the screen 17502c129a598b6a165885fe950275675d62993d2eeSeth Raphael * aspect ratio as the target aspect ratio 176b4a2222950f627a39267636fba19649974cb8734Spike Sprague * 17702c129a598b6a165885fe950275675d62993d2eeSeth Raphael * @param matrix the matrix to apply 1786382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael * @param aspectRatio the aspectRatio that the preview should be 17902c129a598b6a165885fe950275675d62993d2eeSeth Raphael */ 1806382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael public void updateTransformFullScreen(Matrix matrix, float aspectRatio) { 18102c129a598b6a165885fe950275675d62993d2eeSeth Raphael aspectRatio = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio; 18202c129a598b6a165885fe950275675d62993d2eeSeth Raphael if (aspectRatio != mAspectRatio) { 18302c129a598b6a165885fe950275675d62993d2eeSeth Raphael setAspectRatio(aspectRatio); 18402c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 18502c129a598b6a165885fe950275675d62993d2eeSeth Raphael 18602c129a598b6a165885fe950275675d62993d2eeSeth Raphael mPreview.setTransform(matrix); 187274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael mPreviewArea = mCaptureLayoutHelper.getPreviewRect(); 188274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael onPreviewAreaChanged(mPreviewArea); 189274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 19002c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 19102c129a598b6a165885fe950275675d62993d2eeSeth Raphael 19270da918464276b110c43868caa272c97baadb89eDoris Liu public void updateTransform(Matrix matrix) { 19370da918464276b110c43868caa272c97baadb89eDoris Liu RectF previewRect = new RectF(0, 0, mWidth, mHeight); 19470da918464276b110c43868caa272c97baadb89eDoris Liu matrix.mapRect(previewRect); 19570da918464276b110c43868caa272c97baadb89eDoris Liu 19670da918464276b110c43868caa272c97baadb89eDoris Liu float previewWidth = previewRect.width(); 19770da918464276b110c43868caa272c97baadb89eDoris Liu float previewHeight = previewRect.height(); 19870da918464276b110c43868caa272c97baadb89eDoris Liu if (previewHeight == 0 || previewWidth == 0) { 19970da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); 20070da918464276b110c43868caa272c97baadb89eDoris Liu return; 20170da918464276b110c43868caa272c97baadb89eDoris Liu } 20228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu float aspectRatio = previewWidth / previewHeight; 20328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu aspectRatio = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio; 20428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (aspectRatio != mAspectRatio) { 20528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(aspectRatio); 20628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 20728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 20828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu RectF previewAreaBasedOnAspectRatio = mCaptureLayoutHelper.getPreviewRect(); 20928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu Matrix addtionalTransform = new Matrix(); 21028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu addtionalTransform.setRectToRect(previewRect, previewAreaBasedOnAspectRatio, 21128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu Matrix.ScaleToFit.CENTER); 21228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu matrix.postConcat(addtionalTransform); 21370da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 214a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu updatePreviewArea(matrix); 215a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } 21670da918464276b110c43868caa272c97baadb89eDoris Liu 217a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu /** 218a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu * Calculates and updates the preview area rect using the latest transform matrix. 219a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu */ 220a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu private void updatePreviewArea(Matrix matrix) { 221a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu mPreviewArea.set(0, 0, mWidth, mHeight); 222a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu matrix.mapRect(mPreviewArea); 2232bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong onPreviewAreaChanged(mPreviewArea); 22470da918464276b110c43868caa272c97baadb89eDoris Liu } 22570da918464276b110c43868caa272c97baadb89eDoris Liu 22670da918464276b110c43868caa272c97baadb89eDoris Liu public void setOnLayoutChangeListener(OnLayoutChangeListener listener) { 22770da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener = listener; 22870da918464276b110c43868caa272c97baadb89eDoris Liu } 22970da918464276b110c43868caa272c97baadb89eDoris Liu 23070da918464276b110c43868caa272c97baadb89eDoris Liu public void setSurfaceTextureListener(TextureView.SurfaceTextureListener listener) { 23170da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener = listener; 23270da918464276b110c43868caa272c97baadb89eDoris Liu } 23370da918464276b110c43868caa272c97baadb89eDoris Liu 23458b9b03f2bedc522bde5b4199121ea2e559c79a9Angus Kong /** 23570da918464276b110c43868caa272c97baadb89eDoris Liu * Updates the transform matrix based current width and height of TextureView 23670da918464276b110c43868caa272c97baadb89eDoris Liu * and preview stream aspect ratio. 2378c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * 2388c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * <p>If not {@code mAutoAdjustTransform}, this does nothing except return 2398c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * {@code false}. In all other cases, it returns {@code true}, regardless of 2408c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * whether the transform was changed.</p> 2418c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * 2428c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * @return Whether {@code mAutoAdjustTransform}. 24370da918464276b110c43868caa272c97baadb89eDoris Liu */ 2448c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher private boolean updateTransform() { 2457351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "updateTransform"); 2468c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher if (!mAutoAdjustTransform) { 2478c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return false; 2488c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher } 24928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mAspectRatio == MATCH_SCREEN || mAspectRatio < 0 || mWidth == 0 || mHeight == 0) { 2508c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return true; 2518c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher } 2528c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher 2538c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher Matrix matrix; 2548c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher int cameraId = mCameraProvider.getCurrentCameraId(); 2558c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher if (cameraId >= 0) { 2568c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher CameraDeviceInfo.Characteristics info = mCameraProvider.getCharacteristics(cameraId); 2578c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher matrix = info.getPreviewTransform(mOrientation, new RectF(0, 0, mWidth, mHeight), 2588c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher mCaptureLayoutHelper.getPreviewRect()); 2598c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher } else { 2608c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher Log.w(TAG, "Unable to find current camera... defaulting to identity matrix"); 2618c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher matrix = new Matrix(); 26270da918464276b110c43868caa272c97baadb89eDoris Liu } 26370da918464276b110c43868caa272c97baadb89eDoris Liu 26470da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 265a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu updatePreviewArea(matrix); 2668c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return true; 26770da918464276b110c43868caa272c97baadb89eDoris Liu } 26870da918464276b110c43868caa272c97baadb89eDoris Liu 2692bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong private void onPreviewAreaChanged(final RectF previewArea) { 2702bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong // Notify listeners of preview area change 2712bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong final List<PreviewStatusListener.PreviewAreaChangedListener> listeners = 2722bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong new ArrayList<PreviewStatusListener.PreviewAreaChangedListener>( 273fe60979d7d7ce78de503404da8e91e118242071aAngus Kong mPreviewSizeChangedListeners); 274fe60979d7d7ce78de503404da8e91e118242071aAngus Kong // This method can be called during layout pass. We post a Runnable so 275fe60979d7d7ce78de503404da8e91e118242071aAngus Kong // that the callbacks won't happen during the layout pass. 276fe60979d7d7ce78de503404da8e91e118242071aAngus Kong mPreview.post(new Runnable() { 277fe60979d7d7ce78de503404da8e91e118242071aAngus Kong @Override 278fe60979d7d7ce78de503404da8e91e118242071aAngus Kong public void run() { 2792bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong for (PreviewStatusListener.PreviewAreaChangedListener listener : listeners) { 2802bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(previewArea); 281fe60979d7d7ce78de503404da8e91e118242071aAngus Kong } 282fe60979d7d7ce78de503404da8e91e118242071aAngus Kong } 283fe60979d7d7ce78de503404da8e91e118242071aAngus Kong }); 28470da918464276b110c43868caa272c97baadb89eDoris Liu } 28570da918464276b110c43868caa272c97baadb89eDoris Liu 28670da918464276b110c43868caa272c97baadb89eDoris Liu /** 287213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * Returns a new copy of the preview area, to avoid internal data being modified 288213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu * from outside of the class. 289213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 290213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public RectF getPreviewArea() { 291213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu return new RectF(mPreviewArea); 292213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 293213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 294213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 295274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael * Returns a copy of the area of the whole preview, including bits clipped 296274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael * by the view 297274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael */ 298274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael public RectF getTextureArea() { 299274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 300274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael if (mPreview == null) { 301274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael return new RectF(); 302274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 303274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael Matrix matrix = new Matrix(); 304274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael RectF area = new RectF(0, 0, mWidth, mHeight); 305274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael mPreview.getTransform(matrix).mapRect(area); 306274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael return area; 307274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 308274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 309274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael public Bitmap getPreviewBitmap(int downsample) { 310274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael RectF textureArea = getTextureArea(); 3118c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher int width = (int) textureArea.width() / downsample; 3128c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher int height = (int) textureArea.height() / downsample; 3138c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher Bitmap preview = mPreview.getBitmap(width, height); 3148c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return Bitmap.createBitmap(preview, 0, 0, width, height, mPreview.getTransform(null), true); 315274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 316274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 317274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael /** 3182bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * Adds a listener that will get notified when the preview area changed. This 31970da918464276b110c43868caa272c97baadb89eDoris Liu * can be useful for UI elements or focus overlay to adjust themselves according 3202bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * to the preview area change. 32128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu * <p/> 32215b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * Note that a listener will only be added once. A newly added listener will receive 3232bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * a notification of current preview area immediately after being added. 32428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu * <p/> 32515b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * This function should be called on the UI thread and listeners will be notified 32615b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * on the UI thread. 32715b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * 3282bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * @param listener the listener that will get notified of preview area change 32970da918464276b110c43868caa272c97baadb89eDoris Liu */ 330482de029dc20e0a577388a602985fb31c3200309Doris Liu public void addPreviewAreaSizeChangedListener( 3312bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong PreviewStatusListener.PreviewAreaChangedListener listener) { 332482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && !mPreviewSizeChangedListeners.contains(listener)) { 333482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.add(listener); 334a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu if (mPreviewArea.width() == 0 || mPreviewArea.height() == 0) { 3352bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(new RectF(0, 0, mWidth, mHeight)); 336a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } else { 3372bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(new RectF(mPreviewArea)); 338a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } 339482de029dc20e0a577388a602985fb31c3200309Doris Liu } 340482de029dc20e0a577388a602985fb31c3200309Doris Liu } 341482de029dc20e0a577388a602985fb31c3200309Doris Liu 342482de029dc20e0a577388a602985fb31c3200309Doris Liu /** 3432bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * Removes a listener that gets notified when the preview area changed. 344482de029dc20e0a577388a602985fb31c3200309Doris Liu * 3452bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * @param listener the listener that gets notified of preview area change 346482de029dc20e0a577388a602985fb31c3200309Doris Liu */ 347482de029dc20e0a577388a602985fb31c3200309Doris Liu public void removePreviewAreaSizeChangedListener( 3482bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong PreviewStatusListener.PreviewAreaChangedListener listener) { 349482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && mPreviewSizeChangedListeners.contains(listener)) { 350482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.remove(listener); 351482de029dc20e0a577388a602985fb31c3200309Doris Liu } 35270da918464276b110c43868caa272c97baadb89eDoris Liu } 35370da918464276b110c43868caa272c97baadb89eDoris Liu 35470da918464276b110c43868caa272c97baadb89eDoris Liu @Override 35570da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 35670da918464276b110c43868caa272c97baadb89eDoris Liu // Workaround for b/11168275, see b/10981460 for more details 35770da918464276b110c43868caa272c97baadb89eDoris Liu if (mWidth != 0 && mHeight != 0) { 35870da918464276b110c43868caa272c97baadb89eDoris Liu // Re-apply transform matrix for new surface texture 35970da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 36070da918464276b110c43868caa272c97baadb89eDoris Liu } 36170da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 36270da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureAvailable(surface, width, height); 36370da918464276b110c43868caa272c97baadb89eDoris Liu } 36470da918464276b110c43868caa272c97baadb89eDoris Liu } 36570da918464276b110c43868caa272c97baadb89eDoris Liu 36670da918464276b110c43868caa272c97baadb89eDoris Liu @Override 36770da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 36870da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 36970da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height); 37070da918464276b110c43868caa272c97baadb89eDoris Liu } 37170da918464276b110c43868caa272c97baadb89eDoris Liu } 37270da918464276b110c43868caa272c97baadb89eDoris Liu 37370da918464276b110c43868caa272c97baadb89eDoris Liu @Override 37470da918464276b110c43868caa272c97baadb89eDoris Liu public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 37570da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 37670da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureDestroyed(surface); 37770da918464276b110c43868caa272c97baadb89eDoris Liu } 37870da918464276b110c43868caa272c97baadb89eDoris Liu return false; 37970da918464276b110c43868caa272c97baadb89eDoris Liu } 38070da918464276b110c43868caa272c97baadb89eDoris Liu 38170da918464276b110c43868caa272c97baadb89eDoris Liu @Override 38270da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureUpdated(SurfaceTexture surface) { 38370da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 38470da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureUpdated(surface); 38570da918464276b110c43868caa272c97baadb89eDoris Liu } 38670da918464276b110c43868caa272c97baadb89eDoris Liu 38770da918464276b110c43868caa272c97baadb89eDoris Liu } 38870da918464276b110c43868caa272c97baadb89eDoris Liu} 389