146 lines
5.6 KiB
Java
146 lines
5.6 KiB
Java
/*
|
|
* 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.marshal;
|
|
|
|
import android.annotation.Nullable;
|
|
import android.hardware.camera2.impl.CameraMetadataNative;
|
|
import android.hardware.camera2.utils.TypeReference;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
|
|
*/
|
|
public class MarshalRegistry {
|
|
|
|
/**
|
|
* Register a marshal queryable for the managed type {@code T}.
|
|
*
|
|
* <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
|
|
* this is desirable if they support different native types (e.g. marshaler 1 supports
|
|
* {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
|
|
*
|
|
* @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
|
|
*/
|
|
public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
|
|
synchronized(sMarshalLock) {
|
|
sRegisteredMarshalQueryables.add(queryable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lookup a marshaler between {@code T} and {@code nativeType}.
|
|
*
|
|
* <p>Marshalers are looked up in the order they were registered; earlier registered
|
|
* marshal queriers get priority.</p>
|
|
*
|
|
* @param typeToken The compile-time type reference for {@code T}
|
|
* @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
|
|
* @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
|
|
*
|
|
* @throws UnsupportedOperationException If no marshaler matching the args could be found
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
|
|
synchronized(sMarshalLock) {
|
|
// TODO: can avoid making a new token each time by code-genning
|
|
// the list of type tokens and native types from the keys (at the call sites)
|
|
MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
|
|
|
|
/*
|
|
* Marshalers are instantiated lazily once they are looked up; successive lookups
|
|
* will not instantiate new marshalers.
|
|
*/
|
|
Marshaler<T> marshaler =
|
|
(Marshaler<T>) sMarshalerMap.get(marshalToken);
|
|
|
|
if (marshaler == null) {
|
|
|
|
if (sRegisteredMarshalQueryables.size() == 0) {
|
|
throw new AssertionError("No available query marshalers registered");
|
|
}
|
|
|
|
// Query each marshaler to see if they support the native/managed type combination
|
|
for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
|
|
|
|
MarshalQueryable<T> castedPotential =
|
|
(MarshalQueryable<T>)potentialMarshaler;
|
|
|
|
if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
|
|
marshaler = castedPotential.createMarshaler(typeToken, nativeType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (marshaler == null) {
|
|
throw new UnsupportedOperationException(
|
|
"Could not find marshaler that matches the requested " +
|
|
"combination of type reference " +
|
|
typeToken + " and native type " +
|
|
MarshalHelpers.toStringNativeType(nativeType));
|
|
}
|
|
|
|
// Only put when no cached version exists to avoid +0.5ms lookup per call.
|
|
sMarshalerMap.put(marshalToken, marshaler);
|
|
}
|
|
|
|
return marshaler;
|
|
}
|
|
}
|
|
|
|
private static class MarshalToken<T> {
|
|
public MarshalToken(TypeReference<T> typeReference, int nativeType) {
|
|
this.typeReference = typeReference;
|
|
this.nativeType = nativeType;
|
|
this.hash = typeReference.hashCode() ^ nativeType;
|
|
}
|
|
|
|
final TypeReference<T> typeReference;
|
|
final int nativeType;
|
|
private final int hash;
|
|
|
|
@Override
|
|
public boolean equals(@Nullable Object other) {
|
|
if (other instanceof MarshalToken<?>) {
|
|
MarshalToken<?> otherToken = (MarshalToken<?>)other;
|
|
return typeReference.equals(otherToken.typeReference) &&
|
|
nativeType == otherToken.nativeType;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
// Control access to the static data structures below
|
|
private static final Object sMarshalLock = new Object();
|
|
|
|
private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
|
|
new ArrayList<MarshalQueryable<?>>();
|
|
private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
|
|
new HashMap<MarshalToken<?>, Marshaler<?>>();
|
|
|
|
private MarshalRegistry() {
|
|
throw new AssertionError();
|
|
}
|
|
}
|