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.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 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, int)}.
* {@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} | {@link MeteringMode#AE} |
* {@link MeteringMode#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, int)}. App can also this API to enable
* different region for AF and AE respectively.
*
* <p>If any AF points are specified, it will trigger autofocus to start a manual scan. When
* focus is locked and specified AF/AE/AWB regions are updated in capture result, the returned
* {@link ListenableFuture} in {@link CameraControl#startFocusAndMetering(FocusMeteringAction)}
* will completed with {@link FocusMeteringResult#isFocusSuccessful()} set to indicate if focus is
* done successfully or not. If AF point is not specified, it will not trigger autofocus and
* simply wait for specified AE/AWB regions being updated to complete the returned
* {@link ListenableFuture}. In the case of AF points not specified,
* {@link FocusMeteringResult#isFocusSuccessful()} will be set to false. If Af points are
* specified but current camera does not support auto focus,
* {@link FocusMeteringResult#isFocusSuccessful()} will be set to true .
*
* <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 final class FocusMeteringAction {
@MeteringMode
static final int DEFAULT_METERINGMODE = MeteringMode.AF | MeteringMode.AE | MeteringMode.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 long mAutoCancelDurationInMillis;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
FocusMeteringAction(Builder builder) {
mMeteringPointsAf = Collections.unmodifiableList(builder.mMeteringPointsAf);
mMeteringPointsAe = Collections.unmodifiableList(builder.mMeteringPointsAe);
mMeteringPointsAwb = Collections.unmodifiableList(builder.mMeteringPointsAwb);
mAutoCancelDurationInMillis = builder.mAutoCancelDurationInMillis;
}
/**
* Returns auto-cancel duration. Returns 0 if auto-cancel is disabled.
*/
public long getAutoCancelDurationInMillis() {
return mAutoCancelDurationInMillis;
}
/**
* 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 mAutoCancelDurationInMillis > 0;
}
/**
* Focus/Metering mode used to specify which 3A regions is activated for corresponding
* {@link MeteringPoint}.
*/
@IntDef(flag = true, value = {MeteringMode.AF, MeteringMode.AE, MeteringMode.AWB})
@Retention(RetentionPolicy.SOURCE)
public @interface MeteringMode {
int AF = 1;
int AE = 1 << 1;
int AWB = 1 << 2;
}
/**
* The builder used to create the {@link FocusMeteringAction}. App must use
* {@link Builder#from(MeteringPoint)}
* or {@link Builder#from(MeteringPoint, int)} 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 */
long mAutoCancelDurationInMillis = DEFAULT_AUTOCANCEL_DURATION;
private Builder(@NonNull MeteringPoint point) {
this(point, DEFAULT_METERINGMODE);
}
private Builder(@NonNull MeteringPoint point, @MeteringMode int mode) {
addPoint(point, mode);
}
/**
* Creates the Builder from a {@link MeteringPoint} with default
* mode {@link MeteringMode#AF} | {@link MeteringMode#AE} | {@link MeteringMode#AWB}.
*/
@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,
@MeteringMode int mode) {
return new Builder(meteringPoint, mode);
}
/**
* Adds another {@link MeteringPoint} with default mode {@link MeteringMode#AF} |
* {@link MeteringMode#AE} | {@link MeteringMode#AWB}.
*
* <p>If more points are added than what current device supports for AF/AE/AWB, only the
* first region and then in order up to the number of regions supported by the device
* will be enabled. If it turns out no added points can be supported on the device, the
* returned {@link ListenableFuture} in
* {@link CameraControl#startFocusAndMetering(FocusMeteringAction)} will fail immediately.
*/
@NonNull
public Builder addPoint(@NonNull MeteringPoint point) {
return addPoint(point, DEFAULT_METERINGMODE);
}
/**
* Adds another {@link MeteringPoint} with specified {@link MeteringMode}.
*
* <p>If more points are added than what current device supports for AF/AE/AWB, only the
* first region and then in order up to the number of regions supported by the device
* will be enabled. If it turns out no added points can be supported on the device, the
* returned {@link ListenableFuture} in
* {@link CameraControl#startFocusAndMetering(FocusMeteringAction)} will fail immediately.
*
* @param mode Must be a valid {@link MeteringMode}, otherwise an
* {@link IllegalArgumentException} is thrown.
*/
@NonNull
public Builder addPoint(@NonNull MeteringPoint point, @MeteringMode int mode) {
Preconditions.checkArgument(
(mode >= MeteringMode.AF) && (mode <= (MeteringMode.AF | MeteringMode.AE
| MeteringMode.AWB)), "Invalid metering mode " + mode);
if ((mode & MeteringMode.AF) != 0) {
mMeteringPointsAf.add(point);
}
if ((mode & MeteringMode.AE) != 0) {
mMeteringPointsAe.add(point);
}
if ((mode & MeteringMode.AWB) != 0) {
mMeteringPointsAwb.add(point);
}
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. The duration must be greater than or equal to 1 otherwise it
* will throw a {@link IllegalArgumentException}.
*/
@NonNull
public Builder setAutoCancelDuration(@IntRange(from = 1) long duration,
@NonNull TimeUnit timeUnit) {
Preconditions.checkArgument(duration >= 1, "autoCancelDuration must be at least 1");
mAutoCancelDurationInMillis = timeUnit.toMillis(duration);
return this;
}
/**
* Disables the auto-cancel.
*/
@NonNull
public Builder disableAutoCancel() {
mAutoCancelDurationInMillis = 0;
return this;
}
/**
* Builds the {@link FocusMeteringAction} instance.
*/
@NonNull
public FocusMeteringAction build() {
return new FocusMeteringAction(this);
}
}
}