parent
e96008f4b0
commit
53d044e340
@ -1,126 +0,0 @@ |
|||||||
package com.otaliastudios.cameraview.engine; |
|
||||||
|
|
||||||
import android.hardware.camera2.CameraCharacteristics; |
|
||||||
import android.hardware.camera2.CaptureRequest; |
|
||||||
import android.hardware.camera2.CaptureResult; |
|
||||||
import android.hardware.camera2.TotalCaptureResult; |
|
||||||
import android.os.Build; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.RequiresApi; |
|
||||||
|
|
||||||
import com.otaliastudios.cameraview.CameraLogger; |
|
||||||
import com.otaliastudios.cameraview.engine.locking.AutoExposure; |
|
||||||
import com.otaliastudios.cameraview.engine.locking.AutoFocus; |
|
||||||
import com.otaliastudios.cameraview.engine.locking.AutoWhiteBalance; |
|
||||||
import com.otaliastudios.cameraview.engine.locking.Parameter; |
|
||||||
|
|
||||||
/** |
|
||||||
* Helps Camera2-based engines to perform 3A locking and unlocking. |
|
||||||
* Users are required to: |
|
||||||
* |
|
||||||
* - Call {@link #lock(CaptureResult)} to start |
|
||||||
* - Call {@link #onCapture(CaptureResult)} when they have partial or total results, as long as the |
|
||||||
* locker is still in a locking operation, which can be checked through {@link #isLocking()} |
|
||||||
*/ |
|
||||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
|
||||||
public class Locker { |
|
||||||
|
|
||||||
/** |
|
||||||
* The locker callback. |
|
||||||
*/ |
|
||||||
public interface Callback extends Parameter.LockingChangeCallback { |
|
||||||
|
|
||||||
/** |
|
||||||
* Notifies that locking has ended. No action is required for implementors. |
|
||||||
* From now on, {@link #isLocking()} will return false. |
|
||||||
* @param success success |
|
||||||
*/ |
|
||||||
void onLocked(boolean success); |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the currently used builder. This can change while a locking |
|
||||||
* operation happens, so the locker will never cache this value. |
|
||||||
* It is the engine responsibility to copy over values to the new builder |
|
||||||
* when it changes. |
|
||||||
* @return a builder |
|
||||||
*/ |
|
||||||
@NonNull |
|
||||||
CaptureRequest.Builder getLockingBuilder(); |
|
||||||
} |
|
||||||
|
|
||||||
private static final String TAG = Locker.class.getSimpleName(); |
|
||||||
private static final CameraLogger LOG = CameraLogger.create(TAG); |
|
||||||
private static final int FORCED_END_DELAY = 2500; |
|
||||||
|
|
||||||
private final CameraCharacteristics mCharacteristics; |
|
||||||
private final Callback mCallback; |
|
||||||
|
|
||||||
private boolean mIsLocking; |
|
||||||
private Parameter mAutoFocus; |
|
||||||
private Parameter mAutoWhiteBalance; |
|
||||||
private Parameter mAutoExposure; |
|
||||||
private long mLockingStartTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a new locker. |
|
||||||
* @param characteristics the camera characteristics |
|
||||||
* @param callback the callback |
|
||||||
*/ |
|
||||||
public Locker(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull Callback callback) { |
|
||||||
mCharacteristics = characteristics; |
|
||||||
mCallback = callback; |
|
||||||
mAutoFocus = new AutoFocus(callback); |
|
||||||
mAutoExposure = new AutoExposure(callback); |
|
||||||
mAutoWhiteBalance = new AutoWhiteBalance(callback); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Locks 3A values. |
|
||||||
* @param lastResult the last result |
|
||||||
*/ |
|
||||||
public void lock(@NonNull CaptureResult lastResult) { |
|
||||||
mIsLocking = true; |
|
||||||
mLockingStartTime = System.currentTimeMillis(); |
|
||||||
// TODO mAutoFocus.lock(mCharacteristics, mCallback.getLockingBuilder(), lastResult);
|
|
||||||
// TODO mAutoWhiteBalance.lock(mCharacteristics, mCallback.getLockingBuilder(), lastResult);
|
|
||||||
mAutoExposure.lock(mCharacteristics, mCallback.getLockingBuilder(), lastResult); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* True if we're locking. False if we're not, for example |
|
||||||
* if {@link #lock(CaptureResult)} was never called. |
|
||||||
* @return true if locking |
|
||||||
*/ |
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public boolean isLocking() { |
|
||||||
return mIsLocking; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Should be called when we have partial or total CaptureResults, |
|
||||||
* but only while {@link #isLocking()} returns true. |
|
||||||
* @param result result |
|
||||||
*/ |
|
||||||
public void onCapture(@NonNull CaptureResult result) { |
|
||||||
if (!mIsLocking) return; // We're not interested in results anymore
|
|
||||||
if (!(result instanceof TotalCaptureResult)) return; // Let's ignore these, contents are missing/wrong
|
|
||||||
|
|
||||||
// TODO if (!mAutoFocus.isLocked()) mAutoFocus.onCapture(mCallback.getLockingBuilder(), result);
|
|
||||||
if (!mAutoExposure.isLocked()) mAutoExposure.onCapture(mCallback.getLockingBuilder(), result); |
|
||||||
// TODO if (!mAutoWhiteBalance.isLocked()) mAutoWhiteBalance.onCapture(mCallback.getLockingBuilder(), result);
|
|
||||||
if (/* TODO mAutoFocus.isLocked() && */ mAutoExposure.isLocked() /* && mAutoWhiteBalance.isLocked() */) { |
|
||||||
LOG.i("onCapture:", "all Parameters have converged. Dispatching onMeteringEnd"); |
|
||||||
boolean success = /* TODO mAutoFocus.isSuccessful() |
|
||||||
&& */ mAutoExposure.isSuccessful() |
|
||||||
/* TODO && mAutoWhiteBalance.isSuccessful() */; |
|
||||||
mCallback.onLocked(success); |
|
||||||
mIsLocking = false; |
|
||||||
} else if (System.currentTimeMillis() - mLockingStartTime >= FORCED_END_DELAY) { |
|
||||||
LOG.e("onCapture:", "FORCED_END_DELAY was reached. Some Parameter is stuck. Forcing end."); |
|
||||||
mCallback.onLocked(false); |
|
||||||
mIsLocking = false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,7 +1,11 @@ |
|||||||
package com.otaliastudios.cameraview.engine.action; |
package com.otaliastudios.cameraview.engine.action; |
||||||
|
|
||||||
|
import android.os.Build; |
||||||
|
|
||||||
import androidx.annotation.NonNull; |
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
public interface ActionCallback { |
public interface ActionCallback { |
||||||
void onActionStateChanged(@NonNull Action action, int state); |
void onActionStateChanged(@NonNull Action action, int state); |
||||||
} |
} |
||||||
|
@ -0,0 +1,49 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.action; |
||||||
|
|
||||||
|
import android.hardware.camera2.CaptureRequest; |
||||||
|
import android.hardware.camera2.CaptureResult; |
||||||
|
import android.hardware.camera2.TotalCaptureResult; |
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public abstract class ActionWrapper extends BaseAction { |
||||||
|
|
||||||
|
@NonNull |
||||||
|
public abstract BaseAction getAction(); |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onStart(@NonNull ActionHolder holder) { |
||||||
|
super.onStart(holder); |
||||||
|
getAction().addCallback(new ActionCallback() { |
||||||
|
@Override |
||||||
|
public void onActionStateChanged(@NonNull Action action, int state) { |
||||||
|
setState(state); |
||||||
|
if (state == STATE_COMPLETED) { |
||||||
|
action.removeCallback(this); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
getAction().onStart(holder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) { |
||||||
|
super.onCaptureStarted(holder, request); |
||||||
|
getAction().onCaptureStarted(holder, request); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCaptureProgressed(@NonNull ActionHolder holder, @NonNull CaptureRequest request, @NonNull CaptureResult result) { |
||||||
|
super.onCaptureProgressed(holder, request, result); |
||||||
|
getAction().onCaptureProgressed(holder, request, result); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { |
||||||
|
super.onCaptureCompleted(holder, request, result); |
||||||
|
getAction().onCaptureCompleted(holder, request, result); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.action; |
||||||
|
|
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public abstract class CompletionCallback implements ActionCallback { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onActionStateChanged(@NonNull Action action, int state) { |
||||||
|
if (state == Action.STATE_COMPLETED) { |
||||||
|
onActionCompleted(action); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess") |
||||||
|
protected abstract void onActionCompleted(@NonNull Action action); |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.lock; |
||||||
|
|
||||||
|
import android.hardware.camera2.CameraCharacteristics; |
||||||
|
import android.hardware.camera2.CaptureRequest; |
||||||
|
import android.hardware.camera2.CaptureResult; |
||||||
|
import android.hardware.camera2.TotalCaptureResult; |
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
import com.otaliastudios.cameraview.CameraLogger; |
||||||
|
import com.otaliastudios.cameraview.engine.action.ActionHolder; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public class AutoWhiteBalanceLock extends BaseLock { |
||||||
|
|
||||||
|
private final static String TAG = AutoWhiteBalanceLock.class.getSimpleName(); |
||||||
|
private final static CameraLogger LOG = CameraLogger.create(TAG); |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean checkIsSupported(@NonNull ActionHolder holder) { |
||||||
|
boolean isNotLegacy = readCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL, -1) |
||||||
|
!= CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; |
||||||
|
Integer awbMode = holder.getBuilder(this).get(CaptureRequest.CONTROL_AWB_MODE); |
||||||
|
boolean result = isNotLegacy && awbMode != null && awbMode == CaptureRequest.CONTROL_AWB_MODE_AUTO; |
||||||
|
LOG.i("checkIsSupported:", result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean checkShouldSkip(@NonNull ActionHolder holder) { |
||||||
|
Integer awbState = holder.getLastResult(this).get(CaptureResult.CONTROL_AWB_STATE); |
||||||
|
boolean result = awbState != null && awbState == CaptureRequest.CONTROL_AWB_STATE_LOCKED; |
||||||
|
LOG.i("checkShouldSkip:", result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onStarted(@NonNull ActionHolder holder) { |
||||||
|
holder.getBuilder(this).set(CaptureRequest.CONTROL_AWB_LOCK, true); |
||||||
|
holder.applyBuilder(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCaptureCompleted(@NonNull ActionHolder holder, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { |
||||||
|
super.onCaptureCompleted(holder, request, result); |
||||||
|
Integer awbState = result.get(CaptureResult.CONTROL_AWB_STATE); |
||||||
|
LOG.i("processCapture:", "awbState:", awbState); |
||||||
|
if (awbState == null) return; |
||||||
|
switch (awbState) { |
||||||
|
case CaptureRequest.CONTROL_AWB_STATE_LOCKED: { |
||||||
|
setState(STATE_COMPLETED); |
||||||
|
break; |
||||||
|
} |
||||||
|
case CaptureRequest.CONTROL_AWB_STATE_CONVERGED: |
||||||
|
case CaptureRequest.CONTROL_AWB_STATE_INACTIVE: |
||||||
|
case CaptureRequest.CONTROL_AWB_STATE_SEARCHING: { |
||||||
|
// Wait...
|
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.lock; |
||||||
|
|
||||||
|
import android.hardware.camera2.CameraCharacteristics; |
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
import com.otaliastudios.cameraview.engine.action.ActionHolder; |
||||||
|
import com.otaliastudios.cameraview.engine.action.BaseAction; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public abstract class BaseLock extends BaseAction { |
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess") |
||||||
|
@NonNull |
||||||
|
protected <T> T readCharacteristic(@NonNull CameraCharacteristics.Key<T> key, |
||||||
|
@NonNull T fallback) { |
||||||
|
T value = getHolder().getCharacteristics(this).get(key); |
||||||
|
return value == null ? fallback : value; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final void onStart(@NonNull ActionHolder holder) { |
||||||
|
super.onStart(holder); |
||||||
|
boolean isSkipped = checkShouldSkip(holder); |
||||||
|
boolean isSupported = checkIsSupported(holder); |
||||||
|
if (isSupported && !isSkipped) { |
||||||
|
onStarted(holder); |
||||||
|
} else { |
||||||
|
setState(STATE_COMPLETED); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract void onStarted(@NonNull ActionHolder holder); |
||||||
|
|
||||||
|
protected abstract boolean checkShouldSkip(@NonNull ActionHolder holder); |
||||||
|
|
||||||
|
protected abstract boolean checkIsSupported(@NonNull ActionHolder holder); |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.lock; |
||||||
|
|
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
import com.otaliastudios.cameraview.engine.action.ActionWrapper; |
||||||
|
import com.otaliastudios.cameraview.engine.action.Actions; |
||||||
|
import com.otaliastudios.cameraview.engine.action.BaseAction; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public class LockAction extends ActionWrapper { |
||||||
|
|
||||||
|
private final BaseAction action = Actions.together( |
||||||
|
new AutoExposureLock(), |
||||||
|
new AutoFocusLock(), |
||||||
|
new AutoWhiteBalanceLock() |
||||||
|
); |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public BaseAction getAction() { |
||||||
|
return action; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package com.otaliastudios.cameraview.engine.lock; |
||||||
|
|
||||||
|
import android.hardware.camera2.CaptureRequest; |
||||||
|
import android.os.Build; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.annotation.RequiresApi; |
||||||
|
|
||||||
|
import com.otaliastudios.cameraview.engine.action.ActionHolder; |
||||||
|
import com.otaliastudios.cameraview.engine.action.BaseAction; |
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public class UnlockAction extends BaseAction { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onStart(@NonNull ActionHolder holder) { |
||||||
|
super.onStart(holder); |
||||||
|
holder.getBuilder(this).set(CaptureRequest.CONTROL_AE_LOCK, false); |
||||||
|
holder.getBuilder(this).set(CaptureRequest.CONTROL_AWB_LOCK, false); |
||||||
|
holder.applyBuilder(this); |
||||||
|
setState(STATE_COMPLETED); |
||||||
|
// TODO focus is managed by the engine
|
||||||
|
// TODO should wait results?
|
||||||
|
} |
||||||
|
} |
@ -1,73 +0,0 @@ |
|||||||
package com.otaliastudios.cameraview.engine.locking; |
|
||||||
|
|
||||||
import android.hardware.camera2.CameraCharacteristics; |
|
||||||
import android.hardware.camera2.CaptureRequest; |
|
||||||
import android.hardware.camera2.CaptureResult; |
|
||||||
import android.os.Build; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.RequiresApi; |
|
||||||
|
|
||||||
import com.otaliastudios.cameraview.CameraLogger; |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
|
||||||
public class AutoWhiteBalance extends Parameter { |
|
||||||
|
|
||||||
private static final String TAG = AutoWhiteBalance.class.getSimpleName(); |
|
||||||
private static final CameraLogger LOG = CameraLogger.create(TAG + "Locking"); |
|
||||||
|
|
||||||
public AutoWhiteBalance(@NonNull LockingChangeCallback callback) { |
|
||||||
super(callback); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected boolean checkSupportsLocking(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CaptureRequest.Builder builder) { |
|
||||||
boolean isNotLegacy = readCharacteristic(characteristics, |
|
||||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL, -1) != |
|
||||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; |
|
||||||
Integer awbMode = builder.get(CaptureRequest.CONTROL_AWB_MODE); |
|
||||||
boolean result = isNotLegacy && awbMode != null && awbMode == CaptureRequest.CONTROL_AWB_MODE_AUTO; |
|
||||||
LOG.i("checkSupportsLocking:", result); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected boolean checkShouldSkip(@NonNull CaptureResult lastResult) { |
|
||||||
Integer awbState = lastResult.get(CaptureResult.CONTROL_AWB_STATE); |
|
||||||
boolean result = awbState != null && awbState == CaptureRequest.CONTROL_AWB_STATE_LOCKED; |
|
||||||
LOG.i("checkShouldSkip:", result); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onLock(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CaptureRequest.Builder builder) { |
|
||||||
builder.set(CaptureRequest.CONTROL_AWB_LOCK, true); |
|
||||||
notifyBuilderChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void processCapture(@NonNull CaptureResult result) { |
|
||||||
Integer awbState = result.get(CaptureResult.CONTROL_AWB_STATE); |
|
||||||
LOG.i("processCapture:", "awbState:", awbState); |
|
||||||
if (awbState == null) return; |
|
||||||
switch (awbState) { |
|
||||||
case CaptureRequest.CONTROL_AWB_STATE_LOCKED: { |
|
||||||
notifyLocked(true); |
|
||||||
break; |
|
||||||
} |
|
||||||
case CaptureRequest.CONTROL_AWB_STATE_CONVERGED: |
|
||||||
case CaptureRequest.CONTROL_AWB_STATE_INACTIVE: |
|
||||||
case CaptureRequest.CONTROL_AWB_STATE_SEARCHING: { |
|
||||||
// Wait...
|
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onLocked(@NonNull CaptureRequest.Builder builder, boolean success) { |
|
||||||
// Do nothing
|
|
||||||
} |
|
||||||
} |
|
@ -1,88 +0,0 @@ |
|||||||
package com.otaliastudios.cameraview.engine.locking; |
|
||||||
|
|
||||||
import android.hardware.camera2.CameraCharacteristics; |
|
||||||
import android.hardware.camera2.CaptureRequest; |
|
||||||
import android.hardware.camera2.CaptureResult; |
|
||||||
import android.os.Build; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.RequiresApi; |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
|
||||||
public abstract class Parameter { |
|
||||||
|
|
||||||
public interface LockingChangeCallback { |
|
||||||
void onLockingChange(); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isSuccessful; |
|
||||||
private boolean isLocked; |
|
||||||
private LockingChangeCallback callback; |
|
||||||
private boolean shouldSkip; |
|
||||||
private boolean supportsLocking; |
|
||||||
|
|
||||||
protected Parameter(@NonNull LockingChangeCallback callback) { |
|
||||||
this.callback = callback; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
@NonNull |
|
||||||
protected <T> T readCharacteristic(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CameraCharacteristics.Key<T> key, |
|
||||||
@NonNull T fallback) { |
|
||||||
T value = characteristics.get(key); |
|
||||||
return value == null ? fallback : value; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
protected void notifyBuilderChanged() { |
|
||||||
callback.onLockingChange(); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "SameParameterValue"}) |
|
||||||
protected void notifyLocked(boolean success) { |
|
||||||
isLocked = true; |
|
||||||
isSuccessful = success; |
|
||||||
} |
|
||||||
|
|
||||||
public final boolean isLocked() { |
|
||||||
// A non supported parameter should always appear as metered
|
|
||||||
return isLocked || !supportsLocking || shouldSkip; |
|
||||||
} |
|
||||||
|
|
||||||
public final boolean isSuccessful() { |
|
||||||
// A non supported parameter should always appear as successful
|
|
||||||
return isSuccessful || !supportsLocking || shouldSkip; |
|
||||||
} |
|
||||||
|
|
||||||
public final void lock(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CaptureRequest.Builder builder, |
|
||||||
@NonNull CaptureResult lastResult) { |
|
||||||
isSuccessful = false; |
|
||||||
isLocked = false; |
|
||||||
shouldSkip = checkShouldSkip(lastResult); |
|
||||||
supportsLocking = checkSupportsLocking(characteristics, builder); |
|
||||||
if (!shouldSkip && supportsLocking) { |
|
||||||
onLock(characteristics, builder); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public final void onCapture(@NonNull CaptureRequest.Builder builder, |
|
||||||
@NonNull CaptureResult result) { |
|
||||||
if (isLocked()) return; |
|
||||||
processCapture(result); |
|
||||||
if (isLocked()) onLocked(builder, isSuccessful); |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract boolean checkSupportsLocking(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CaptureRequest.Builder builder); |
|
||||||
|
|
||||||
protected abstract boolean checkShouldSkip(@NonNull CaptureResult lastResult); |
|
||||||
|
|
||||||
protected abstract void onLock(@NonNull CameraCharacteristics characteristics, |
|
||||||
@NonNull CaptureRequest.Builder builder); |
|
||||||
|
|
||||||
protected abstract void processCapture(@NonNull CaptureResult result); |
|
||||||
|
|
||||||
protected abstract void onLocked(@NonNull CaptureRequest.Builder builder, boolean success); |
|
||||||
} |
|
Loading…
Reference in new issue