FocusMeteringAction.java
/*
* Copyright 2019 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.core;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A configuration used to trigger a focus and/or metering action.
*
* <p>To construct a {@link FocusMeteringAction}, apps have to create a {@link Builder} by
* {@link Builder#from(MeteringPoint)} or {@link Builder#from(MeteringPoint, MeteringMode)}.
* {@link MeteringPoint} is a point used to specify the focus/metering areas. Apps can use various
* {@link MeteringPointFactory} to create the points. When the {@link FocusMeteringAction} is built,
* pass it to {@link CameraControl#startFocusAndMetering(FocusMeteringAction)} to initiate the focus
* and metering action.
*
* <p>The default {@link MeteringMode} is {@link MeteringMode#AF_AE_AWB} which means the point is
* used for all AF/AE/AWB regions. Apps can set the proper {@link MeteringMode} to optionally
* exclude some 3A regions. Multiple regions for specific 3A type are also supported via
* {@link Builder#addPoint(MeteringPoint)} or
* {@link Builder#addPoint(MeteringPoint, MeteringMode)}. App can also this API to enable
* different region for AF and AE respectively.
*
* <p>If any AF points are specified, it will trigger AF to start a manual AF scan and cancel AF
* trigger when {@link CameraControl#cancelFocusAndMetering()} is called. When triggering AF is
* done, it will call the {@link OnAutoFocusListener#onFocusCompleted(boolean)} which is set via
* {@link Builder#setAutoFocusCallback(OnAutoFocusListener)}. If AF point is not specified or
* the action is cancelled before AF is locked, CameraX will call the
* {@link OnAutoFocusListener#onFocusCompleted(boolean)} with isFocusLocked set to false.
*
* <p>App can set a auto-cancel duration to let CameraX call
* {@link CameraControl#cancelFocusAndMetering()} automatically in the specified duration. By
* default the auto-cancel duration is 5 seconds. Apps can call {@link Builder#disableAutoCancel()}
* to disable auto-cancel.
*/
public class FocusMeteringAction {
static final MeteringMode DEFAULT_METERINGMODE = MeteringMode.AF_AE_AWB;
static final long DEFAULT_AUTOCANCEL_DURATION = 5000;
private final List<MeteringPoint> mMeteringPointsAF;
private final List<MeteringPoint> mMeteringPointsAE;
private final List<MeteringPoint> mMeteringPointsAWB;
private final Executor mListenerExecutor;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
final OnAutoFocusListener mOnAutoFocusListener;
private final long mAutoCancelDurationInMs;
private AtomicBoolean mHasNotifiedListener = new AtomicBoolean(false);
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
FocusMeteringAction(Builder builder) {
mMeteringPointsAF = builder.mMeteringPointsAF;
mMeteringPointsAE = builder.mMeteringPointsAE;
mMeteringPointsAWB = builder.mMeteringPointsAWB;
mListenerExecutor = builder.mListenerExecutor;
mOnAutoFocusListener = builder.mOnAutoFocusListener;
mAutoCancelDurationInMs = builder.mAutoCancelDurationInMs;
}
/**
* Returns current {@link OnAutoFocusListener}.
*/
@Nullable
public OnAutoFocusListener getOnAutoFocusListener() {
return mOnAutoFocusListener;
}
/**
* Returns auto-cancel duration. Returns 0 if auto-cancel is disabled.
*/
public long getAutoCancelDurationInMs() {
return mAutoCancelDurationInMs;
}
/**
* Returns all {@link MeteringPoint}s used for AF regions.
*/
@NonNull
public List<MeteringPoint> getMeteringPointsAF() {
return mMeteringPointsAF;
}
/**
* Returns all {@link MeteringPoint}s used for AE regions.
*/
@NonNull
public List<MeteringPoint> getMeteringPointsAE() {
return mMeteringPointsAE;
}
/**
* Returns all {@link MeteringPoint}s used for AWB regions.
*/
@NonNull
public List<MeteringPoint> getMeteringPointsAWB() {
return mMeteringPointsAWB;
}
/**
* Returns if auto-cancel is enabled or not.
*/
public boolean isAutoCancelEnabled() {
return mAutoCancelDurationInMs != 0;
}
@VisibleForTesting
Executor getListenerExecutor() {
return mListenerExecutor;
}
/**
* Notifies current {@link OnAutoFocusListener} and ensures it is called once.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void notifyAutoFocusCompleted(boolean isFocused) {
if (!mHasNotifiedListener.getAndSet(true)) {
if (mOnAutoFocusListener != null) {
mListenerExecutor.execute(new Runnable() {
@Override
public void run() {
mOnAutoFocusListener.onFocusCompleted(isFocused);
}
});
}
}
}
/**
* Listener for receiving auto-focus completion event.
*/
public interface OnAutoFocusListener {
/**
* Called when camera auto focus completes or when the action is cancelled before
* auto-focus completes.
*
* @param isFocusLocked true if focus is locked successfully, false otherwise.
*/
void onFocusCompleted(boolean isFocusLocked);
}
/**
* Focus/Metering mode used to specify which 3A regions is activated for corresponding
* {@link MeteringPoint}.
*/
public enum MeteringMode {
AF_AE_AWB,
AF_AE,
AE_AWB,
AF_AWB,
AF_ONLY,
AE_ONLY,
AWB_ONLY
}
/**
* The builder used to create the {@link FocusMeteringAction}. App must use
* {@link Builder#from(MeteringPoint)}
* or {@link Builder#from(MeteringPoint, MeteringMode)} to create the {@link Builder}.
*/
public static class Builder {
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
final List<MeteringPoint> mMeteringPointsAF = new ArrayList<>();
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
final List<MeteringPoint> mMeteringPointsAE = new ArrayList<>();
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
final List<MeteringPoint> mMeteringPointsAWB = new ArrayList<>();
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
OnAutoFocusListener mOnAutoFocusListener = null;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
Executor mListenerExecutor = CameraXExecutors.mainThreadExecutor();
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
long mAutoCancelDurationInMs = DEFAULT_AUTOCANCEL_DURATION;
private Builder(@NonNull MeteringPoint point) {
this(point, DEFAULT_METERINGMODE);
}
private Builder(@NonNull MeteringPoint point, @NonNull MeteringMode mode) {
addPoint(point, mode);
}
/**
* Creates the Builder from a {@link MeteringPoint} with default {@link MeteringMode}.
*/
@NonNull
public static Builder from(@NonNull MeteringPoint meteringPoint) {
return new Builder(meteringPoint);
}
/**
* Creates the Builder from a {@link MeteringPoint} and {@link MeteringMode}
*/
@NonNull
public static Builder from(@NonNull MeteringPoint meteringPoint,
@NonNull MeteringMode mode) {
return new Builder(meteringPoint, mode);
}
/**
* Adds another {@link MeteringPoint} with default {@link MeteringMode}.
*/
@NonNull
public Builder addPoint(@NonNull MeteringPoint point) {
return addPoint(point, DEFAULT_METERINGMODE);
}
/**
* Adds another {@link MeteringPoint} with specified {@link MeteringMode}.
*/
@NonNull
public Builder addPoint(@NonNull MeteringPoint point, @NonNull MeteringMode mode) {
if (mode == MeteringMode.AF_AE_AWB
|| mode == MeteringMode.AF_AE
|| mode == MeteringMode.AF_AWB
|| mode == MeteringMode.AF_ONLY) {
mMeteringPointsAF.add(point);
}
if (mode == MeteringMode.AF_AE_AWB
|| mode == MeteringMode.AF_AE
|| mode == MeteringMode.AE_AWB
|| mode == MeteringMode.AE_ONLY) {
mMeteringPointsAE.add(point);
}
if (mode == MeteringMode.AF_AE_AWB
|| mode == MeteringMode.AE_AWB
|| mode == MeteringMode.AF_AWB
|| mode == MeteringMode.AWB_ONLY) {
mMeteringPointsAWB.add(point);
}
return this;
}
/**
* Sets the {@link OnAutoFocusListener} to be notified when auto-focus completes. The
* listener is called on main thread.
*/
@NonNull
public Builder setAutoFocusCallback(@NonNull OnAutoFocusListener listener) {
mOnAutoFocusListener = listener;
return this;
}
/**
* Sets the {@link OnAutoFocusListener} to be notified when auto-focus completes. The
* listener is called on specified {@link Executor}.
*/
@NonNull
public Builder setAutoFocusCallback(@NonNull Executor executor,
@NonNull OnAutoFocusListener listener) {
mListenerExecutor = executor;
mOnAutoFocusListener = listener;
return this;
}
/**
* Sets the auto-cancel duration. After set, {@link CameraControl#cancelFocusAndMetering()}
* will be called in specified duration. By default, auto-cancel is enabled with 5
* seconds duration.
*/
@NonNull
public Builder setAutoCancelDuration(long duration, @NonNull TimeUnit timeUnit) {
mAutoCancelDurationInMs = timeUnit.toMillis(duration);
return this;
}
/**
* Disables the auto-cancel.
*/
@NonNull
public Builder disableAutoCancel() {
mAutoCancelDurationInMs = 0;
return this;
}
/**
* Builds the {@link FocusMeteringAction} instance.
*/
@NonNull
public FocusMeteringAction build() {
return new FocusMeteringAction(this);
}
}
}