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