diff options
6 files changed, 405 insertions, 18 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 9a16390baf10..62f78bd07511 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -17949,6 +17949,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateOrientationMap> INFO_DEVICE_STATE_ORIENTATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES; @@ -18643,6 +18644,12 @@ package android.hardware.camera2.params { method public android.util.Rational getElement(int, int); } + public final class DeviceStateOrientationMap { + method public int getSensorOrientation(long); + field public static final long FOLDED = 4L; // 0x4L + field public static final long NORMAL = 0L; // 0x0L + } + public final class ExtensionSessionConfiguration { ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback); method @NonNull public java.util.concurrent.Executor getExecutor(); diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index e0138c5db178..ddac22cd42a3 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -22,15 +22,18 @@ import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.utils.TypeReference; import android.os.Build; +import android.util.Log; import android.util.Rational; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -202,8 +205,25 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri private List<CaptureResult.Key<?>> mAvailableResultKeys; private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations; + private final Object mLock = new Object(); + @GuardedBy("mLock") + private boolean mFoldedDeviceState; + + private final CameraManager.DeviceStateListener mFoldStateListener = + new CameraManager.DeviceStateListener() { + @Override + public final void onDeviceStateChanged(boolean folded) { + synchronized (mLock) { + mFoldedDeviceState = folded; + } + }}; + + private static final String TAG = "CameraCharacteristics"; + /** * Takes ownership of the passed-in properties object + * + * @param properties Camera properties. * @hide */ public CameraCharacteristics(CameraMetadataNative properties) { @@ -220,6 +240,41 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri } /** + * Return the device state listener for this Camera characteristics instance + */ + CameraManager.DeviceStateListener getDeviceStateListener() { return mFoldStateListener; } + + /** + * Overrides the property value + * + * <p>Check whether a given property value needs to be overridden in some specific + * case.</p> + * + * @param key The characteristics field to override. + * @return The value of overridden property, or {@code null} if the property doesn't need an + * override. + */ + @Nullable + private <T> T overrideProperty(Key<T> key) { + if (CameraCharacteristics.SENSOR_ORIENTATION.equals(key) && (mFoldStateListener != null) && + (mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS) != null)) { + DeviceStateOrientationMap deviceStateOrientationMap = + mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATION_MAP); + synchronized (mLock) { + Integer ret = deviceStateOrientationMap.getSensorOrientation(mFoldedDeviceState ? + DeviceStateOrientationMap.FOLDED : DeviceStateOrientationMap.NORMAL); + if (ret >= 0) { + return (T) ret; + } else { + Log.w(TAG, "No valid device state to orientation mapping! Using default!"); + } + } + } + + return null; + } + + /** * Get a camera characteristics field value. * * <p>The field definitions can be @@ -235,7 +290,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri */ @Nullable public <T> T get(Key<T> key) { - return mProperties.get(key); + T propertyOverride = overrideProperty(key); + return (propertyOverride != null) ? propertyOverride : mProperties.get(key); } /** @@ -3993,11 +4049,26 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * upright on the device screen in its native orientation.</p> * <p>Also defines the direction of rolling shutter readout, which is from top to bottom in * the sensor's coordinate system.</p> + * <p>Starting with Android API level 32, camera clients that query the orientation via + * {@link android.hardware.camera2.CameraCharacteristics#get } on foldable devices which + * include logical cameras can receive a value that can dynamically change depending on the + * device/fold state. + * Clients are advised to not cache or store the orientation value of such logical sensors. + * In case repeated queries to CameraCharacteristics are not preferred, then clients can + * also access the entire mapping from device state to sensor orientation in + * {@link android.hardware.camera2.params.DeviceStateOrientationMap }. + * Do note that a dynamically changing sensor orientation value in camera characteristics + * will not be the best way to establish the orientation per frame. Clients that want to + * know the sensor orientation of a particular captured frame should query the + * {@link CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID android.logicalMultiCamera.activePhysicalId} from the corresponding capture result and + * check the respective physical camera orientation.</p> * <p><b>Units</b>: Degrees of clockwise rotation; always a multiple of * 90</p> * <p><b>Range of valid values:</b><br> * 0, 90, 180, 270</p> * <p>This key is available on all devices.</p> + * + * @see CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID */ @PublicKey @NonNull @@ -4307,6 +4378,46 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<String>("android.info.version", String.class); /** + * <p>This lists the mapping between a device folding state and + * specific camera sensor orientation for logical cameras on a foldable device.</p> + * <p>Logical cameras on foldable devices can support sensors with different orientation + * values. The orientation value may need to change depending on the specific folding + * state. Information about the mapping between the device folding state and the + * sensor orientation can be obtained in + * {@link android.hardware.camera2.params.DeviceStateOrientationMap }. + * Device state orientation maps are optional and maybe present on devices that support + * {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop}.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key<android.hardware.camera2.params.DeviceStateOrientationMap> INFO_DEVICE_STATE_ORIENTATION_MAP = + new Key<android.hardware.camera2.params.DeviceStateOrientationMap>("android.info.deviceStateOrientationMap", android.hardware.camera2.params.DeviceStateOrientationMap.class); + + /** + * <p>HAL must populate the array with + * (hardware::camera::provider::V2_5::DeviceState, sensorOrientation) pairs for each + * supported device state bitwise combination.</p> + * <p><b>Units</b>: (device fold state, sensor orientation) x n</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final Key<long[]> INFO_DEVICE_STATE_ORIENTATIONS = + new Key<long[]>("android.info.deviceStateOrientations", long[].class); + + /** * <p>The maximum number of frames that can occur after a request * (different than the previous) has been submitted, and before the * result's state becomes synchronized.</p> diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 5833b3dbef86..9bb901f8c5f7 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -30,15 +30,19 @@ import android.hardware.ICameraServiceListener; import android.hardware.camera2.impl.CameraDeviceImpl; import android.hardware.camera2.impl.CameraInjectionSessionImpl; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.utils.CameraIdAndSessionConfiguration; import android.hardware.camera2.utils.ConcurrentCameraIdCombination; +import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.DeadObjectException; import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,6 +54,10 @@ import android.util.Log; import android.util.Size; import android.view.Display; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; + +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -97,6 +105,80 @@ public final class CameraManager { synchronized(mLock) { mContext = context; } + + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mFoldStateListener = new FoldStateListener(context); + context.getSystemService(DeviceStateManager.class) + .registerCallback(new HandlerExecutor(mHandler), mFoldStateListener); + } + + private HandlerThread mHandlerThread; + private Handler mHandler; + private FoldStateListener mFoldStateListener; + @GuardedBy("mLock") + private ArrayList<WeakReference<DeviceStateListener>> mDeviceStateListeners = new ArrayList<>(); + private boolean mFoldedDeviceState; + + /** + * @hide + */ + public interface DeviceStateListener { + void onDeviceStateChanged(boolean folded); + } + + private final class FoldStateListener implements DeviceStateManager.DeviceStateCallback { + private final int[] mFoldedDeviceStates; + + public FoldStateListener(Context context) { + mFoldedDeviceStates = context.getResources().getIntArray( + com.android.internal.R.array.config_foldedDeviceStates); + } + + private void handleStateChange(int state) { + boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state); + synchronized (mLock) { + mFoldedDeviceState = folded; + ArrayList<WeakReference<DeviceStateListener>> invalidListeners = new ArrayList<>(); + for (WeakReference<DeviceStateListener> listener : mDeviceStateListeners) { + DeviceStateListener callback = listener.get(); + if (callback != null) { + callback.onDeviceStateChanged(folded); + } else { + invalidListeners.add(listener); + } + } + if (!invalidListeners.isEmpty()) { + mDeviceStateListeners.removeAll(invalidListeners); + } + } + } + + @Override + public final void onBaseStateChanged(int state) { + handleStateChange(state); + } + + @Override + public final void onStateChanged(int state) { + handleStateChange(state); + } + } + + /** + * Register a {@link CameraCharacteristics} device state listener + * + * @param chars Camera characteristics that need to receive device state updates + * + * @hide + */ + public void registerDeviceStateListener(@NonNull CameraCharacteristics chars) { + synchronized (mLock) { + DeviceStateListener listener = chars.getDeviceStateListener(); + listener.onDeviceStateChanged(mFoldedDeviceState); + mDeviceStateListeners.add(new WeakReference<>(listener)); + } } /** @@ -504,6 +586,7 @@ public final class CameraManager { "Camera service is currently unavailable", e); } } + registerDeviceStateListener(characteristics); return characteristics; } @@ -1327,8 +1410,7 @@ public final class CameraManager { private ICameraService mCameraService; // Singleton, don't allow construction - private CameraManagerGlobal() { - } + private CameraManagerGlobal() { } public static final boolean sCameraServiceDisabled = SystemProperties.getBoolean("config.disable_cameraservice", false); diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 196134b397cb..37450222aca9 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -50,6 +50,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; import android.hardware.camera2.marshal.impl.MarshalQueryableString; import android.hardware.camera2.params.Capability; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; @@ -754,7 +755,7 @@ public class CameraMetadataNative implements Parcelable { }); sGetCommandMap.put( CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(), - new GetCommand() { + new GetCommand() { @Override @SuppressWarnings("unchecked") public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { @@ -762,6 +763,15 @@ public class CameraMetadataNative implements Parcelable { } }); sGetCommandMap.put( + CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATION_MAP.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getDeviceStateOrientationMap(); + } + }); + sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), new GetCommand() { @Override @@ -994,6 +1004,18 @@ public class CameraMetadataNative implements Parcelable { return map; } + private DeviceStateOrientationMap getDeviceStateOrientationMap() { + long[] mapArray = getBase(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS); + + // Do not warn if map is null while s is not. This is valid. + if (mapArray == null) { + return null; + } + + DeviceStateOrientationMap map = new DeviceStateOrientationMap(mapArray); + return map; + } + private Location getGpsLocation() { String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); diff --git a/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java b/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java new file mode 100644 index 000000000000..3907f040759c --- /dev/null +++ b/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2021 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.params; + +import android.annotation.LongDef; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.utils.HashCodeHelpers; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; + +/** + * Immutable class that maps the device fold state to sensor orientation. + * + * <p>Some {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical} + * cameras on foldables can include physical sensors with different sensor orientation + * values. As a result, the values of the logical camera device can potentially change depending + * on the device fold state.</p> + * + * <p>The device fold state to sensor orientation map will contain information about the + * respective logical camera sensor orientation given a device state. Clients + * can query the mapping for all possible supported folded states. + * + * @see CameraCharacteristics#SENSOR_ORIENTATION + */ +public final class DeviceStateOrientationMap { + /** + * Needs to be kept in sync with the HIDL/AIDL DeviceState + */ + + /** + * The device is in its normal physical configuration. This is the default if the + * device does not support multiple different states. + */ + public static final long NORMAL = 0; + + /** + * The device is folded. If not set, the device is unfolded or does not + * support folding. + * + * The exact point when this status change happens during the folding + * operation is device-specific. + */ + public static final long FOLDED = 1 << 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @LongDef(prefix = {"DEVICE_STATE"}, value = + {NORMAL, + FOLDED }) + public @interface DeviceState {}; + + private final HashMap<Long, Integer> mDeviceStateOrientationMap = new HashMap<>(); + + /** + * Create a new immutable DeviceStateOrientationMap instance. + * + * <p>This constructor takes over the array; do not write to the array afterwards.</p> + * + * @param elements + * An array of elements describing the map + * + * @throws IllegalArgumentException + * if the {@code elements} array length is invalid, not divisible by 2 or contains + * invalid element values + * @throws NullPointerException + * if {@code elements} is {@code null} + * + * @hide + */ + public DeviceStateOrientationMap(final long[] elements) { + mElements = Objects.requireNonNull(elements, "elements must not be null"); + if ((elements.length % 2) != 0) { + throw new IllegalArgumentException("Device state orientation map length " + + elements.length + " is not even!"); + } + + for (int i = 0; i < elements.length; i += 2) { + if ((elements[i+1] % 90) != 0) { + throw new IllegalArgumentException("Sensor orientation not divisible by 90: " + + elements[i+1]); + } + + mDeviceStateOrientationMap.put(elements[i], Math.toIntExact(elements[i + 1])); + } + } + + /** + * Return the logical camera sensor orientation given a specific device fold state. + * + * @param deviceState Device fold state + * + * @return Valid {@link android.hardware.camera2.CameraCharacteristics#SENSOR_ORIENTATION} for + * any supported device fold state + * + * @throws IllegalArgumentException if the given device state is invalid + */ + public int getSensorOrientation(@DeviceState long deviceState) { + if (!mDeviceStateOrientationMap.containsKey(deviceState)) { + throw new IllegalArgumentException("Invalid device state: " + deviceState); + } + + return mDeviceStateOrientationMap.get(deviceState); + } + + /** + * Check if this DeviceStateOrientationMap is equal to another DeviceStateOrientationMap. + * + * <p>Two device state orientation maps are equal if and only if all of their elements are + * {@link Object#equals equal}.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof DeviceStateOrientationMap) { + final DeviceStateOrientationMap other = (DeviceStateOrientationMap) obj; + return Arrays.equals(mElements, other.mElements); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return HashCodeHelpers.hashCodeGeneric(mElements); + } + + private final long[] mElements; +} diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index b0893cc360b7..ed37d7e2e6e6 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -19,6 +19,7 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Camera; import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.hardware.camera2.CameraAccessException; @@ -135,6 +136,7 @@ public class CameraExtensionsProxyService extends Service { private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>(); private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>(); + private CameraManager mCameraManager; private static boolean checkForAdvancedAPI() { if (EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(ADVANCED_VERSION_PREFIX)) { @@ -460,12 +462,12 @@ public class CameraExtensionsProxyService extends Service { // This will setup the camera vendor tag descriptor in the service process // along with all camera characteristics. try { - CameraManager manager = getSystemService(CameraManager.class); + mCameraManager = getSystemService(CameraManager.class); - String [] cameraIds = manager.getCameraIdListNoLazy(); + String [] cameraIds = mCameraManager.getCameraIdListNoLazy(); if (cameraIds != null) { for (String cameraId : cameraIds) { - CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId); + CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId); mCharacteristicsHashMap.put(cameraId, chars); Object thisClass = CameraCharacteristics.Key.class; Class<CameraCharacteristics.Key<?>> keyClass = @@ -1174,8 +1176,9 @@ public class CameraExtensionsProxyService extends Service { @Override public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { mCameraId = cameraId; - mPreviewExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), - CameraExtensionsProxyService.this); + CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics); + mCameraManager.registerDeviceStateListener(chars); + mPreviewExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this); } @Override @@ -1200,13 +1203,16 @@ public class CameraExtensionsProxyService extends Service { @Override public void init(String cameraId, CameraMetadataNative chars) { - mPreviewExtender.init(cameraId, new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + mPreviewExtender.init(cameraId, c); } @Override public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) { - return mPreviewExtender.isExtensionAvailable(cameraId, - new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + return mPreviewExtender.isExtensionAvailable(cameraId, c); } @Override @@ -1283,8 +1289,9 @@ public class CameraExtensionsProxyService extends Service { @Override public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { - mImageExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), - CameraExtensionsProxyService.this); + CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics); + mCameraManager.registerDeviceStateListener(chars); + mImageExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this); mCameraId = cameraId; } @@ -1310,13 +1317,16 @@ public class CameraExtensionsProxyService extends Service { @Override public void init(String cameraId, CameraMetadataNative chars) { - mImageExtender.init(cameraId, new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + mImageExtender.init(cameraId, c); } @Override public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) { - return mImageExtender.isExtensionAvailable(cameraId, - new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + return mImageExtender.isExtensionAvailable(cameraId, c); } @Override |