1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.view; 18 19 import android.graphics.Bitmap; 20 import android.util.Size; 21 import android.view.View; 22 import android.widget.FrameLayout; 23 24 import androidx.camera.core.SurfaceRequest; 25 26 import com.google.common.util.concurrent.ListenableFuture; 27 28 import org.jspecify.annotations.NonNull; 29 import org.jspecify.annotations.Nullable; 30 31 import java.util.concurrent.Executor; 32 33 /** 34 * Wraps the underlying handling of the {@link android.view.Surface} used for preview, which is 35 * done using either a {@link android.view.TextureView} (see {@link TextureViewImplementation}) 36 * or a {@link android.view.SurfaceView} (see {@link SurfaceViewImplementation}). 37 */ 38 abstract class PreviewViewImplementation { 39 40 @Nullable Size mResolution; 41 42 @NonNull FrameLayout mParent; 43 44 private final @NonNull PreviewTransformation mPreviewTransform; 45 46 private boolean mWasSurfaceProvided = false; 47 initializePreview()48 abstract void initializePreview(); 49 getPreview()50 abstract @Nullable View getPreview(); 51 PreviewViewImplementation(@onNull FrameLayout parent, @NonNull PreviewTransformation previewTransform)52 PreviewViewImplementation(@NonNull FrameLayout parent, 53 @NonNull PreviewTransformation previewTransform) { 54 mParent = parent; 55 mPreviewTransform = previewTransform; 56 } 57 58 /** 59 * Starts to execute the {@link SurfaceRequest} by providing a Surface. 60 * 61 * <p>A listener can be set optionally to be notified when the provided Surface is not in use 62 * any more or the SurfaceRequest is cancelled before providing a Surface. This can be used 63 * as a signal that SurfaceRequest (and the Preview) is no longer using PreviewView and we 64 * can do some cleanup. The listener will be invoked on main thread. 65 */ onSurfaceRequested(@onNull SurfaceRequest surfaceRequest, @Nullable OnSurfaceNotInUseListener onSurfaceNotInUseListener)66 abstract void onSurfaceRequested(@NonNull SurfaceRequest surfaceRequest, 67 @Nullable OnSurfaceNotInUseListener onSurfaceNotInUseListener); 68 69 /** 70 * Invoked when the preview needs to be adjusted, either because the layout bounds of the 71 * preview's container {@link PreviewView} have changed, or the {@link PreviewView.ScaleType} 72 * has changed. 73 * <p> 74 * Corrects and adjusts the preview using the latest {@link PreviewView.ScaleType} and 75 * display properties such as the display orientation and size. 76 */ redrawPreview()77 void redrawPreview() { 78 View preview = getPreview(); 79 // Only calls setScaleX/Y and setTranslationX/Y after the surface has been provided. 80 // Otherwise, it might cause some preview stretched issue when using PERFORMANCE mode 81 // together with Compose UI. For more details, please see b/183864890. 82 if (preview == null || !mWasSurfaceProvided) { 83 return; 84 } 85 mPreviewTransform.transformView(new Size(mParent.getWidth(), 86 mParent.getHeight()), mParent.getLayoutDirection(), preview); 87 } 88 89 /** Invoked after a {@link android.view.Surface} has been provided to the camera for preview. */ onSurfaceProvided()90 void onSurfaceProvided() { 91 mWasSurfaceProvided = true; 92 redrawPreview(); 93 } 94 95 /** Invoked when onAttachedToWindow happens in the PreviewView. */ onAttachedToWindow()96 abstract void onAttachedToWindow(); 97 98 /** Invoked when onDetachedFromWindow happens in the PreviewView */ onDetachedFromWindow()99 abstract void onDetachedFromWindow(); 100 101 /** 102 * Returns a {@link ListenableFuture} which will complete when the next frame is shown. 103 * 104 * <p>For implementation that does not support frame update event, the returned future will 105 * complete immediately. 106 */ waitForNextFrame()107 abstract @NonNull ListenableFuture<Void> waitForNextFrame(); 108 getBitmap()109 @Nullable Bitmap getBitmap() { 110 final Bitmap bitmap = getPreviewBitmap(); 111 if (bitmap == null) { 112 return null; 113 } 114 return mPreviewTransform.createTransformedBitmap(bitmap, 115 new Size(mParent.getWidth(), mParent.getHeight()), 116 mParent.getLayoutDirection()); 117 } 118 getPreviewBitmap()119 abstract @Nullable Bitmap getPreviewBitmap(); 120 setFrameUpdateListener( @onNull Executor executor, PreviewView.@NonNull OnFrameUpdateListener listener)121 void setFrameUpdateListener( 122 @NonNull Executor executor, PreviewView.@NonNull OnFrameUpdateListener listener) {} 123 124 /** 125 * Listener to be notified when the provided Surface is no longer in use or the request is 126 * cancelled before a Surface is provided. 127 */ 128 interface OnSurfaceNotInUseListener { onSurfaceNotInUse()129 void onSurfaceNotInUse(); 130 } 131 } 132