ViewfinderSurface.java
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.viewfinder.internal.surface;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.TextureView;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.camera.viewfinder.internal.utils.Logger;
import androidx.camera.viewfinder.internal.utils.futures.Futures;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import com.google.common.util.concurrent.ListenableFuture;
/**
* A class for creating and tracking use of a {@link Surface} in an asynchronous manner.
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public abstract class ViewfinderSurface {
private static final String TAG = "ViewfinderSurface";
@NonNull private final Object mLock = new Object();
@NonNull private final ListenableFuture<Void> mTerminationFuture;
@GuardedBy("mLock")
private boolean mClosed = false;
@Nullable
@GuardedBy("mLock")
private CallbackToFutureAdapter.Completer<Void> mTerminationCompleter;
public ViewfinderSurface() {
mTerminationFuture = CallbackToFutureAdapter.getFuture(completer -> {
synchronized (mLock) {
mTerminationCompleter = completer;
}
return "ViewfinderSurface-termination(" + ViewfinderSurface.this + ")";
});
}
@NonNull
public final ListenableFuture<Surface> getSurface() {
return provideSurfaceAsync();
}
@NonNull
public ListenableFuture<Void> getTerminationFuture() {
return Futures.nonCancellationPropagating(mTerminationFuture);
}
/**
* Close the surface.
*
* <p> After closing, the underlying surface resources can be safely released by
* {@link SurfaceView} or {@link TextureView} implementation.
*/
public void close() {
CallbackToFutureAdapter.Completer<Void> terminationCompleter = null;
synchronized (mLock) {
if (!mClosed) {
mClosed = true;
terminationCompleter = mTerminationCompleter;
mTerminationCompleter = null;
Logger.d(TAG,
"surface closed, closed=true " + this);
}
}
if (terminationCompleter != null) {
terminationCompleter.set(null);
}
}
@NonNull
protected abstract ListenableFuture<Surface> provideSurfaceAsync();
/**
* The exception that is returned by the ListenableFuture of {@link #getSurface()} if the
* deferrable surface is unable to produce a {@link Surface}.
*/
public static final class SurfaceUnavailableException extends Exception {
public SurfaceUnavailableException(@NonNull String message) {
super(message);
}
}
}