Merge "Revert "Camera: SessionConfiguration should use Executors"" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6896508045
@@ -16435,8 +16435,8 @@ package android.hardware.camera2.params {
|
||||
}
|
||||
|
||||
public final class SessionConfiguration {
|
||||
ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
|
||||
method public java.util.concurrent.Executor getExecutor();
|
||||
ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler);
|
||||
method public android.os.Handler getHandler();
|
||||
method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
|
||||
method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
|
||||
method public android.hardware.camera2.CaptureRequest getSessionParameters();
|
||||
|
||||
@@ -819,8 +819,7 @@ public abstract class CameraDevice implements AutoCloseable {
|
||||
* @param config A session configuration (see {@link SessionConfiguration}).
|
||||
*
|
||||
* @throws IllegalArgumentException In case the session configuration is invalid; or the output
|
||||
* configurations are empty; or the session configuration
|
||||
* executor is invalid.
|
||||
* configurations are empty.
|
||||
* @throws CameraAccessException In case the camera device is no longer connected or has
|
||||
* encountered a fatal error.
|
||||
* @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* A dispatcher that replaces one argument with another; replaces any argument at an index
|
||||
* with another argument.
|
||||
*
|
||||
* <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always
|
||||
* equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to
|
||||
* be something
|
||||
* that's not an {@code int}.</p>
|
||||
*
|
||||
* @param <T>
|
||||
* source dispatch type, whose methods with {@link #dispatch} will be called
|
||||
* @param <TArg>
|
||||
* argument replacement type, args in {@link #dispatch} matching {@code argumentIndex}
|
||||
* will be overriden to objects of this type
|
||||
*/
|
||||
public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> {
|
||||
|
||||
private final Dispatchable<T> mTarget;
|
||||
private final int mArgumentIndex;
|
||||
private final TArg mReplaceWith;
|
||||
|
||||
/**
|
||||
* Create a new argument replacing dispatcher; dispatches are forwarded to {@code target}
|
||||
* after the argument is replaced.
|
||||
*
|
||||
* <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted
|
||||
* to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set
|
||||
* {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p>
|
||||
*
|
||||
* <p>If a method dispatched has less arguments than {@code argumentIndex}, it is
|
||||
* passed through with the arguments unchanged.</p>
|
||||
*
|
||||
* @param target destination dispatch type, methods will be redirected to this dispatcher
|
||||
* @param argumentIndex the numeric index of the argument {@code >= 0}
|
||||
* @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object
|
||||
*/
|
||||
public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex,
|
||||
TArg replaceWith) {
|
||||
mTarget = checkNotNull(target, "target must not be null");
|
||||
mArgumentIndex = checkArgumentNonnegative(argumentIndex,
|
||||
"argumentIndex must not be negative");
|
||||
mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object dispatch(Method method, Object[] args) throws Throwable {
|
||||
|
||||
if (args.length > mArgumentIndex) {
|
||||
args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches
|
||||
args[mArgumentIndex] = mReplaceWith;
|
||||
}
|
||||
|
||||
return mTarget.dispatch(method, args);
|
||||
}
|
||||
|
||||
private static Object[] arrayCopy(Object[] array) {
|
||||
int length = array.length;
|
||||
Object[] newArray = new Object[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
newArray[i] = array[i];
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Broadcast a single dispatch into multiple other dispatchables.
|
||||
*
|
||||
* <p>Every time {@link #dispatch} is invoked, all the broadcast targets will
|
||||
* see the same dispatch as well. The first target's return value is returned.</p>
|
||||
*
|
||||
* <p>This enables a single listener to be converted into a multi-listener.</p>
|
||||
*/
|
||||
public class BroadcastDispatcher<T> implements Dispatchable<T> {
|
||||
|
||||
private final List<Dispatchable<T>> mDispatchTargets;
|
||||
|
||||
/**
|
||||
* Create a broadcast dispatcher from the supplied dispatch targets.
|
||||
*
|
||||
* @param dispatchTargets one or more targets to dispatch to
|
||||
*/
|
||||
@SafeVarargs
|
||||
public BroadcastDispatcher(Dispatchable<T>... dispatchTargets) {
|
||||
mDispatchTargets = Arrays.asList(
|
||||
checkNotNull(dispatchTargets, "dispatchTargets must not be null"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object dispatch(Method method, Object[] args) throws Throwable {
|
||||
Object result = null;
|
||||
boolean gotResult = false;
|
||||
|
||||
for (Dispatchable<T> dispatchTarget : mDispatchTargets) {
|
||||
Object localResult = dispatchTarget.dispatch(method, args);
|
||||
|
||||
if (!gotResult) {
|
||||
gotResult = true;
|
||||
result = localResult;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Dynamically dispatch a method and its argument to some object.
|
||||
*
|
||||
* <p>This can be used to intercept method calls and do work around them, redirect work,
|
||||
* or block calls entirely.</p>
|
||||
*/
|
||||
public interface Dispatchable<T> {
|
||||
/**
|
||||
* Dispatch the method and arguments to this object.
|
||||
* @param method a method defined in class {@code T}
|
||||
* @param args arguments corresponding to said {@code method}
|
||||
* @return the object returned when invoking {@code method}
|
||||
* @throws Throwable any exception that might have been raised while invoking the method
|
||||
*/
|
||||
public Object dispatch(Method method, Object[] args) throws Throwable;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Duck typing dispatcher; converts dispatch methods calls from one class to another by
|
||||
* looking up equivalently methods at runtime by name.
|
||||
*
|
||||
* <p>For example, if two types have identical method names and arguments, but
|
||||
* are not subclasses/subinterfaces of each other, this dispatcher will allow calls to be
|
||||
* made from one type to the other.</p>
|
||||
*
|
||||
* @param <TFrom> source dispatch type, whose methods with {@link #dispatch} will be called
|
||||
* @param <T> destination dispatch type, methods will be converted to the class of {@code T}
|
||||
*/
|
||||
public class DuckTypingDispatcher<TFrom, T> implements Dispatchable<TFrom> {
|
||||
|
||||
private final MethodNameInvoker<T> mDuck;
|
||||
|
||||
/**
|
||||
* Create a new duck typing dispatcher.
|
||||
*
|
||||
* @param target destination dispatch type, methods will be redirected to this dispatcher
|
||||
* @param targetClass destination dispatch class, methods will be converted to this class's
|
||||
*/
|
||||
public DuckTypingDispatcher(Dispatchable<T> target, Class<T> targetClass) {
|
||||
checkNotNull(targetClass, "targetClass must not be null");
|
||||
checkNotNull(target, "target must not be null");
|
||||
|
||||
mDuck = new MethodNameInvoker<T>(target, targetClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object dispatch(Method method, Object[] args) {
|
||||
return mDuck.invoke(method.getName(), args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
import android.hardware.camera2.utils.UncheckedThrow;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Forward all interface calls into a handler by posting it as a {@code Runnable}.
|
||||
*
|
||||
* <p>All calls will return immediately; functions with return values will return a default
|
||||
* value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p>
|
||||
*
|
||||
* <p>Any exceptions thrown on the handler while trying to invoke a method
|
||||
* will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any
|
||||
* checked exceptions to be thrown will result in "undefined" behavior
|
||||
* (although in practice it is usually thrown as normal).</p>
|
||||
*/
|
||||
public class HandlerDispatcher<T> implements Dispatchable<T> {
|
||||
|
||||
private static final String TAG = "HandlerDispatcher";
|
||||
|
||||
private final Dispatchable<T> mDispatchTarget;
|
||||
private final Handler mHandler;
|
||||
|
||||
/**
|
||||
* Create a dispatcher that forwards it's dispatch calls by posting
|
||||
* them onto the {@code handler} as a {@code Runnable}.
|
||||
*
|
||||
* @param dispatchTarget the destination whose method calls will be redirected into the handler
|
||||
* @param handler all calls into {@code dispatchTarget} will be posted onto this handler
|
||||
* @param <T> the type of the element you want to wrap.
|
||||
* @return a dispatcher that will forward it's dispatch calls to a handler
|
||||
*/
|
||||
public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) {
|
||||
mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
|
||||
mHandler = checkNotNull(handler, "handler must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object dispatch(final Method method, final Object[] args) throws Throwable {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mDispatchTarget.dispatch(method, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getTargetException();
|
||||
// Potential UB. Hopefully 't' is a runtime exception.
|
||||
UncheckedThrow.throwAnyException(t);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Impossible
|
||||
Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Impossible
|
||||
Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
|
||||
} catch (Throwable e) {
|
||||
UncheckedThrow.throwAnyException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO handle primitive return values that would avoid NPE if unboxed
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
import android.hardware.camera2.utils.UncheckedThrow;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
|
||||
public class InvokeDispatcher<T> implements Dispatchable<T> {
|
||||
|
||||
private static final String TAG = "InvocationSink";
|
||||
private final T mTarget;
|
||||
|
||||
public InvokeDispatcher(T target) {
|
||||
mTarget = checkNotNull(target, "target must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object dispatch(Method method, Object[] args) {
|
||||
try {
|
||||
return method.invoke(mTarget, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getTargetException();
|
||||
// Potential UB. Hopefully 't' is a runtime exception.
|
||||
UncheckedThrow.throwAnyException(t);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Impossible
|
||||
Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Impossible
|
||||
Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
|
||||
}
|
||||
|
||||
// unreachable
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.hardware.camera2.utils.UncheckedThrow;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
|
||||
*
|
||||
* @param <T> destination dispatch type, methods will be looked up in the class of {@code T}
|
||||
*/
|
||||
public class MethodNameInvoker<T> {
|
||||
|
||||
private final Dispatchable<T> mTarget;
|
||||
private final Class<T> mTargetClass;
|
||||
private final Method[] mTargetClassMethods;
|
||||
private final ConcurrentHashMap<String, Method> mMethods =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new method name invoker.
|
||||
*
|
||||
* @param target destination dispatch type, invokes will be redirected to this dispatcher
|
||||
* @param targetClass destination dispatch class, the invoked methods will be from this class
|
||||
*/
|
||||
public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
|
||||
mTargetClass = targetClass;
|
||||
mTargetClassMethods = targetClass.getMethods();
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a method by its name.
|
||||
*
|
||||
* <p>If more than one method exists in {@code targetClass}, the first method with the right
|
||||
* number of arguments will be used, and later calls will all use that method.</p>
|
||||
*
|
||||
* @param methodName
|
||||
* The name of the method, which will be matched 1:1 to the destination method
|
||||
* @param params
|
||||
* Variadic parameter list.
|
||||
* @return
|
||||
* The same kind of value that would normally be returned by calling {@code methodName}
|
||||
* statically.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code methodName} does not exist on the target class
|
||||
* @throws Throwable will rethrow anything that the target method would normally throw
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K> K invoke(String methodName, Object... params) {
|
||||
checkNotNull(methodName, "methodName must not be null");
|
||||
|
||||
Method targetMethod = mMethods.get(methodName);
|
||||
if (targetMethod == null) {
|
||||
for (Method method : mTargetClassMethods) {
|
||||
// TODO future: match types of params if possible
|
||||
if (method.getName().equals(methodName) &&
|
||||
(params.length == method.getParameterTypes().length) ) {
|
||||
targetMethod = method;
|
||||
mMethods.put(methodName, targetMethod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetMethod == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Method " + methodName + " does not exist on class " + mTargetClass);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return (K) mTarget.dispatch(targetMethod, params);
|
||||
} catch (Throwable e) {
|
||||
UncheckedThrow.throwAnyException(e);
|
||||
// unreachable
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 android.hardware.camera2.dispatch;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Do nothing when dispatching; follows the null object pattern.
|
||||
*/
|
||||
public class NullDispatcher<T> implements Dispatchable<T> {
|
||||
/**
|
||||
* Create a dispatcher that does nothing when dispatched to.
|
||||
*/
|
||||
public NullDispatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing; all parameters are ignored.
|
||||
*/
|
||||
@Override
|
||||
public Object dispatch(Method method, Object[] args) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
3
core/java/android/hardware/camera2/dispatch/package.html
Normal file
3
core/java/android/hardware/camera2/dispatch/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
{@hide}
|
||||
</body>
|
||||
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
package android.hardware.camera2.impl;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CaptureFailure;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.hardware.camera2.CaptureResult;
|
||||
import android.hardware.camera2.TotalCaptureResult;
|
||||
import android.hardware.camera2.dispatch.Dispatchable;
|
||||
import android.hardware.camera2.dispatch.MethodNameInvoker;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
@@ -35,86 +34,164 @@ import static com.android.internal.util.Preconditions.*;
|
||||
* to use our own proxy mechanism.</p>
|
||||
*/
|
||||
public class CallbackProxies {
|
||||
|
||||
// TODO: replace with codegen
|
||||
|
||||
public static class DeviceStateCallbackProxy extends CameraDeviceImpl.StateCallbackKK {
|
||||
private final MethodNameInvoker<CameraDeviceImpl.StateCallbackKK> mProxy;
|
||||
|
||||
public DeviceStateCallbackProxy(
|
||||
Dispatchable<CameraDeviceImpl.StateCallbackKK> dispatchTarget) {
|
||||
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
|
||||
mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateCallbackKK.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpened(CameraDevice camera) {
|
||||
mProxy.invoke("onOpened", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(CameraDevice camera) {
|
||||
mProxy.invoke("onDisconnected", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(CameraDevice camera, int error) {
|
||||
mProxy.invoke("onError", camera, error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnconfigured(CameraDevice camera) {
|
||||
mProxy.invoke("onUnconfigured", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActive(CameraDevice camera) {
|
||||
mProxy.invoke("onActive", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBusy(CameraDevice camera) {
|
||||
mProxy.invoke("onBusy", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(CameraDevice camera) {
|
||||
mProxy.invoke("onClosed", camera);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIdle(CameraDevice camera) {
|
||||
mProxy.invoke("onIdle", camera);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback {
|
||||
private final MethodNameInvoker<CameraDeviceImpl.CaptureCallback> mProxy;
|
||||
|
||||
public DeviceCaptureCallbackProxy(
|
||||
Dispatchable<CameraDeviceImpl.CaptureCallback> dispatchTarget) {
|
||||
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
|
||||
mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureCallback.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureStarted(CameraDevice camera,
|
||||
CaptureRequest request, long timestamp, long frameNumber) {
|
||||
mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCapturePartial(CameraDevice camera,
|
||||
CaptureRequest request, CaptureResult result) {
|
||||
mProxy.invoke("onCapturePartial", camera, request, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureProgressed(CameraDevice camera,
|
||||
CaptureRequest request, CaptureResult partialResult) {
|
||||
mProxy.invoke("onCaptureProgressed", camera, request, partialResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureCompleted(CameraDevice camera,
|
||||
CaptureRequest request, TotalCaptureResult result) {
|
||||
mProxy.invoke("onCaptureCompleted", camera, request, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureFailed(CameraDevice camera,
|
||||
CaptureRequest request, CaptureFailure failure) {
|
||||
mProxy.invoke("onCaptureFailed", camera, request, failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureSequenceCompleted(CameraDevice camera,
|
||||
int sequenceId, long frameNumber) {
|
||||
mProxy.invoke("onCaptureSequenceCompleted", camera, sequenceId, frameNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureSequenceAborted(CameraDevice camera,
|
||||
int sequenceId) {
|
||||
mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureBufferLost(CameraDevice camera,
|
||||
CaptureRequest request, Surface target, long frameNumber) {
|
||||
mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SessionStateCallbackProxy
|
||||
extends CameraCaptureSession.StateCallback {
|
||||
private final Executor mExecutor;
|
||||
private final CameraCaptureSession.StateCallback mCallback;
|
||||
private final MethodNameInvoker<CameraCaptureSession.StateCallback> mProxy;
|
||||
|
||||
public SessionStateCallbackProxy(Executor executor,
|
||||
CameraCaptureSession.StateCallback callback) {
|
||||
mExecutor = checkNotNull(executor, "executor must not be null");
|
||||
mCallback = checkNotNull(callback, "callback must not be null");
|
||||
public SessionStateCallbackProxy(
|
||||
Dispatchable<CameraCaptureSession.StateCallback> dispatchTarget) {
|
||||
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
|
||||
mProxy = new MethodNameInvoker<>(dispatchTarget,
|
||||
CameraCaptureSession.StateCallback.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigured(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onConfigured(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onConfigured", session);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConfigureFailed(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onConfigureFailed(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onConfigureFailed", session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onReady(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onReady", session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActive(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onActive(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onActive", session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureQueueEmpty(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onCaptureQueueEmpty(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onCaptureQueueEmpty", session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(CameraCaptureSession session) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onClosed(session));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onClosed", session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mCallback.onSurfacePrepared(session, surface));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
mProxy.invoke("onSurfacePrepared", session, surface);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,18 +20,20 @@ import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.hardware.camera2.ICameraDeviceUser;
|
||||
import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher;
|
||||
import android.hardware.camera2.dispatch.BroadcastDispatcher;
|
||||
import android.hardware.camera2.dispatch.DuckTypingDispatcher;
|
||||
import android.hardware.camera2.dispatch.HandlerDispatcher;
|
||||
import android.hardware.camera2.dispatch.InvokeDispatcher;
|
||||
import android.hardware.camera2.params.OutputConfiguration;
|
||||
import android.hardware.camera2.utils.TaskDrainer;
|
||||
import android.hardware.camera2.utils.TaskSingleDrainer;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
@@ -49,11 +51,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
|
||||
private final Surface mInput;
|
||||
/**
|
||||
* User-specified state callback, used for outgoing events; calls to this object will be
|
||||
* automatically invoked via {@code mStateExecutor}.
|
||||
* automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
|
||||
*/
|
||||
private final CameraCaptureSession.StateCallback mStateCallback;
|
||||
/** User-specified state executor used for outgoing state callback events */
|
||||
private final Executor mStateExecutor;
|
||||
/** User-specified state handler used for outgoing state callback events */
|
||||
private final Handler mStateHandler;
|
||||
|
||||
/** Internal camera device; used to translate calls into existing deprecated API */
|
||||
private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
|
||||
@@ -85,7 +87,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
|
||||
* (e.g. no pending captures, no repeating requests, no flush).</p>
|
||||
*/
|
||||
CameraCaptureSessionImpl(int id, Surface input,
|
||||
CameraCaptureSession.StateCallback callback, Executor stateExecutor,
|
||||
CameraCaptureSession.StateCallback callback, Handler stateHandler,
|
||||
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
|
||||
Handler deviceStateHandler, boolean configureSuccess) {
|
||||
if (callback == null) {
|
||||
@@ -96,8 +98,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
|
||||
mIdString = String.format("Session %d: ", mId);
|
||||
|
||||
mInput = input;
|
||||
mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null");
|
||||
mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback);
|
||||
mStateHandler = checkHandler(stateHandler);
|
||||
mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
|
||||
|
||||
mDeviceHandler = checkNotNull(deviceStateHandler, "deviceStateHandler must not be null");
|
||||
mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null");
|
||||
@@ -108,12 +110,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
|
||||
* This ensures total ordering between CameraDevice.StateCallback and
|
||||
* CameraDeviceImpl.CaptureCallback events.
|
||||
*/
|
||||
mSequenceDrainer = new TaskDrainer<>(new HandlerExecutor(mDeviceHandler),
|
||||
new SequenceDrainListener(), /*name*/"seq");
|
||||
mIdleDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
|
||||
new IdleDrainListener(), /*name*/"idle");
|
||||
mAbortDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
|
||||
new AbortDrainListener(), /*name*/"abort");
|
||||
mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
|
||||
/*name*/"seq");
|
||||
mIdleDrainer = new TaskSingleDrainer(mDeviceHandler, new IdleDrainListener(),
|
||||
/*name*/"idle");
|
||||
mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
|
||||
/*name*/"abort");
|
||||
|
||||
// CameraDevice should call configureOutputs and have it finish before constructing us
|
||||
|
||||
@@ -444,140 +446,114 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
|
||||
}
|
||||
|
||||
/**
|
||||
* Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}.
|
||||
* Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code handler}.
|
||||
*/
|
||||
private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) {
|
||||
return new CallbackProxies.SessionStateCallbackProxy(executor, callback);
|
||||
private StateCallback createUserStateCallbackProxy(Handler handler, StateCallback callback) {
|
||||
InvokeDispatcher<StateCallback> userCallbackSink = new InvokeDispatcher<>(callback);
|
||||
HandlerDispatcher<StateCallback> handlerPassthrough =
|
||||
new HandlerDispatcher<>(userCallbackSink, handler);
|
||||
|
||||
return new CallbackProxies.SessionStateCallbackProxy(handlerPassthrough);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward callbacks from
|
||||
* CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback.
|
||||
*
|
||||
* <p>In particular, all calls are automatically split to go both to our own
|
||||
* internal callback, and to the user-specified callback (by transparently posting
|
||||
* to the user-specified handler).</p>
|
||||
*
|
||||
* <p>When a capture sequence finishes, update the pending checked sequences set.</p>
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy(
|
||||
Handler handler, CaptureCallback callback) {
|
||||
final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler(
|
||||
handler) : null;
|
||||
CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() {
|
||||
|
||||
return new CameraDeviceImpl.CaptureCallback() {
|
||||
@Override
|
||||
public void onCaptureStarted(CameraDevice camera,
|
||||
CaptureRequest request, long timestamp, long frameNumber) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureStarted(
|
||||
CameraCaptureSessionImpl.this, request, timestamp,
|
||||
frameNumber));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCapturePartial(CameraDevice camera,
|
||||
CaptureRequest request, android.hardware.camera2.CaptureResult result) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCapturePartial(
|
||||
CameraCaptureSessionImpl.this, request, result));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureProgressed(CameraDevice camera,
|
||||
CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureProgressed(
|
||||
CameraCaptureSessionImpl.this, request, partialResult));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureCompleted(CameraDevice camera,
|
||||
CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureCompleted(
|
||||
CameraCaptureSessionImpl.this, request, result));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureFailed(CameraDevice camera,
|
||||
CaptureRequest request, android.hardware.camera2.CaptureFailure failure) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureFailed(
|
||||
CameraCaptureSessionImpl.this, request, failure));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureSequenceCompleted(CameraDevice camera,
|
||||
int sequenceId, long frameNumber) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureSequenceCompleted(
|
||||
CameraCaptureSessionImpl.this, sequenceId, frameNumber));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
finishPendingSequence(sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureSequenceAborted(CameraDevice camera,
|
||||
int sequenceId) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureSequenceAborted(
|
||||
CameraCaptureSessionImpl.this, sequenceId));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
finishPendingSequence(sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureBufferLost(CameraDevice camera,
|
||||
CaptureRequest request, Surface target, long frameNumber) {
|
||||
if ((callback != null) && (executor != null)) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onCaptureBufferLost(
|
||||
CameraCaptureSessionImpl.this, request, target, frameNumber));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Split the calls from the device callback into local callback and the following chain:
|
||||
* - replace the first CameraDevice arg with a CameraCaptureSession
|
||||
* - duck type from device callback to session callback
|
||||
* - then forward the call to a handler
|
||||
* - then finally invoke the destination method on the session callback object
|
||||
*/
|
||||
if (callback == null) {
|
||||
// OK: API allows the user to not specify a callback, and the handler may
|
||||
// also be null in that case. Collapse whole dispatch chain to only call the local
|
||||
// callback
|
||||
return localCallback;
|
||||
}
|
||||
|
||||
InvokeDispatcher<CameraDeviceImpl.CaptureCallback> localSink =
|
||||
new InvokeDispatcher<>(localCallback);
|
||||
|
||||
InvokeDispatcher<CaptureCallback> userCallbackSink =
|
||||
new InvokeDispatcher<>(callback);
|
||||
HandlerDispatcher<CaptureCallback> handlerPassthrough =
|
||||
new HandlerDispatcher<>(userCallbackSink, handler);
|
||||
DuckTypingDispatcher<CameraDeviceImpl.CaptureCallback, CaptureCallback> duckToSession
|
||||
= new DuckTypingDispatcher<>(handlerPassthrough, CaptureCallback.class);
|
||||
ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureCallback, CameraCaptureSessionImpl>
|
||||
replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
|
||||
/*argumentIndex*/0, this);
|
||||
|
||||
BroadcastDispatcher<CameraDeviceImpl.CaptureCallback> broadcaster =
|
||||
new BroadcastDispatcher<CameraDeviceImpl.CaptureCallback>(
|
||||
replaceDeviceWithSession,
|
||||
localSink);
|
||||
|
||||
return new CallbackProxies.DeviceCaptureCallbackProxy(broadcaster);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
@@ -60,14 +59,14 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
|
||||
* (e.g. no pending captures, no repeating requests, no flush).</p>
|
||||
*/
|
||||
CameraConstrainedHighSpeedCaptureSessionImpl(int id,
|
||||
CameraCaptureSession.StateCallback callback, Executor stateExecutor,
|
||||
CameraCaptureSession.StateCallback callback, Handler stateHandler,
|
||||
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
|
||||
Handler deviceStateHandler, boolean configureSuccess,
|
||||
CameraCharacteristics characteristics) {
|
||||
mCharacteristics = characteristics;
|
||||
CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
|
||||
mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
|
||||
stateExecutor, deviceImpl, deviceStateHandler, configureSuccess);
|
||||
stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,10 +35,8 @@ import android.hardware.camera2.params.SessionConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.hardware.camera2.utils.SubmitInfo;
|
||||
import android.hardware.camera2.utils.SurfaceUtils;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
@@ -60,7 +58,6 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
|
||||
@@ -504,9 +501,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
for (Surface surface : outputs) {
|
||||
outConfigurations.add(new OutputConfiguration(surface));
|
||||
}
|
||||
createCaptureSessionInternal(null, outConfigurations, callback,
|
||||
checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
|
||||
/*sessionParams*/ null);
|
||||
createCaptureSessionInternal(null, outConfigurations, callback, handler,
|
||||
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -521,7 +517,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
// OutputConfiguration objects are immutable, but need to have our own array
|
||||
List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
|
||||
|
||||
createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
|
||||
createCaptureSessionInternal(null, currentOutputs, callback, handler,
|
||||
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
|
||||
}
|
||||
|
||||
@@ -541,9 +537,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
for (Surface surface : outputs) {
|
||||
outConfigurations.add(new OutputConfiguration(surface));
|
||||
}
|
||||
createCaptureSessionInternal(inputConfig, outConfigurations, callback,
|
||||
checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
|
||||
/*sessionParams*/ null);
|
||||
createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler,
|
||||
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -571,8 +566,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
currentOutputs.add(new OutputConfiguration(output));
|
||||
}
|
||||
createCaptureSessionInternal(inputConfig, currentOutputs,
|
||||
callback, checkAndWrapHandler(handler),
|
||||
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
|
||||
callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
|
||||
/*sessionParams*/ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -587,8 +582,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
for (Surface surface : outputs) {
|
||||
outConfigurations.add(new OutputConfiguration(surface));
|
||||
}
|
||||
createCaptureSessionInternal(null, outConfigurations, callback,
|
||||
checkAndWrapHandler(handler),
|
||||
createCaptureSessionInternal(null, outConfigurations, callback, handler,
|
||||
/*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
|
||||
/*sessionParams*/ null);
|
||||
}
|
||||
@@ -603,8 +597,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
for (OutputConfiguration output : outputs) {
|
||||
currentOutputs.add(new OutputConfiguration(output));
|
||||
}
|
||||
createCaptureSessionInternal(inputConfig, currentOutputs, callback,
|
||||
checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
|
||||
createCaptureSessionInternal(inputConfig, currentOutputs, callback, handler, operatingMode,
|
||||
/*sessionParams*/ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -618,17 +612,14 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
if (outputConfigs == null) {
|
||||
throw new IllegalArgumentException("Invalid output configurations");
|
||||
}
|
||||
if (config.getExecutor() == null) {
|
||||
throw new IllegalArgumentException("Invalid executor");
|
||||
}
|
||||
createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
|
||||
config.getStateCallback(), config.getExecutor(), config.getSessionType(),
|
||||
config.getStateCallback(), config.getHandler(), config.getSessionType(),
|
||||
config.getSessionParameters());
|
||||
}
|
||||
|
||||
private void createCaptureSessionInternal(InputConfiguration inputConfig,
|
||||
List<OutputConfiguration> outputConfigurations,
|
||||
CameraCaptureSession.StateCallback callback, Executor executor,
|
||||
CameraCaptureSession.StateCallback callback, Handler handler,
|
||||
int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
|
||||
synchronized(mInterfaceLock) {
|
||||
if (DEBUG) {
|
||||
@@ -682,11 +673,12 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
|
||||
|
||||
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
|
||||
callback, executor, this, mDeviceHandler, configureSuccess,
|
||||
callback, handler, this, mDeviceHandler, configureSuccess,
|
||||
mCharacteristics);
|
||||
} else {
|
||||
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
|
||||
callback, executor, this, mDeviceHandler, configureSuccess);
|
||||
callback, handler, this, mDeviceHandler,
|
||||
configureSuccess);
|
||||
}
|
||||
|
||||
// TODO: wait until current session closes, then create the new session
|
||||
@@ -971,12 +963,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
}
|
||||
}
|
||||
};
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(resultDispatch);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
holder.getHandler().post(resultDispatch);
|
||||
} else {
|
||||
Log.w(TAG, String.format(
|
||||
"did not register callback to request %d",
|
||||
@@ -997,9 +984,9 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
|
||||
Handler handler, boolean repeating) throws CameraAccessException {
|
||||
|
||||
// Need a valid executor, or current thread needs to have a looper, if
|
||||
// Need a valid handler, or current thread needs to have a looper, if
|
||||
// callback is valid
|
||||
Executor executor = getExecutor(handler, callback);
|
||||
handler = checkHandler(handler, callback);
|
||||
|
||||
// Make sure that there all requests have at least 1 surface; all surfaces are non-null;
|
||||
// the surface isn't a physical stream surface for reprocessing request
|
||||
@@ -1053,7 +1040,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
if (callback != null) {
|
||||
mCaptureCallbackMap.put(requestInfo.getRequestId(),
|
||||
new CaptureCallbackHolder(
|
||||
callback, requestList, executor, repeating, mNextSessionId - 1));
|
||||
callback, requestList, handler, repeating, mNextSessionId - 1));
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
|
||||
@@ -1367,7 +1354,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
private final boolean mRepeating;
|
||||
private final CaptureCallback mCallback;
|
||||
private final List<CaptureRequest> mRequestList;
|
||||
private final Executor mExecutor;
|
||||
private final Handler mHandler;
|
||||
private final int mSessionId;
|
||||
/**
|
||||
* <p>Determine if the callback holder is for a constrained high speed request list that
|
||||
@@ -1379,13 +1366,13 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
private final boolean mHasBatchedOutputs;
|
||||
|
||||
CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
|
||||
Executor executor, boolean repeating, int sessionId) {
|
||||
if (callback == null || executor == null) {
|
||||
Handler handler, boolean repeating, int sessionId) {
|
||||
if (callback == null || handler == null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Must have a valid handler and a valid callback");
|
||||
}
|
||||
mRepeating = repeating;
|
||||
mExecutor = executor;
|
||||
mHandler = handler;
|
||||
mRequestList = new ArrayList<CaptureRequest>(requestList);
|
||||
mCallback = callback;
|
||||
mSessionId = sessionId;
|
||||
@@ -1438,8 +1425,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
return getRequest(0);
|
||||
}
|
||||
|
||||
public Executor getExecutor() {
|
||||
return mExecutor;
|
||||
public Handler getHandler() {
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
@@ -1823,12 +1810,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
}
|
||||
}
|
||||
};
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(resultDispatch);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
holder.getHandler().post(resultDispatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1879,7 +1861,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
private void scheduleNotifyError(int code) {
|
||||
mInError = true;
|
||||
CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable(
|
||||
CameraDeviceCallbacks::notifyError, this, code));
|
||||
CameraDeviceCallbacks::notifyError, this, code));
|
||||
}
|
||||
|
||||
private void notifyError(int code) {
|
||||
@@ -1947,41 +1929,36 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
if (isClosed()) return;
|
||||
|
||||
// Dispatch capture start notice
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!CameraDeviceImpl.this.isClosed()) {
|
||||
final int subsequenceId = resultExtras.getSubsequenceId();
|
||||
final CaptureRequest request = holder.getRequest(subsequenceId);
|
||||
holder.getHandler().post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!CameraDeviceImpl.this.isClosed()) {
|
||||
final int subsequenceId = resultExtras.getSubsequenceId();
|
||||
final CaptureRequest request = holder.getRequest(subsequenceId);
|
||||
|
||||
if (holder.hasBatchedOutputs()) {
|
||||
// Send derived onCaptureStarted for requests within the
|
||||
// batch
|
||||
final Range<Integer> fpsRange =
|
||||
request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
|
||||
for (int i = 0; i < holder.getRequestCount(); i++) {
|
||||
holder.getCallback().onCaptureStarted(
|
||||
CameraDeviceImpl.this,
|
||||
holder.getRequest(i),
|
||||
timestamp - (subsequenceId - i) *
|
||||
NANO_PER_SECOND/fpsRange.getUpper(),
|
||||
frameNumber - (subsequenceId - i));
|
||||
}
|
||||
} else {
|
||||
if (holder.hasBatchedOutputs()) {
|
||||
// Send derived onCaptureStarted for requests within the batch
|
||||
final Range<Integer> fpsRange =
|
||||
request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
|
||||
for (int i = 0; i < holder.getRequestCount(); i++) {
|
||||
holder.getCallback().onCaptureStarted(
|
||||
CameraDeviceImpl.this,
|
||||
holder.getRequest(resultExtras.getSubsequenceId()),
|
||||
timestamp, frameNumber);
|
||||
holder.getRequest(i),
|
||||
timestamp - (subsequenceId - i) *
|
||||
NANO_PER_SECOND/fpsRange.getUpper(),
|
||||
frameNumber - (subsequenceId - i));
|
||||
}
|
||||
} else {
|
||||
holder.getCallback().onCaptureStarted(
|
||||
CameraDeviceImpl.this,
|
||||
holder.getRequest(resultExtras.getSubsequenceId()),
|
||||
timestamp, frameNumber);
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2134,12 +2111,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
finalResult = resultAsCapture;
|
||||
}
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(resultDispatch);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
holder.getHandler().post(resultDispatch);
|
||||
|
||||
// Collect the partials for a total result; or mark the frame as totally completed
|
||||
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
|
||||
@@ -2235,12 +2207,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
}
|
||||
};
|
||||
// Dispatch the failure callback
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(failureDispatch);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
holder.getHandler().post(failureDispatch);
|
||||
}
|
||||
} else {
|
||||
boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
|
||||
@@ -2280,49 +2247,13 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
checkAndFireSequenceComplete();
|
||||
|
||||
// Dispatch the failure callback
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
holder.getExecutor().execute(failureDispatch);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
holder.getHandler().post(failureDispatch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // public class CameraDeviceCallbacks
|
||||
|
||||
/**
|
||||
* Instantiate a new Executor.
|
||||
*
|
||||
* <p>If the callback isn't null, check the handler and instantiate a new executor,
|
||||
* otherwise instantiate a new executor in case handler is valid.</p>
|
||||
*/
|
||||
static <T> Executor getExecutor(Handler handler, T callback) {
|
||||
if (callback != null) {
|
||||
return checkAndWrapHandler(handler);
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
return new HandlerExecutor(handler);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Handler in Executor.
|
||||
*
|
||||
* <p>
|
||||
* If handler is null, get the current thread's
|
||||
* Looper to create a Executor with. If no looper exists, throw
|
||||
* {@code IllegalArgumentException}.
|
||||
* </p>
|
||||
*/
|
||||
static Executor checkAndWrapHandler(Handler handler) {
|
||||
return new HandlerExecutor(checkHandler(handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Default handler management.
|
||||
*
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
package android.hardware.camera2.params;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.IntDef;
|
||||
import android.os.Handler;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
@@ -31,7 +31,6 @@ import android.hardware.camera2.params.OutputConfiguration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -79,7 +78,7 @@ public final class SessionConfiguration {
|
||||
private List<OutputConfiguration> mOutputConfigurations;
|
||||
private CameraCaptureSession.StateCallback mStateCallback;
|
||||
private int mSessionType;
|
||||
private Executor mExecutor = null;
|
||||
private Handler mHandler = null;
|
||||
private InputConfiguration mInputConfig = null;
|
||||
private CaptureRequest mSessionParameters = null;
|
||||
|
||||
@@ -88,9 +87,10 @@ public final class SessionConfiguration {
|
||||
*
|
||||
* @param sessionType The session type.
|
||||
* @param outputs A list of output configurations for the capture session.
|
||||
* @param executor The executor which should be used to invoke the callback. In general it is
|
||||
* recommended that camera operations are not done on the main (UI) thread.
|
||||
* @param cb A state callback interface implementation.
|
||||
* @param handler The handler on which the callback will be invoked. If it is
|
||||
* set to null, the callback will be invoked on the current thread's
|
||||
* {@link android.os.Looper looper}.
|
||||
*
|
||||
* @see #SESSION_REGULAR
|
||||
* @see #SESSION_HIGH_SPEED
|
||||
@@ -101,12 +101,11 @@ public final class SessionConfiguration {
|
||||
*/
|
||||
public SessionConfiguration(@SessionMode int sessionType,
|
||||
@NonNull List<OutputConfiguration> outputs,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull CameraCaptureSession.StateCallback cb) {
|
||||
@NonNull CameraCaptureSession.StateCallback cb, @Nullable Handler handler) {
|
||||
mSessionType = sessionType;
|
||||
mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
|
||||
mStateCallback = cb;
|
||||
mExecutor = executor;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,12 +136,14 @@ public final class SessionConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the {@link java.util.concurrent.Executor} for the capture session.
|
||||
* Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
|
||||
*
|
||||
* @return The Executor on which the callback will be invoked.
|
||||
* @return The handler on which the callback will be invoked. If it is
|
||||
* set to null, the callback will be invoked on the current thread's
|
||||
* {@link android.os.Looper looper}.
|
||||
*/
|
||||
public Executor getExecutor() {
|
||||
return mExecutor;
|
||||
public Handler getHandler() {
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package android.hardware.camera2.utils;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TaskDrainer<T> {
|
||||
private static final String TAG = "TaskDrainer";
|
||||
private final boolean DEBUG = false;
|
||||
|
||||
private final Executor mExecutor;
|
||||
private final Handler mHandler;
|
||||
private final DrainListener mListener;
|
||||
private final String mName;
|
||||
|
||||
@@ -73,27 +73,28 @@ public class TaskDrainer<T> {
|
||||
|
||||
/**
|
||||
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
|
||||
* via the {@code executor}.
|
||||
* via the {@code handler}.
|
||||
*
|
||||
* @param executor a non-{@code null} executor to use for listener execution
|
||||
* @param handler a non-{@code null} handler to use to post runnables to
|
||||
* @param listener a non-{@code null} listener where {@code onDrained} will be called
|
||||
*/
|
||||
public TaskDrainer(Executor executor, DrainListener listener) {
|
||||
mExecutor = checkNotNull(executor, "executor must not be null");
|
||||
public TaskDrainer(Handler handler, DrainListener listener) {
|
||||
mHandler = checkNotNull(handler, "handler must not be null");
|
||||
mListener = checkNotNull(listener, "listener must not be null");
|
||||
mName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
|
||||
* via the {@code executor}.
|
||||
* via the {@code handler}.
|
||||
*
|
||||
* @param executor a non-{@code null} executor to use for listener execution
|
||||
* @param handler a non-{@code null} handler to use to post runnables to
|
||||
* @param listener a non-{@code null} listener where {@code onDrained} will be called
|
||||
* @param name an optional name used for debug logging
|
||||
*/
|
||||
public TaskDrainer(Executor executor, DrainListener listener, String name) {
|
||||
mExecutor = checkNotNull(executor, "executor must not be null");
|
||||
public TaskDrainer(Handler handler, DrainListener listener, String name) {
|
||||
// XX: Probably don't need a handler at all here
|
||||
mHandler = checkNotNull(handler, "handler must not be null");
|
||||
mListener = checkNotNull(listener, "listener must not be null");
|
||||
mName = name;
|
||||
}
|
||||
@@ -199,12 +200,15 @@ public class TaskDrainer<T> {
|
||||
}
|
||||
|
||||
private void postDrained() {
|
||||
mExecutor.execute(() -> {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG + "[" + mName + "]", "onDrained");
|
||||
}
|
||||
|
||||
mListener.onDrained();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
package android.hardware.camera2.utils;
|
||||
|
||||
import android.hardware.camera2.utils.TaskDrainer.DrainListener;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
* Keep track of a single concurrent task starting and finishing;
|
||||
@@ -39,25 +38,25 @@ public class TaskSingleDrainer {
|
||||
|
||||
/**
|
||||
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
|
||||
* via the {@code executor}.
|
||||
* via the {@code handler}.
|
||||
*
|
||||
* @param executor a non-{@code null} executor to use for listener execution
|
||||
* @param handler a non-{@code null} handler to use to post runnables to
|
||||
* @param listener a non-{@code null} listener where {@code onDrained} will be called
|
||||
*/
|
||||
public TaskSingleDrainer(Executor executor, DrainListener listener) {
|
||||
mTaskDrainer = new TaskDrainer<>(executor, listener);
|
||||
public TaskSingleDrainer(Handler handler, DrainListener listener) {
|
||||
mTaskDrainer = new TaskDrainer<>(handler, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
|
||||
* via the {@code executor}.
|
||||
* via the {@code handler}.
|
||||
*
|
||||
* @param executor a non-{@code null} executor to use for listener execution
|
||||
* @param handler a non-{@code null} handler to use to post runnables to
|
||||
* @param listener a non-{@code null} listener where {@code onDrained} will be called
|
||||
* @param name an optional name used for debug logging
|
||||
*/
|
||||
public TaskSingleDrainer(Executor executor, DrainListener listener, String name) {
|
||||
mTaskDrainer = new TaskDrainer<>(executor, listener, name);
|
||||
public TaskSingleDrainer(Handler handler, DrainListener listener, String name) {
|
||||
mTaskDrainer = new TaskDrainer<>(handler, listener, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user