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 19274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphaelimport android.graphics.Bitmap; 2070da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.Matrix; 2170da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.RectF; 2270da918464276b110c43868caa272c97baadb89eDoris Liuimport android.graphics.SurfaceTexture; 2370da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.TextureView; 2470da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View; 2570da918464276b110c43868caa272c97baadb89eDoris Liuimport android.view.View.OnLayoutChangeListener; 2670da918464276b110c43868caa272c97baadb89eDoris Liu 27f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Linimport com.android.camera.app.AppController; 288c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.camera.app.CameraProvider; 291d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Linimport com.android.camera.app.OrientationManager; 302bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 311d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport com.android.camera.device.CameraId; 3270da918464276b110c43868caa272c97baadb89eDoris Liuimport com.android.camera.ui.PreviewStatusListener; 33e2529657eeb168588b9a47f5dc3bc87eb54f503dSascha Haeberlingimport com.android.camera.util.ApiHelper; 34344320c90639f823451ddac42e8f39b74727787cDoris Liuimport com.android.camera.util.CameraUtil; 35f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Linimport com.android.camera2.R; 368c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucherimport com.android.ex.camera2.portability.CameraDeviceInfo; 3770da918464276b110c43868caa272c97baadb89eDoris Liu 38482de029dc20e0a577388a602985fb31c3200309Doris Liuimport java.util.ArrayList; 39fe60979d7d7ce78de503404da8e91e118242071aAngus Kongimport java.util.List; 40482de029dc20e0a577388a602985fb31c3200309Doris Liu 4170da918464276b110c43868caa272c97baadb89eDoris Liu/** 4270da918464276b110c43868caa272c97baadb89eDoris Liu * This class aims to automate TextureView transform change and notify listeners 4370da918464276b110c43868caa272c97baadb89eDoris Liu * (e.g. bottom bar) of the preview size change. 4470da918464276b110c43868caa272c97baadb89eDoris Liu */ 4570da918464276b110c43868caa272c97baadb89eDoris Liupublic class TextureViewHelper implements TextureView.SurfaceTextureListener, 4670da918464276b110c43868caa272c97baadb89eDoris Liu OnLayoutChangeListener { 4770da918464276b110c43868caa272c97baadb89eDoris Liu 482bca210e5fc8a77685775ffb403096167b017dceAngus Kong private static final Log.Tag TAG = new Log.Tag("TexViewHelper"); 4928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu public static final float MATCH_SCREEN = 0f; 50344320c90639f823451ddac42e8f39b74727787cDoris Liu private static final int UNSET = -1; 51ee36c5f591ac181a10692b2ec2b96de5251c4abbSascha Haeberling private final TextureView mPreview; 528c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher private final CameraProvider mCameraProvider; 5370da918464276b110c43868caa272c97baadb89eDoris Liu private int mWidth = 0; 5470da918464276b110c43868caa272c97baadb89eDoris Liu private int mHeight = 0; 55a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu private RectF mPreviewArea = new RectF(); 5628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private float mAspectRatio = MATCH_SCREEN; 5770da918464276b110c43868caa272c97baadb89eDoris Liu private boolean mAutoAdjustTransform = true; 5870da918464276b110c43868caa272c97baadb89eDoris Liu private TextureView.SurfaceTextureListener mSurfaceTextureListener; 5928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 6028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private final ArrayList<PreviewStatusListener.PreviewAspectRatioChangedListener> 6128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatioChangedListeners = 6228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu new ArrayList<PreviewStatusListener.PreviewAspectRatioChangedListener>(); 6370da918464276b110c43868caa272c97baadb89eDoris Liu 642bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong private final ArrayList<PreviewStatusListener.PreviewAreaChangedListener> 65482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners = 662bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong new ArrayList<PreviewStatusListener.PreviewAreaChangedListener>(); 6770da918464276b110c43868caa272c97baadb89eDoris Liu private OnLayoutChangeListener mOnLayoutChangeListener = null; 6828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private CaptureLayoutHelper mCaptureLayoutHelper = null; 69344320c90639f823451ddac42e8f39b74727787cDoris Liu private int mOrientation = UNSET; 7070da918464276b110c43868caa272c97baadb89eDoris Liu 71f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin // Hack to allow to know which module is running for b/20694189 72f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin private final AppController mAppController; 73436aba83744b104d000ae34fead732c5271d3144I-Jong Lin private final int mCameraModeId; 74436aba83744b104d000ae34fead732c5271d3144I-Jong Lin private final int mCaptureIntentModeId; 75f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin 768c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher public TextureViewHelper(TextureView preview, CaptureLayoutHelper helper, 77f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin CameraProvider cameraProvider, AppController appController) { 7870da918464276b110c43868caa272c97baadb89eDoris Liu mPreview = preview; 798c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher mCameraProvider = cameraProvider; 8070da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.addOnLayoutChangeListener(this); 8170da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setSurfaceTextureListener(this); 8228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper = helper; 83f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin mAppController = appController; 84436aba83744b104d000ae34fead732c5271d3144I-Jong Lin mCameraModeId = appController.getAndroidContext().getResources() 85f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin .getInteger(R.integer.camera_mode_photo); 86436aba83744b104d000ae34fead732c5271d3144I-Jong Lin mCaptureIntentModeId = appController.getAndroidContext().getResources() 87436aba83744b104d000ae34fead732c5271d3144I-Jong Lin .getInteger(R.integer.camera_mode_capture_intent); 8870da918464276b110c43868caa272c97baadb89eDoris Liu } 8970da918464276b110c43868caa272c97baadb89eDoris Liu 9070da918464276b110c43868caa272c97baadb89eDoris Liu /** 9170da918464276b110c43868caa272c97baadb89eDoris Liu * If auto adjust transform is enabled, when there is a layout change, the 921d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * transform matrix will be automatically adjusted based on the preview 931d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * stream aspect ratio in the new layout. 9470da918464276b110c43868caa272c97baadb89eDoris Liu * 9570da918464276b110c43868caa272c97baadb89eDoris Liu * @param enable whether or not auto adjustment should be enabled 9670da918464276b110c43868caa272c97baadb89eDoris Liu */ 9770da918464276b110c43868caa272c97baadb89eDoris Liu public void setAutoAdjustTransform(boolean enable) { 9870da918464276b110c43868caa272c97baadb89eDoris Liu mAutoAdjustTransform = enable; 9970da918464276b110c43868caa272c97baadb89eDoris Liu } 10070da918464276b110c43868caa272c97baadb89eDoris Liu 10170da918464276b110c43868caa272c97baadb89eDoris Liu @Override 10270da918464276b110c43868caa272c97baadb89eDoris Liu public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 1031d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin int oldTop, int oldRight, int oldBottom) { 1047351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "onLayoutChange"); 10570da918464276b110c43868caa272c97baadb89eDoris Liu int width = right - left; 10670da918464276b110c43868caa272c97baadb89eDoris Liu int height = bottom - top; 1078be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde int rotation = CameraUtil.getDisplayRotation(); 108344320c90639f823451ddac42e8f39b74727787cDoris Liu if (mWidth != width || mHeight != height || mOrientation != rotation) { 10970da918464276b110c43868caa272c97baadb89eDoris Liu mWidth = width; 11070da918464276b110c43868caa272c97baadb89eDoris Liu mHeight = height; 111344320c90639f823451ddac42e8f39b74727787cDoris Liu mOrientation = rotation; 1128c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher if (!updateTransform()) { 113d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren clearTransform(); 11470da918464276b110c43868caa272c97baadb89eDoris Liu } 11570da918464276b110c43868caa272c97baadb89eDoris Liu } 11670da918464276b110c43868caa272c97baadb89eDoris Liu if (mOnLayoutChangeListener != null) { 11770da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, 11870da918464276b110c43868caa272c97baadb89eDoris Liu oldRight, oldBottom); 11970da918464276b110c43868caa272c97baadb89eDoris Liu } 12070da918464276b110c43868caa272c97baadb89eDoris Liu } 12170da918464276b110c43868caa272c97baadb89eDoris Liu 122d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren /** 1231d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Transforms the preview with the identity matrix, ensuring there is no 1241d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * scaling on the preview. It also calls onPreviewSizeChanged, to trigger 1251d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * any necessary preview size changing callbacks. 126d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren */ 127d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren public void clearTransform() { 128d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren mPreview.setTransform(new Matrix()); 129d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren mPreviewArea.set(0, 0, mWidth, mHeight); 1302bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong onPreviewAreaChanged(mPreviewArea); 13128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(MATCH_SCREEN); 132d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren } 133d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren 13470da918464276b110c43868caa272c97baadb89eDoris Liu public void updateAspectRatio(float aspectRatio) { 1351d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin Log.v(TAG, "updateAspectRatio " + aspectRatio); 13670da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio <= 0) { 13770da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid aspect ratio: " + aspectRatio); 13870da918464276b110c43868caa272c97baadb89eDoris Liu return; 13970da918464276b110c43868caa272c97baadb89eDoris Liu } 14070da918464276b110c43868caa272c97baadb89eDoris Liu if (aspectRatio < 1f) { 14170da918464276b110c43868caa272c97baadb89eDoris Liu aspectRatio = 1f / aspectRatio; 14270da918464276b110c43868caa272c97baadb89eDoris Liu } 14328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(aspectRatio); 14470da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 14570da918464276b110c43868caa272c97baadb89eDoris Liu } 14670da918464276b110c43868caa272c97baadb89eDoris Liu 14728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void setAspectRatio(float aspectRatio) { 1487351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "setAspectRatio: " + aspectRatio); 14928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mAspectRatio != aspectRatio) { 1507351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "aspect ratio changed from: " + mAspectRatio); 15128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatio = aspectRatio; 15228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu onAspectRatioChanged(); 15328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 15428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 15528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 15628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu private void onAspectRatioChanged() { 15728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mCaptureLayoutHelper.onPreviewAspectRatioChanged(mAspectRatio); 15828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu for (PreviewStatusListener.PreviewAspectRatioChangedListener listener 15928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu : mAspectRatioChangedListeners) { 16028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu listener.onPreviewAspectRatioChanged(mAspectRatio); 16128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 16228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 16328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 16428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu public void addAspectRatioChangedListener( 16528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu PreviewStatusListener.PreviewAspectRatioChangedListener listener) { 16628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (listener != null && !mAspectRatioChangedListeners.contains(listener)) { 16728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu mAspectRatioChangedListeners.add(listener); 16828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 16928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 17028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 17102c129a598b6a165885fe950275675d62993d2eeSeth Raphael /** 17202c129a598b6a165885fe950275675d62993d2eeSeth Raphael * This returns the rect that is available to display the preview, and 17302c129a598b6a165885fe950275675d62993d2eeSeth Raphael * capture buttons 17402c129a598b6a165885fe950275675d62993d2eeSeth Raphael * 17502c129a598b6a165885fe950275675d62993d2eeSeth Raphael * @return the rect. 17602c129a598b6a165885fe950275675d62993d2eeSeth Raphael */ 17702c129a598b6a165885fe950275675d62993d2eeSeth Raphael public RectF getFullscreenRect() { 17802c129a598b6a165885fe950275675d62993d2eeSeth Raphael return mCaptureLayoutHelper.getFullscreenRect(); 17902c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 18002c129a598b6a165885fe950275675d62993d2eeSeth Raphael 18102c129a598b6a165885fe950275675d62993d2eeSeth Raphael /** 18202c129a598b6a165885fe950275675d62993d2eeSeth Raphael * This takes a matrix to apply to the texture view and uses the screen 18302c129a598b6a165885fe950275675d62993d2eeSeth Raphael * aspect ratio as the target aspect ratio 184b4a2222950f627a39267636fba19649974cb8734Spike Sprague * 18502c129a598b6a165885fe950275675d62993d2eeSeth Raphael * @param matrix the matrix to apply 1866382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael * @param aspectRatio the aspectRatio that the preview should be 18702c129a598b6a165885fe950275675d62993d2eeSeth Raphael */ 1886382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael public void updateTransformFullScreen(Matrix matrix, float aspectRatio) { 18902c129a598b6a165885fe950275675d62993d2eeSeth Raphael aspectRatio = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio; 19002c129a598b6a165885fe950275675d62993d2eeSeth Raphael if (aspectRatio != mAspectRatio) { 19102c129a598b6a165885fe950275675d62993d2eeSeth Raphael setAspectRatio(aspectRatio); 19202c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 19302c129a598b6a165885fe950275675d62993d2eeSeth Raphael 19402c129a598b6a165885fe950275675d62993d2eeSeth Raphael mPreview.setTransform(matrix); 195274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael mPreviewArea = mCaptureLayoutHelper.getPreviewRect(); 196274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael onPreviewAreaChanged(mPreviewArea); 197274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 19802c129a598b6a165885fe950275675d62993d2eeSeth Raphael } 19902c129a598b6a165885fe950275675d62993d2eeSeth Raphael 20070da918464276b110c43868caa272c97baadb89eDoris Liu public void updateTransform(Matrix matrix) { 20170da918464276b110c43868caa272c97baadb89eDoris Liu RectF previewRect = new RectF(0, 0, mWidth, mHeight); 20270da918464276b110c43868caa272c97baadb89eDoris Liu matrix.mapRect(previewRect); 20370da918464276b110c43868caa272c97baadb89eDoris Liu 20470da918464276b110c43868caa272c97baadb89eDoris Liu float previewWidth = previewRect.width(); 20570da918464276b110c43868caa272c97baadb89eDoris Liu float previewHeight = previewRect.height(); 20670da918464276b110c43868caa272c97baadb89eDoris Liu if (previewHeight == 0 || previewWidth == 0) { 20770da918464276b110c43868caa272c97baadb89eDoris Liu Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); 20870da918464276b110c43868caa272c97baadb89eDoris Liu return; 20970da918464276b110c43868caa272c97baadb89eDoris Liu } 21028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu float aspectRatio = previewWidth / previewHeight; 21128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu aspectRatio = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio; 21228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (aspectRatio != mAspectRatio) { 21328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu setAspectRatio(aspectRatio); 21428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu } 21528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu 21628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu RectF previewAreaBasedOnAspectRatio = mCaptureLayoutHelper.getPreviewRect(); 21728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu Matrix addtionalTransform = new Matrix(); 21828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu addtionalTransform.setRectToRect(previewRect, previewAreaBasedOnAspectRatio, 21928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu Matrix.ScaleToFit.CENTER); 22028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu matrix.postConcat(addtionalTransform); 22170da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 222a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu updatePreviewArea(matrix); 223a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } 22470da918464276b110c43868caa272c97baadb89eDoris Liu 225a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu /** 2261d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Calculates and updates the preview area rect using the latest transform 2271d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * matrix. 228a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu */ 229a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu private void updatePreviewArea(Matrix matrix) { 230a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu mPreviewArea.set(0, 0, mWidth, mHeight); 231a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu matrix.mapRect(mPreviewArea); 2322bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong onPreviewAreaChanged(mPreviewArea); 23370da918464276b110c43868caa272c97baadb89eDoris Liu } 23470da918464276b110c43868caa272c97baadb89eDoris Liu 23570da918464276b110c43868caa272c97baadb89eDoris Liu public void setOnLayoutChangeListener(OnLayoutChangeListener listener) { 23670da918464276b110c43868caa272c97baadb89eDoris Liu mOnLayoutChangeListener = listener; 23770da918464276b110c43868caa272c97baadb89eDoris Liu } 23870da918464276b110c43868caa272c97baadb89eDoris Liu 23970da918464276b110c43868caa272c97baadb89eDoris Liu public void setSurfaceTextureListener(TextureView.SurfaceTextureListener listener) { 24070da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener = listener; 24170da918464276b110c43868caa272c97baadb89eDoris Liu } 24270da918464276b110c43868caa272c97baadb89eDoris Liu 24358b9b03f2bedc522bde5b4199121ea2e559c79a9Angus Kong /** 2441d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Returns a transformation matrix that implements rotation that is 2451d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * consistent with CaptureLayoutHelper and TextureViewHelper. The magical 2461d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * invariant for CaptureLayoutHelper and TextureViewHelper that must be 2471d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * obeyed is that the bounding box of the view must be EXACTLY the bounding 2481d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * box of the surfaceDimensions AFTER the transformation has been applied. 2498c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * 2501d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * @param currentDisplayOrientation The current display orientation, 2511d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * measured counterclockwise from to the device's natural 2521d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * orientation (in degrees, always a multiple of 90, and between 2531d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * 0 and 270, inclusive). 2541d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * @param surfaceDimensions The dimensions of the 2551d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * {@link android.view.Surface} on which the preview image is 2561d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * being rendered. It usually only makes sense for the upper-left 2571d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * corner to be at the origin. 2581d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * @param desiredBounds The boundaries within the 2591d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * {@link android.view.Surface} where the final image should 2601d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * appear. These can be used to translate and scale the output, 2611d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * but note that the image will be stretched to fit, possibly 2621d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * changing its aspect ratio. 2631d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * @return The transform matrix that should be applied to the 2641d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * {@link android.view.Surface} in order for the image to display 2651d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * properly in the device's current orientation. 2661d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin */ 2671d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin public Matrix getPreviewRotationalTransform(int currentDisplayOrientation, 2681d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin RectF surfaceDimensions, 2691d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin RectF desiredBounds) { 2701d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin if (surfaceDimensions.equals(desiredBounds)) { 2711d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin return new Matrix(); 2721d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin } 2731d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 2741d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin Matrix transform = new Matrix(); 2751d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.setRectToRect(surfaceDimensions, desiredBounds, Matrix.ScaleToFit.FILL); 2761d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 2771d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin RectF normalRect = surfaceDimensions; 2781d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin // Bounding box of 90 or 270 degree rotation. 2791d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin RectF rotatedRect = new RectF(normalRect.width() / 2 - normalRect.height() / 2, 2801d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin normalRect.height() / 2 - normalRect.width() / 2, 2811d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin normalRect.width() / 2 + normalRect.height() / 2, 2821d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin normalRect.height() / 2 + normalRect.width() / 2); 2831d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 2841d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin OrientationManager.DeviceOrientation deviceOrientation = 2851d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin OrientationManager.DeviceOrientation.from(currentDisplayOrientation); 2861d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 28755e498578b46ef9e7b3aa70f30a68ea9bd788d63I-Jong Lin // This rotation code assumes that the aspect ratio of the content 28855e498578b46ef9e7b3aa70f30a68ea9bd788d63I-Jong Lin // (not of necessarily the surface) equals the aspect ratio of view that is receiving 28955e498578b46ef9e7b3aa70f30a68ea9bd788d63I-Jong Lin // the preview. So, a 4:3 surface that contains 16:9 data will look correct as 29055e498578b46ef9e7b3aa70f30a68ea9bd788d63I-Jong Lin // long as the view is also 16:9. 2911d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin switch (deviceOrientation) { 2921d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin case CLOCKWISE_90: 2931d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.setRectToRect(rotatedRect, desiredBounds, Matrix.ScaleToFit.FILL); 2941d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.preRotate(270, mWidth / 2, mHeight / 2); 2951d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin break; 2961d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin case CLOCKWISE_180: 2971d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.setRectToRect(normalRect, desiredBounds, Matrix.ScaleToFit.FILL); 2981d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.preRotate(180, mWidth / 2, mHeight / 2); 2991d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin break; 3001d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin case CLOCKWISE_270: 3011d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.setRectToRect(rotatedRect, desiredBounds, Matrix.ScaleToFit.FILL); 3021d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.preRotate(90, mWidth / 2, mHeight / 2); 3031d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin break; 3041d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin case CLOCKWISE_0: 3051d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin default: 3061d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin transform.setRectToRect(normalRect, desiredBounds, Matrix.ScaleToFit.FILL); 3071d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin break; 3081d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin } 3091d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 3101d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin return transform; 3111d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin } 3121d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 3131d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin /** 3141d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Updates the transform matrix based current width and height of 3151d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * TextureView and preview stream aspect ratio. 3161d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * <p> 3171d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * If not {@code mAutoAdjustTransform}, this does nothing except return 3188c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * {@code false}. In all other cases, it returns {@code true}, regardless of 3191d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * whether the transform was changed. 3201d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * </p> 3211d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * In {@code mAutoAdjustTransform} and the CameraProvder is invalid, it is assumed 3221d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * that the CaptureModule/PhotoModule is Camera2 API-based and must implements its 3231d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * rotation via matrix transformation implemented in getPreviewRotationalTransform. 3248c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * 3258c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher * @return Whether {@code mAutoAdjustTransform}. 32670da918464276b110c43868caa272c97baadb89eDoris Liu */ 3278c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher private boolean updateTransform() { 3287351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger Log.v(TAG, "updateTransform"); 3298c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher if (!mAutoAdjustTransform) { 3308c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return false; 3318c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher } 3321d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin 33328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu if (mAspectRatio == MATCH_SCREEN || mAspectRatio < 0 || mWidth == 0 || mHeight == 0) { 3348c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return true; 3358c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher } 3368c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher 337f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin Matrix matrix = new Matrix(); 3381d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde CameraId cameraKey = mCameraProvider.getCurrentCameraId(); 3391d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde int cameraId = -1; 3401d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde 3411d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde try { 3421d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde cameraId = cameraKey.getLegacyValue(); 3431d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde } catch (UnsupportedOperationException ignored) { 3441d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde Log.e(TAG, "TransformViewHelper does not support Camera API2"); 3451d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde } 3461d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde 347f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin 348f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin // Only apply this fix when Current Active Module is Photo module AND 349f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin // Phone is Nexus4 The enhancement fix b/20694189 to original fix to 350f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin // b/19271661 ensures that the fix should only be applied when: 351f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin // 1) the phone is a Nexus4 which requires the specific workaround 352436aba83744b104d000ae34fead732c5271d3144I-Jong Lin // 2) CaptureModule is enabled. 353436aba83744b104d000ae34fead732c5271d3144I-Jong Lin // 3) the Camera Photo Mode Or Capture Intent Photo Mode is active 354436aba83744b104d000ae34fead732c5271d3144I-Jong Lin if (ApiHelper.IS_NEXUS_4 && mAppController.getCameraFeatureConfig().isUsingCaptureModule() 355436aba83744b104d000ae34fead732c5271d3144I-Jong Lin && (mAppController.getCurrentModuleIndex() == mCameraModeId || 356436aba83744b104d000ae34fead732c5271d3144I-Jong Lin mAppController.getCurrentModuleIndex() == mCaptureIntentModeId)) { 357436aba83744b104d000ae34fead732c5271d3144I-Jong Lin Log.v(TAG, "Applying Photo Mode, Capture Module, Nexus-4 specific fix for b/19271661"); 3581d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin mOrientation = CameraUtil.getDisplayRotation(); 359f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin matrix = getPreviewRotationalTransform(mOrientation, 360f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin new RectF(0, 0, mWidth, mHeight), 361f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin mCaptureLayoutHelper.getPreviewRect()); 362436aba83744b104d000ae34fead732c5271d3144I-Jong Lin } else if (cameraId >= 0) { 363436aba83744b104d000ae34fead732c5271d3144I-Jong Lin // Otherwise, do the default, legacy action. 364f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin CameraDeviceInfo.Characteristics info = mCameraProvider.getCharacteristics(cameraId); 365f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin matrix = info.getPreviewTransform(mOrientation, new RectF(0, 0, mWidth, mHeight), 3661d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin mCaptureLayoutHelper.getPreviewRect()); 367436aba83744b104d000ae34fead732c5271d3144I-Jong Lin } else { 368436aba83744b104d000ae34fead732c5271d3144I-Jong Lin // Do Nothing 36970da918464276b110c43868caa272c97baadb89eDoris Liu } 37070da918464276b110c43868caa272c97baadb89eDoris Liu 37170da918464276b110c43868caa272c97baadb89eDoris Liu mPreview.setTransform(matrix); 372a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu updatePreviewArea(matrix); 3738c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return true; 37470da918464276b110c43868caa272c97baadb89eDoris Liu } 37570da918464276b110c43868caa272c97baadb89eDoris Liu 3762bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong private void onPreviewAreaChanged(final RectF previewArea) { 3772bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong // Notify listeners of preview area change 3782bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong final List<PreviewStatusListener.PreviewAreaChangedListener> listeners = 3792bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong new ArrayList<PreviewStatusListener.PreviewAreaChangedListener>( 380fe60979d7d7ce78de503404da8e91e118242071aAngus Kong mPreviewSizeChangedListeners); 381fe60979d7d7ce78de503404da8e91e118242071aAngus Kong // This method can be called during layout pass. We post a Runnable so 382fe60979d7d7ce78de503404da8e91e118242071aAngus Kong // that the callbacks won't happen during the layout pass. 383fe60979d7d7ce78de503404da8e91e118242071aAngus Kong mPreview.post(new Runnable() { 384fe60979d7d7ce78de503404da8e91e118242071aAngus Kong @Override 385fe60979d7d7ce78de503404da8e91e118242071aAngus Kong public void run() { 3862bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong for (PreviewStatusListener.PreviewAreaChangedListener listener : listeners) { 3872bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(previewArea); 388fe60979d7d7ce78de503404da8e91e118242071aAngus Kong } 389fe60979d7d7ce78de503404da8e91e118242071aAngus Kong } 390fe60979d7d7ce78de503404da8e91e118242071aAngus Kong }); 39170da918464276b110c43868caa272c97baadb89eDoris Liu } 39270da918464276b110c43868caa272c97baadb89eDoris Liu 39370da918464276b110c43868caa272c97baadb89eDoris Liu /** 3941d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Returns a new copy of the preview area, to avoid internal data being 3951d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * modified from outside of the class. 396213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu */ 397213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu public RectF getPreviewArea() { 398213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu return new RectF(mPreviewArea); 399213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu } 400213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu 401213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu /** 402274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael * Returns a copy of the area of the whole preview, including bits clipped 403274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael * by the view 404274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael */ 405274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael public RectF getTextureArea() { 406274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 407274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael if (mPreview == null) { 408274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael return new RectF(); 409274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 410274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael Matrix matrix = new Matrix(); 411274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael RectF area = new RectF(0, 0, mWidth, mHeight); 412274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael mPreview.getTransform(matrix).mapRect(area); 413274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael return area; 414274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 415274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 416274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael public Bitmap getPreviewBitmap(int downsample) { 417274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael RectF textureArea = getTextureArea(); 4188c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher int width = (int) textureArea.width() / downsample; 4198c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher int height = (int) textureArea.height() / downsample; 4208c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher Bitmap preview = mPreview.getBitmap(width, height); 4218c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher return Bitmap.createBitmap(preview, 0, 0, width, height, mPreview.getTransform(null), true); 422274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael } 423274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael 424274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael /** 4251d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Adds a listener that will get notified when the preview area changed. 4261d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * This can be useful for UI elements or focus overlay to adjust themselves 4271d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * according to the preview area change. 42828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu * <p/> 4291d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * Note that a listener will only be added once. A newly added listener will 4301d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * receive a notification of current preview area immediately after being 4311d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * added. 43228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu * <p/> 4331d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * This function should be called on the UI thread and listeners will be 4341d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * notified on the UI thread. 43515b9961c5ca49fc6ac9d036e7a967797987e46eeDoris Liu * 4361d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * @param listener the listener that will get notified of preview area 4371d0dd50db5d3d02d1209b4c0a3e6d4a71d2c8acfI-Jong Lin * change 43870da918464276b110c43868caa272c97baadb89eDoris Liu */ 439482de029dc20e0a577388a602985fb31c3200309Doris Liu public void addPreviewAreaSizeChangedListener( 4402bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong PreviewStatusListener.PreviewAreaChangedListener listener) { 441482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && !mPreviewSizeChangedListeners.contains(listener)) { 442482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.add(listener); 443a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu if (mPreviewArea.width() == 0 || mPreviewArea.height() == 0) { 4442bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(new RectF(0, 0, mWidth, mHeight)); 445a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } else { 4462bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong listener.onPreviewAreaChanged(new RectF(mPreviewArea)); 447a1ec04a9f9526418f5cb17a5afbfc48aca1e02d0Doris Liu } 448482de029dc20e0a577388a602985fb31c3200309Doris Liu } 449482de029dc20e0a577388a602985fb31c3200309Doris Liu } 450482de029dc20e0a577388a602985fb31c3200309Doris Liu 451482de029dc20e0a577388a602985fb31c3200309Doris Liu /** 4522bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * Removes a listener that gets notified when the preview area changed. 453482de029dc20e0a577388a602985fb31c3200309Doris Liu * 4542bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong * @param listener the listener that gets notified of preview area change 455482de029dc20e0a577388a602985fb31c3200309Doris Liu */ 456482de029dc20e0a577388a602985fb31c3200309Doris Liu public void removePreviewAreaSizeChangedListener( 4572bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong PreviewStatusListener.PreviewAreaChangedListener listener) { 458482de029dc20e0a577388a602985fb31c3200309Doris Liu if (listener != null && mPreviewSizeChangedListeners.contains(listener)) { 459482de029dc20e0a577388a602985fb31c3200309Doris Liu mPreviewSizeChangedListeners.remove(listener); 460482de029dc20e0a577388a602985fb31c3200309Doris Liu } 46170da918464276b110c43868caa272c97baadb89eDoris Liu } 46270da918464276b110c43868caa272c97baadb89eDoris Liu 46370da918464276b110c43868caa272c97baadb89eDoris Liu @Override 46470da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 46570da918464276b110c43868caa272c97baadb89eDoris Liu // Workaround for b/11168275, see b/10981460 for more details 46670da918464276b110c43868caa272c97baadb89eDoris Liu if (mWidth != 0 && mHeight != 0) { 46770da918464276b110c43868caa272c97baadb89eDoris Liu // Re-apply transform matrix for new surface texture 46870da918464276b110c43868caa272c97baadb89eDoris Liu updateTransform(); 46970da918464276b110c43868caa272c97baadb89eDoris Liu } 47070da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 47170da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureAvailable(surface, width, height); 47270da918464276b110c43868caa272c97baadb89eDoris Liu } 47370da918464276b110c43868caa272c97baadb89eDoris Liu } 47470da918464276b110c43868caa272c97baadb89eDoris Liu 47570da918464276b110c43868caa272c97baadb89eDoris Liu @Override 47670da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 47770da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 47870da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height); 47970da918464276b110c43868caa272c97baadb89eDoris Liu } 48070da918464276b110c43868caa272c97baadb89eDoris Liu } 48170da918464276b110c43868caa272c97baadb89eDoris Liu 48270da918464276b110c43868caa272c97baadb89eDoris Liu @Override 48370da918464276b110c43868caa272c97baadb89eDoris Liu public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 48470da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 48570da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureDestroyed(surface); 48670da918464276b110c43868caa272c97baadb89eDoris Liu } 48770da918464276b110c43868caa272c97baadb89eDoris Liu return false; 48870da918464276b110c43868caa272c97baadb89eDoris Liu } 48970da918464276b110c43868caa272c97baadb89eDoris Liu 49070da918464276b110c43868caa272c97baadb89eDoris Liu @Override 49170da918464276b110c43868caa272c97baadb89eDoris Liu public void onSurfaceTextureUpdated(SurfaceTexture surface) { 49270da918464276b110c43868caa272c97baadb89eDoris Liu if (mSurfaceTextureListener != null) { 49370da918464276b110c43868caa272c97baadb89eDoris Liu mSurfaceTextureListener.onSurfaceTextureUpdated(surface); 49470da918464276b110c43868caa272c97baadb89eDoris Liu } 49570da918464276b110c43868caa272c97baadb89eDoris Liu 49670da918464276b110c43868caa272c97baadb89eDoris Liu } 49770da918464276b110c43868caa272c97baadb89eDoris Liu} 498