Merge "Nfc: Null ptr checks in HAL" am: 3b4d423d42 am: 0ee41f6f8c
am: 87e7c64385
Change-Id: I8706702a3f55ecb6c034e8aa02b3ab4011c2c006
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp
new file mode 100644
index 0000000..69ff791
--- /dev/null
+++ b/audio/2.0/Android.bp
@@ -0,0 +1,106 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.audio@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IDevice.hal",
+ "IDevicesFactory.hal",
+ "IPrimaryDevice.hal",
+ "IStream.hal",
+ "IStreamIn.hal",
+ "IStreamOut.hal",
+ "IStreamOutCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio@2.0",
+ srcs: [
+ ":android.hardware.audio@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/2.0/types.cpp",
+ "android/hardware/audio/2.0/DeviceAll.cpp",
+ "android/hardware/audio/2.0/DevicesFactoryAll.cpp",
+ "android/hardware/audio/2.0/PrimaryDeviceAll.cpp",
+ "android/hardware/audio/2.0/StreamAll.cpp",
+ "android/hardware/audio/2.0/StreamInAll.cpp",
+ "android/hardware/audio/2.0/StreamOutAll.cpp",
+ "android/hardware/audio/2.0/StreamOutCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio@2.0",
+ srcs: [
+ ":android.hardware.audio@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/2.0/types.h",
+ "android/hardware/audio/2.0/IDevice.h",
+ "android/hardware/audio/2.0/IHwDevice.h",
+ "android/hardware/audio/2.0/BnHwDevice.h",
+ "android/hardware/audio/2.0/BpHwDevice.h",
+ "android/hardware/audio/2.0/BsDevice.h",
+ "android/hardware/audio/2.0/IDevicesFactory.h",
+ "android/hardware/audio/2.0/IHwDevicesFactory.h",
+ "android/hardware/audio/2.0/BnHwDevicesFactory.h",
+ "android/hardware/audio/2.0/BpHwDevicesFactory.h",
+ "android/hardware/audio/2.0/BsDevicesFactory.h",
+ "android/hardware/audio/2.0/IPrimaryDevice.h",
+ "android/hardware/audio/2.0/IHwPrimaryDevice.h",
+ "android/hardware/audio/2.0/BnHwPrimaryDevice.h",
+ "android/hardware/audio/2.0/BpHwPrimaryDevice.h",
+ "android/hardware/audio/2.0/BsPrimaryDevice.h",
+ "android/hardware/audio/2.0/IStream.h",
+ "android/hardware/audio/2.0/IHwStream.h",
+ "android/hardware/audio/2.0/BnHwStream.h",
+ "android/hardware/audio/2.0/BpHwStream.h",
+ "android/hardware/audio/2.0/BsStream.h",
+ "android/hardware/audio/2.0/IStreamIn.h",
+ "android/hardware/audio/2.0/IHwStreamIn.h",
+ "android/hardware/audio/2.0/BnHwStreamIn.h",
+ "android/hardware/audio/2.0/BpHwStreamIn.h",
+ "android/hardware/audio/2.0/BsStreamIn.h",
+ "android/hardware/audio/2.0/IStreamOut.h",
+ "android/hardware/audio/2.0/IHwStreamOut.h",
+ "android/hardware/audio/2.0/BnHwStreamOut.h",
+ "android/hardware/audio/2.0/BpHwStreamOut.h",
+ "android/hardware/audio/2.0/BsStreamOut.h",
+ "android/hardware/audio/2.0/IStreamOutCallback.h",
+ "android/hardware/audio/2.0/IHwStreamOutCallback.h",
+ "android/hardware/audio/2.0/BnHwStreamOutCallback.h",
+ "android/hardware/audio/2.0/BpHwStreamOutCallback.h",
+ "android/hardware/audio/2.0/BsStreamOutCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.audio@2.0",
+ generated_sources: ["android.hardware.audio@2.0_genc++"],
+ generated_headers: ["android.hardware.audio@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.audio@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/audio/2.0/Android.mk b/audio/2.0/Android.mk
new file mode 100644
index 0000000..e989364
--- /dev/null
+++ b/audio/2.0/Android.mk
@@ -0,0 +1,46 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio@2.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/audio/V2_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IDevice.hal
+$(GEN): $(LOCAL_PATH)/IDevicesFactory.hal
+$(GEN): $(LOCAL_PATH)/IPrimaryDevice.hal
+$(GEN): $(LOCAL_PATH)/IStream.hal
+$(GEN): $(LOCAL_PATH)/IStreamIn.hal
+$(GEN): $(LOCAL_PATH)/IStreamOut.hal
+$(GEN): $(LOCAL_PATH)/IStreamOutCallback.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.audio@2.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/2.0/IDevice.hal b/audio/2.0/IDevice.hal
new file mode 100644
index 0000000..2b5329b
--- /dev/null
+++ b/audio/2.0/IDevice.hal
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ /*
+ * Returns whether the audio hardware interface has been initialized.
+ *
+ * @return retval OK on success, NOT_INITIALIZED on failure.
+ */
+ initCheck() generates (Result retval);
+
+ /*
+ * Sets the audio volume for all audio activities other than voice call. If
+ * NOT_SUPPORTED is returned, the software mixer will emulate this
+ * capability.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setMasterVolume(float volume) generates (Result retval);
+
+ /*
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. For example, AudioFlinger will query this value
+ * from the primary audio HAL when the service starts and use the value for
+ * setting the initial master volume across all HALs. HALs which do not
+ * support this method must return NOT_SUPPORTED in 'retval'.
+ *
+ * @return retval operation completion status.
+ * @return volume 1.0f means unity, 0.0f is zero.
+ */
+ getMasterVolume() generates (Result retval, float volume);
+
+ /*
+ * Sets microphone muting state.
+ *
+ * @param mute whether microphone is muted.
+ * @return retval operation completion status.
+ */
+ setMicMute(bool mute) generates (Result retval);
+
+ /*
+ * Gets whether microphone is muted.
+ *
+ * @return retval operation completion status.
+ * @return mute whether microphone is muted.
+ */
+ getMicMute() generates (Result retval, bool mute);
+
+ /*
+ * Set the audio mute status for all audio activities. If the return value
+ * is NOT_SUPPORTED, the software mixer will emulate this capability.
+ *
+ * @param mute whether audio is muted.
+ * @return retval operation completion status.
+ */
+ setMasterMute(bool mute) generates (Result retval);
+
+ /**
+ * Get the current master mute status for the HAL, if the HAL supports
+ * master mute control. AudioFlinger will query this value from the primary
+ * audio HAL when the service starts and use the value for setting the
+ * initial master mute across all HALs. HAL must indicate that the feature
+ * is not supported by returning NOT_SUPPORTED status.
+ *
+ * @return retval operation completion status.
+ * @return mute whether audio is muted.
+ */
+ getMasterMute() generates (Result retval, bool mute);
+
+ /*
+ * Returns audio input buffer size according to parameters passed or
+ * INVALID_ARGUMENTS if one of the parameters is not supported.
+ *
+ * @param config audio configuration.
+ * @return retval operation completion status.
+ * @return bufferSize input buffer size in bytes.
+ */
+ getInputBufferSize(AudioConfig config)
+ generates (Result retval, uint64_t bufferSize);
+
+ /*
+ * This method creates and opens the audio hardware output stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @return retval operation completion status.
+ * @return outStream created output stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openOutputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ AudioOutputFlag flags) generates (
+ Result retval,
+ IStreamOut outStream,
+ AudioConfig suggestedConfig);
+
+ /*
+ * This method creates and opens the audio hardware input stream.
+ * If the stream can not be opened with the proposed audio config,
+ * HAL must provide suggested values for the audio config.
+ *
+ * @param ioHandle handle assigned by AudioFlinger.
+ * @param device device type and (if needed) address.
+ * @param config stream configuration.
+ * @param flags additional flags.
+ * @param source source specification.
+ * @return retval operation completion status.
+ * @return inStream in case of success, created input stream.
+ * @return suggestedConfig in case of invalid parameters, suggested config.
+ */
+ openInputStream(
+ AudioIoHandle ioHandle,
+ DeviceAddress device,
+ AudioConfig config,
+ AudioInputFlag flags,
+ AudioSource source) generates (
+ Result retval,
+ IStreamIn inStream,
+ AudioConfig suggestedConfig);
+
+ /*
+ * Returns whether HAL supports audio patches.
+ *
+ * @return supports true if audio patches are supported.
+ */
+ supportsAudioPatches() generates (bool supports);
+
+ /*
+ * Creates an audio patch between several source and sink ports. The handle
+ * is allocated by the HAL and must be unique for this audio HAL module.
+ *
+ * @param sources patch sources.
+ * @param sinks patch sinks.
+ * @return retval operation completion status.
+ * @return patch created patch handle.
+ */
+ createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+ generates (Result retval, AudioPatchHandle patch);
+
+ /*
+ * Release an audio patch.
+ *
+ * @param patch patch handle.
+ * @return retval operation completion status.
+ */
+ releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+ /*
+ * Returns the list of supported attributes for a given audio port.
+ *
+ * As input, 'port' contains the information (type, role, address etc...)
+ * needed by the HAL to identify the port.
+ *
+ * As output, 'resultPort' contains possible attributes (sampling rates,
+ * formats, channel masks, gain controllers...) for this port.
+ *
+ * @param port port identifier.
+ * @return retval operation completion status.
+ * @return resultPort port descriptor with all parameters filled up.
+ */
+ getAudioPort(AudioPort port)
+ generates (Result retval, AudioPort resultPort);
+
+ /*
+ * Set audio port configuration.
+ *
+ * @param config audio port configuration.
+ * @return retval operation completion status.
+ */
+ setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+ /*
+ * Gets the HW synchronization source of the device. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+ *
+ * @return hwAvSync HW synchronization source
+ */
+ getHwAvSync() generates (AudioHwSync hwAvSync);
+
+ /*
+ * Sets whether the screen is on. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+ *
+ * @param turnedOn whether the screen is turned on.
+ * @return retval operation completion status.
+ */
+ setScreenState(bool turnedOn) generates (Result retval);
+
+ /*
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param keys parameter keys.
+ * @return retval operation completion status.
+ * @return parameters parameter key value pairs.
+ */
+ getParameters(vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /*
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ */
+ setParameters(vec<ParameterValue> parameters) generates (Result retval);
+
+ /*
+ * Dumps information about the stream into the provided file descriptor.
+ * This is used for the dumpsys facility.
+ *
+ * @param fd dump file descriptor.
+ */
+ debugDump(handle fd);
+};
diff --git a/audio/2.0/IDevicesFactory.hal b/audio/2.0/IDevicesFactory.hal
new file mode 100644
index 0000000..0ef6bc5
--- /dev/null
+++ b/audio/2.0/IDevicesFactory.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import IDevice;
+
+interface IDevicesFactory {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ enum Device : int32_t {
+ PRIMARY,
+ A2DP,
+ USB,
+ R_SUBMIX,
+ STUB
+ };
+
+ /*
+ * Opens an audio device. To close the device, it is necessary to release
+ * references to the returned device object.
+ *
+ * @param device device type.
+ * @return retval operation completion status. Returns INVALID_ARGUMENTS
+ * if there is no corresponding hardware module found,
+ * NOT_INITIALIZED if an error occured while opening the hardware
+ * module.
+ * @return result the interface for the created device.
+ */
+ openDevice(Device device) generates (Result retval, IDevice result);
+};
diff --git a/audio/2.0/IPrimaryDevice.hal b/audio/2.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..f1dd56e
--- /dev/null
+++ b/audio/2.0/IPrimaryDevice.hal
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ /*
+ * Sets the audio volume of a voice call.
+ *
+ * @param volume 1.0f means unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setVoiceVolume(float volume) generates (Result retval);
+
+ /*
+ * This method is used to notify the HAL about audio mode changes.
+ *
+ * @param mode new mode.
+ * @return retval operation completion status.
+ */
+ setMode(AudioMode mode) generates (Result retval);
+
+ /*
+ * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT SCO NR + EC are enabled.
+ */
+ getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+ /*
+ * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+ * on the legacy HAL.
+ *
+ * @param enabled whether BT SCO NR + EC are enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+ /*
+ * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether BT Wideband is enabled.
+ */
+ getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+ /*
+ * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+ *
+ * @param enabled whether BT Wideband is enabled.
+ * @return retval operation completion status.
+ */
+ setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+ enum TtyMode : int32_t {
+ OFF,
+ VCO,
+ HCO,
+ FULL
+ };
+
+ /*
+ * Gets current TTY mode selection. Calling this method is equivalent to
+ * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return mode TTY mode.
+ */
+ getTtyMode() generates (Result retval, TtyMode mode);
+
+ /*
+ * Sets current TTY mode. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+ *
+ * @param mode TTY mode.
+ * @return retval operation completion status.
+ */
+ setTtyMode(TtyMode mode) generates (Result retval);
+
+ /*
+ * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to getting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ *
+ * @return retval operation completion status.
+ * @return enabled whether HAC mode is enabled.
+ */
+ getHacEnabled() generates (Result retval, bool enabled);
+
+ /*
+ * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+ * enabled. Calling this method is equivalent to setting
+ * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+ *
+ * @param enabled whether HAC mode is enabled.
+ * @return retval operation completion status.
+ */
+ setHacEnabled(bool enabled) generates (Result retval);
+};
diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal
new file mode 100644
index 0000000..8de7851
--- /dev/null
+++ b/audio/2.0/IStream.hal
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import android.hardware.audio.effect@2.0::IEffect;
+
+interface IStream {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ /*
+ * Return the frame size (number of bytes per sample).
+ *
+ * @return frameSize frame size in bytes.
+ */
+ getFrameSize() generates (uint64_t frameSize);
+
+ /*
+ * Return the frame count of the buffer. Calling this method is equivalent
+ * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+ *
+ * @return count frame count.
+ */
+ getFrameCount() generates (uint64_t count);
+
+ /*
+ * Return the size of input/output buffer in bytes for this stream.
+ * It must be a multiple of the frame size.
+ *
+ * @return buffer buffer size in bytes.
+ */
+ getBufferSize() generates (uint64_t bufferSize);
+
+ /*
+ * Return the sampling rate in Hz.
+ *
+ * @return sampleRateHz sample rate in Hz.
+ */
+ getSampleRate() generates (uint32_t sampleRateHz);
+
+ /*
+ * Return supported sampling rates of the stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the
+ * legacy HAL.
+ *
+ * @return sampleRateHz supported sample rates.
+ */
+ getSupportedSampleRates() generates (vec<uint32_t> sampleRates);
+
+ /*
+ * Sets the sampling rate of the stream. Calling this method is equivalent
+ * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
+ *
+ * @param sampleRateHz sample rate in Hz.
+ * @return retval operation completion status.
+ */
+ setSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+ /*
+ * Return the channel mask of the stream.
+ *
+ * @return mask channel mask.
+ */
+ getChannelMask() generates (AudioChannelMask mask);
+
+ /*
+ * Return supported channel masks of the stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
+ * HAL.
+ *
+ * @return masks supported audio masks.
+ */
+ getSupportedChannelMasks() generates (vec<AudioChannelMask> masks);
+
+ /*
+ * Sets the channel mask of the stream. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
+ *
+ * @param format audio format.
+ * @return retval operation completion status.
+ */
+ setChannelMask(AudioChannelMask mask) generates (Result retval);
+
+ /*
+ * Return the audio format of the stream.
+ *
+ * @return format audio format.
+ */
+ getFormat() generates (AudioFormat format);
+
+ /*
+ * Return supported audio formats of the stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+ * HAL.
+ *
+ * @return formats supported audio formats.
+ */
+ getSupportedFormats() generates (vec<AudioFormat> formats);
+
+ /*
+ * Sets the audio format of the stream. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+ *
+ * @param format audio format.
+ * @return retval operation completion status.
+ */
+ setFormat(AudioFormat format) generates (Result retval);
+
+ /*
+ * Convenience method for retrieving several stream parameters in
+ * one transaction.
+ *
+ * @return sampleRateHz sample rate in Hz.
+ * @return mask channel mask.
+ * @return format audio format.
+ */
+ getAudioProperties() generates (
+ uint32_t sampleRateHz, AudioChannelMask mask, AudioFormat format);
+
+ /*
+ * Applies audio effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to apply.
+ * @return retval operation completion status.
+ */
+ addEffect(uint64_t effectId) generates (Result retval);
+
+ /*
+ * Stops application of the effect to the stream.
+ *
+ * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+ * the effect to remove.
+ * @return retval operation completion status.
+ */
+ removeEffect(uint64_t effectId) generates (Result retval);
+
+ /*
+ * Put the audio hardware input/output into standby mode.
+ * Driver must exit from standby mode at the next I/O operation.
+ *
+ * @return retval operation completion status.
+ */
+ standby() generates (Result retval);
+
+ /*
+ * Return the set of device(s) which this stream is connected to.
+ *
+ * @return device set of device(s) which this stream is connected to.
+ */
+ getDevice() generates (AudioDevice device);
+
+ /*
+ * Connects the stream to the device.
+ *
+ * This method must only be used for HALs that do not support
+ * 'IDevice.createAudioPatch' method. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING in the legacy HAL
+ * interface.
+ *
+ * @param address device to connect the stream to.
+ * @return retval operation completion status.
+ */
+ setDevice(DeviceAddress address) generates (Result retval);
+
+ /*
+ * Notifies the stream about device connection state. Calling this method is
+ * equivalent to setting AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy
+ * HAL.
+ *
+ * @param address audio device specification.
+ * @param connected whether the device is connected.
+ * @return retval operation completion status.
+ */
+ setConnectedState(DeviceAddress address, bool connected)
+ generates (Result retval);
+
+ /*
+ * Sets the HW synchronization source. Calling this method is equivalent to
+ * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+ *
+ * @param hwAvSync HW synchronization source
+ * @return retval operation completion status.
+ */
+ setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+ /*
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param keys parameter keys.
+ * @return retval operation completion status.
+ * @return parameters parameter key value pairs.
+ */
+ getParameters(vec<string> keys)
+ generates (Result retval, vec<ParameterValue> parameters);
+
+ /*
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * @param parameters parameter key value pairs.
+ * @return retval operation completion status.
+ */
+ setParameters(vec<ParameterValue> parameters) generates (Result retval);
+
+ /*
+ * Dumps information about the stream into the provided file descriptor.
+ * This is used for the dumpsys facility.
+ *
+ * @param fd dump file descriptor.
+ */
+ debugDump(handle fd);
+
+ /*
+ * Called by the framework to start a stream operating in mmap mode.
+ * createMmapBuffer() must be called before calling start().
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ start() generates (Result retval);
+
+ /**
+ * Called by the framework to stop a stream operating in mmap mode.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the succes.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ */
+ stop() generates (Result retval) ;
+
+ /*
+ * Called by the framework to retrieve information on the mmap buffer used for audio
+ * samples transfer.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @param minSizeFrames minimum buffer size requested. The actual buffer
+ * size returned in struct MmapBufferInfo can be larger.
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * NOT_INITIALIZED in case of memory allocation error
+ * INVALID_ARGUMENTS if the requested buffer size is too large
+ * INVALID_STATE if called out of sequence
+ * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created.
+ */
+ createMmapBuffer(int32_t minSizeFrames)
+ generates (Result retval, MmapBufferInfo info);
+
+ /*
+ * Called by the framework to read current read/write position in the mmap buffer
+ * with associated time stamp.
+ * Function only implemented by streams operating in mmap mode.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED on non mmap mode streams
+ * INVALID_STATE if called out of sequence
+ * @return position a MmapPosition struct containing current HW read/write position in frames
+ * with associated time stamp.
+ */
+ getMmapPosition()
+ generates (Result retval, MmapPosition position);
+
+ /*
+ * Called by the framework to deinitialize the stream and free up
+ * all the currently allocated resources. It is recommended to close
+ * the stream on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED if called on IStream instead of input or
+ * output stream interface.
+ * INVALID_STATE if the stream was already closed.
+ */
+ close() generates (Result retval);
+};
diff --git a/audio/2.0/IStreamIn.hal b/audio/2.0/IStreamIn.hal
new file mode 100644
index 0000000..6f1f9df
--- /dev/null
+++ b/audio/2.0/IStreamIn.hal
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ /*
+ * Returns the source descriptor of the input stream. Calling this method is
+ * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+ * HAL.
+ *
+ * @return retval operation completion status.
+ * @return source audio source.
+ */
+ getAudioSource() generates (Result retval, AudioSource source);
+
+ /*
+ * Set the input gain for the audio driver.
+ *
+ * @param gain 1.0f is unity, 0.0f is zero.
+ * @result retval operation completion status.
+ */
+ setGain(float gain) generates (Result retval);
+
+ /*
+ * Commands that can be executed on the driver reader thread.
+ */
+ enum ReadCommand : int32_t {
+ READ,
+ GET_CAPTURE_POSITION
+ };
+
+ /*
+ * Data structure passed to the driver for executing commands
+ * on the driver reader thread.
+ */
+ struct ReadParameters {
+ ReadCommand command; // discriminator
+ union Params {
+ uint64_t read; // READ command, amount of bytes to read, >= 0.
+ // No parameters for GET_CAPTURE_POSITION.
+ } params;
+ };
+
+ /*
+ * Data structure passed back to the client via status message queue
+ * of 'read' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, read operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow reads.
+ */
+ struct ReadStatus {
+ Result retval;
+ ReadCommand replyTo; // discriminator
+ union Reply {
+ uint64_t read; // READ command, amount of bytes read, >= 0.
+ struct CapturePosition { // same as generated by getCapturePosition.
+ uint64_t frames;
+ uint64_t time;
+ } capturePosition;
+ } reply;
+ };
+
+ /*
+ * Set up required transports for receiving audio buffers from the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the reader thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the driver
+ * to the client;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually read or error code).
+ *
+ * The driver operates on a dedicated thread. The client must ensure that
+ * the thread is given an appropriate priority and assigned to correct
+ * scheduler and cgroup. For this purpose, the method returns identifiers
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @param threadPriority priority of the driver thread.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using ReadStatus structures.
+ * @return threadInfo identifiers of the driver's dedicated thread.
+ */
+ prepareForReading(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<ReadParameters> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<ReadStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /*
+ * Return the amount of input frames lost in the audio driver since the last
+ * call of this function.
+ *
+ * Audio driver is expected to reset the value to 0 and restart counting
+ * upon returning the current value by this function call. Such loss
+ * typically occurs when the user space process is blocked longer than the
+ * capacity of audio driver buffers.
+ *
+ * @return framesLost the number of input audio frames lost.
+ */
+ getInputFramesLost() generates (uint32_t framesLost);
+
+ /**
+ * Return a recent count of the number of audio frames received and the
+ * clock time associated with that frame count.
+ *
+ * @return retval INVALID_STATE if the device is not ready/available,
+ * NOT_SUPPORTED if the command is not supported,
+ * OK otherwise.
+ * @return frames the total frame count received. This must be as early in
+ * the capture pipeline as possible. In general, frames
+ * must be non-negative and must not go "backwards".
+ * @return time is the clock monotonic time when frames was measured. In
+ * general, time must be a positive quantity and must not
+ * go "backwards".
+ */
+ getCapturePosition()
+ generates (Result retval, uint64_t frames, uint64_t time);
+};
diff --git a/audio/2.0/IStreamOut.hal b/audio/2.0/IStreamOut.hal
new file mode 100644
index 0000000..9ee32c5
--- /dev/null
+++ b/audio/2.0/IStreamOut.hal
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+ typedef android.hardware.audio@2.0::Result Result;
+
+ /*
+ * Return the audio hardware driver estimated latency in milliseconds.
+ *
+ * @return latencyMs latency in milliseconds.
+ */
+ getLatency() generates (uint32_t latencyMs);
+
+ /*
+ * This method is used in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ *
+ * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+ * @return retval operation completion status.
+ */
+ setVolume(float left, float right) generates (Result retval);
+
+ /*
+ * Commands that can be executed on the driver writer thread.
+ */
+ enum WriteCommand : int32_t {
+ WRITE,
+ GET_PRESENTATION_POSITION,
+ GET_LATENCY
+ };
+
+ /*
+ * Data structure passed back to the client via status message queue
+ * of 'write' operation.
+ *
+ * Possible values of 'retval' field:
+ * - OK, write operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow writes;
+ * - INVALID_OPERATION, retrieving presentation position isn't supported.
+ */
+ struct WriteStatus {
+ Result retval;
+ WriteCommand replyTo; // discriminator
+ union Reply {
+ uint64_t written; // WRITE command, amount of bytes written, >= 0.
+ struct PresentationPosition { // same as generated by
+ uint64_t frames; // getPresentationPosition.
+ TimeSpec timeStamp;
+ } presentationPosition;
+ uint32_t latencyMs; // Same as generated by getLatency.
+ } reply;
+ };
+
+ /*
+ * Set up required transports for passing audio buffers to the driver.
+ *
+ * The transport consists of three message queues:
+ * -- command queue is used to instruct the writer thread what operation
+ * to perform;
+ * -- data queue is used for passing audio data from the client
+ * to the driver;
+ * -- status queue is used for reporting operation status
+ * (e.g. amount of bytes actually written or error code).
+ *
+ * The driver operates on a dedicated thread. The client must ensure that
+ * the thread is given an appropriate priority and assigned to correct
+ * scheduler and cgroup. For this purpose, the method returns identifiers
+ * of the driver thread.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return commandMQ a message queue used for passing commands.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using WriteStatus structures.
+ * @return threadInfo identifiers of the driver's dedicated thread.
+ */
+ prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+ generates (
+ Result retval,
+ fmq_sync<WriteCommand> commandMQ,
+ fmq_sync<uint8_t> dataMQ,
+ fmq_sync<WriteStatus> statusMQ,
+ ThreadInfo threadInfo);
+
+ /*
+ * Return the number of audio frames written by the audio DSP to DAC since
+ * the output has exited standby.
+ *
+ * @return retval operation completion status.
+ * @return dspFrames number of audio frames written.
+ */
+ getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+ /*
+ * Get the local time at which the next write to the audio driver will be
+ * presented. The units are microseconds, where the epoch is decided by the
+ * local audio HAL.
+ *
+ * @return retval operation completion status.
+ * @return timestampUs time of the next write.
+ */
+ getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+ /*
+ * Set the callback interface for notifying completion of non-blocking
+ * write and drain.
+ *
+ * Calling this function implies that all future 'write' and 'drain'
+ * must be non-blocking and use the callback to signal completion.
+ *
+ * 'clearCallback' method needs to be called in order to release the local
+ * callback proxy on the server side and thus dereference the callback
+ * implementation on the client side.
+ *
+ * @return retval operation completion status.
+ */
+ setCallback(IStreamOutCallback callback) generates (Result retval);
+
+ /*
+ * Clears the callback previously set via 'setCallback' method.
+ *
+ * Warning: failure to call this method results in callback implementation
+ * on the client side being held until the HAL server termination.
+ *
+ * @return retval operation completion status: OK or NOT_SUPPORTED.
+ */
+ clearCallback() generates (Result retval);
+
+ /*
+ * Returns whether HAL supports pausing and resuming of streams.
+ *
+ * @return supportsPause true if pausing is supported.
+ * @return supportsResume true if resume is supported.
+ */
+ supportsPauseAndResume()
+ generates (bool supportsPause, bool supportsResume);
+
+ /**
+ * Notifies to the audio driver to stop playback however the queued buffers
+ * are retained by the hardware. Useful for implementing pause/resume. Empty
+ * implementation if not supported however must be implemented for hardware
+ * with non-trivial latency. In the pause state, some audio hardware may
+ * still be using power. Client code may consider calling 'suspend' after a
+ * timeout to prevent that excess power usage.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ pause() generates (Result retval);
+
+ /*
+ * Notifies to the audio driver to resume playback following a pause.
+ * Returns error INVALID_STATE if called without matching pause.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ resume() generates (Result retval);
+
+ /*
+ * Returns whether HAL supports draining of streams.
+ *
+ * @return supports true if draining is supported.
+ */
+ supportsDrain() generates (bool supports);
+
+ /**
+ * Requests notification when data buffered by the driver/hardware has been
+ * played. If 'setCallback' has previously been called to enable
+ * non-blocking mode, then 'drain' must not block, instead it must return
+ * quickly and completion of the drain is notified through the callback. If
+ * 'setCallback' has not been called, then 'drain' must block until
+ * completion.
+ *
+ * If 'type' is 'ALL', the drain completes when all previously written data
+ * has been played.
+ *
+ * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+ * for the current track has played to allow time for the framework to
+ * perform a gapless track switch.
+ *
+ * Drain must return immediately on 'stop' and 'flush' calls.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @param type type of drain.
+ * @return retval operation completion status.
+ */
+ drain(AudioDrain type) generates (Result retval);
+
+ /*
+ * Notifies to the audio driver to flush the queued data. Stream must
+ * already be paused before calling 'flush'.
+ *
+ * Implementation of this function is mandatory for offloaded playback.
+ *
+ * @return retval operation completion status.
+ */
+ flush() generates (Result retval);
+
+ /*
+ * Return a recent count of the number of audio frames presented to an
+ * external observer. This excludes frames which have been written but are
+ * still in the pipeline. The count is not reset to zero when output enters
+ * standby. Also returns the value of CLOCK_MONOTONIC as of this
+ * presentation count. The returned count is expected to be 'recent', but
+ * does not need to be the most recent possible value. However, the
+ * associated time must correspond to whatever count is returned.
+ *
+ * Example: assume that N+M frames have been presented, where M is a 'small'
+ * number. Then it is permissible to return N instead of N+M, and the
+ * timestamp must correspond to N rather than N+M. The terms 'recent' and
+ * 'small' are not defined. They reflect the quality of the implementation.
+ *
+ * @return retval operation completion status.
+ * @return frames count of presented audio frames.
+ * @return timeStamp associated clock time.
+ */
+ getPresentationPosition()
+ generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+};
diff --git a/audio/2.0/IStreamOutCallback.hal b/audio/2.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..cdb38de
--- /dev/null
+++ b/audio/2.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+/*
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+ /*
+ * Non blocking write completed.
+ */
+ oneway onWriteReady();
+
+ /*
+ * Drain completed.
+ */
+ oneway onDrainReady();
+
+ /*
+ * Stream hit an error.
+ */
+ oneway onError();
+};
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk
new file mode 100644
index 0000000..93f7ad0
--- /dev/null
+++ b/audio/2.0/default/Android.mk
@@ -0,0 +1,85 @@
+#
+# Copyright (C) 2016 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio@2.0-impl
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SRC_FILES := \
+ Conversions.cpp \
+ Device.cpp \
+ DevicesFactory.cpp \
+ ParametersUtil.cpp \
+ PrimaryDevice.cpp \
+ Stream.cpp \
+ StreamIn.cpp \
+ StreamOut.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libfmq \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ android.hardware.audio@2.0 \
+ android.hardware.audio.common@2.0 \
+ android.hardware.audio.common@2.0-util \
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+
+include $(BUILD_SHARED_LIBRARY)
+
+#
+# Service
+#
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio@2.0-service
+LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SRC_FILES := \
+ service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ libhardware \
+ android.hardware.audio@2.0 \
+ android.hardware.audio.common@2.0 \
+ android.hardware.audio.effect@2.0 \
+ android.hardware.soundtrigger@2.0 \
+ android.hardware.broadcastradio@1.0 \
+ android.hardware.broadcastradio@1.1
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+ifeq ($(TARGET_USES_BCRADIO_FUTURE_FEATURES),true)
+LOCAL_CFLAGS += -DTARGET_USES_BCRADIO_FUTURE_FEATURES
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/audio/2.0/default/Conversions.cpp b/audio/2.0/default/Conversions.cpp
new file mode 100644
index 0000000..e669185
--- /dev/null
+++ b/audio/2.0/default/Conversions.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <stdio.h>
+
+#include "Conversions.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+std::string deviceAddressToHal(const DeviceAddress& address) {
+ // HAL assumes that the address is NUL-terminated.
+ char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ memset(halAddress, 0, sizeof(halAddress));
+ uint32_t halDevice = static_cast<uint32_t>(address.device);
+ const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
+ if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
+ if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
+ || (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+ snprintf(halAddress, sizeof(halAddress),
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ address.address.mac[0], address.address.mac[1], address.address.mac[2],
+ address.address.mac[3], address.address.mac[4], address.address.mac[5]);
+ } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0)
+ || (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+ snprintf(halAddress, sizeof(halAddress),
+ "%d.%d.%d.%d",
+ address.address.ipv4[0], address.address.ipv4[1],
+ address.address.ipv4[2], address.address.ipv4[3]);
+ } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0)
+ || (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+ snprintf(halAddress, sizeof(halAddress),
+ "card=%d;device=%d",
+ address.address.alsa.card, address.address.alsa.device);
+ } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0)
+ || (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+ snprintf(halAddress, sizeof(halAddress),
+ "%s", address.busAddress.c_str());
+ } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
+ || (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+ snprintf(halAddress, sizeof(halAddress),
+ "%s", address.rSubmixAddress.c_str());
+ }
+ return halAddress;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/Conversions.h b/audio/2.0/default/Conversions.h
new file mode 100644
index 0000000..ebda5c5
--- /dev/null
+++ b/audio/2.0/default/Conversions.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_audio_V2_0_Conversions_H_
+#define android_hardware_audio_V2_0_Conversions_H_
+
+#include <string>
+
+#include <android/hardware/audio/2.0/types.h>
+#include <system/audio.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::V2_0::DeviceAddress;
+
+std::string deviceAddressToHal(const DeviceAddress& address);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_audio_V2_0_Conversions_H_
diff --git a/audio/2.0/default/Device.cpp b/audio/2.0/default/Device.cpp
new file mode 100644
index 0000000..8a51cd7
--- /dev/null
+++ b/audio/2.0/default/Device.cpp
@@ -0,0 +1,297 @@
+ /*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "DeviceHAL"
+//#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <memory.h>
+#include <string.h>
+
+#include <android/log.h>
+
+#include "Conversions.h"
+#include "Device.h"
+#include "HidlUtils.h"
+#include "StreamIn.h"
+#include "StreamOut.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+Device::Device(audio_hw_device_t* device)
+ : mDevice(device) {
+}
+
+Device::~Device() {
+ int status = audio_hw_device_close(mDevice);
+ ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status));
+ mDevice = nullptr;
+}
+
+Result Device::analyzeStatus(const char* funcName, int status) {
+ if (status != 0) {
+ ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status));
+ }
+ switch (status) {
+ case 0: return Result::OK;
+ case -EINVAL: return Result::INVALID_ARGUMENTS;
+ case -ENODATA: return Result::INVALID_STATE;
+ case -ENODEV: return Result::NOT_INITIALIZED;
+ case -ENOSYS: return Result::NOT_SUPPORTED;
+ default: return Result::INVALID_STATE;
+ }
+}
+
+char* Device::halGetParameters(const char* keys) {
+ return mDevice->get_parameters(mDevice, keys);
+}
+
+int Device::halSetParameters(const char* keysAndValues) {
+ return mDevice->set_parameters(mDevice, keysAndValues);
+}
+
+// Methods from ::android::hardware::audio::V2_0::IDevice follow.
+Return<Result> Device::initCheck() {
+ return analyzeStatus("init_check", mDevice->init_check(mDevice));
+}
+
+Return<Result> Device::setMasterVolume(float volume) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (mDevice->set_master_volume != NULL) {
+ retval = analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume));
+ }
+ return retval;
+}
+
+Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ float volume = 0;
+ if (mDevice->get_master_volume != NULL) {
+ retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume));
+ }
+ _hidl_cb(retval, volume);
+ return Void();
+}
+
+Return<Result> Device::setMicMute(bool mute) {
+ return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
+}
+
+Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
+ bool mute = false;
+ Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
+ _hidl_cb(retval, mute);
+ return Void();
+}
+
+Return<Result> Device::setMasterMute(bool mute) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (mDevice->set_master_mute != NULL) {
+ retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute));
+ }
+ return retval;
+}
+
+Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ bool mute = false;
+ if (mDevice->get_master_mute != NULL) {
+ retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute));
+ }
+ _hidl_cb(retval, mute);
+ return Void();
+}
+
+Return<void> Device::getInputBufferSize(
+ const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
+ audio_config_t halConfig;
+ HidlUtils::audioConfigToHal(config, &halConfig);
+ size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
+ Result retval(Result::INVALID_ARGUMENTS);
+ uint64_t bufferSize = 0;
+ if (halBufferSize != 0) {
+ retval = Result::OK;
+ bufferSize = halBufferSize;
+ }
+ _hidl_cb(retval, bufferSize);
+ return Void();
+}
+
+Return<void> Device::openOutputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioOutputFlag flags,
+ openOutputStream_cb _hidl_cb) {
+ audio_config_t halConfig;
+ HidlUtils::audioConfigToHal(config, &halConfig);
+ audio_stream_out_t *halStream;
+ ALOGV("open_output_stream handle: %d devices: %x flags: %#x "
+ "srate: %d format %#x channels %x address %s",
+ ioHandle,
+ static_cast<audio_devices_t>(device.device), static_cast<audio_output_flags_t>(flags),
+ halConfig.sample_rate, halConfig.format, halConfig.channel_mask,
+ deviceAddressToHal(device).c_str());
+ int status = mDevice->open_output_stream(
+ mDevice,
+ ioHandle,
+ static_cast<audio_devices_t>(device.device),
+ static_cast<audio_output_flags_t>(flags),
+ &halConfig,
+ &halStream,
+ deviceAddressToHal(device).c_str());
+ ALOGV("open_output_stream status %d stream %p", status, halStream);
+ sp<IStreamOut> streamOut;
+ if (status == OK) {
+ streamOut = new StreamOut(mDevice, halStream);
+ }
+ AudioConfig suggestedConfig;
+ HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
+ _hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig);
+ return Void();
+}
+
+Return<void> Device::openInputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioInputFlag flags,
+ AudioSource source,
+ openInputStream_cb _hidl_cb) {
+ audio_config_t halConfig;
+ HidlUtils::audioConfigToHal(config, &halConfig);
+ audio_stream_in_t *halStream;
+ ALOGV("open_input_stream handle: %d devices: %x flags: %#x "
+ "srate: %d format %#x channels %x address %s source %d",
+ ioHandle,
+ static_cast<audio_devices_t>(device.device), static_cast<audio_input_flags_t>(flags),
+ halConfig.sample_rate, halConfig.format, halConfig.channel_mask,
+ deviceAddressToHal(device).c_str(), static_cast<audio_source_t>(source));
+ int status = mDevice->open_input_stream(
+ mDevice,
+ ioHandle,
+ static_cast<audio_devices_t>(device.device),
+ &halConfig,
+ &halStream,
+ static_cast<audio_input_flags_t>(flags),
+ deviceAddressToHal(device).c_str(),
+ static_cast<audio_source_t>(source));
+ ALOGV("open_input_stream status %d stream %p", status, halStream);
+ sp<IStreamIn> streamIn;
+ if (status == OK) {
+ streamIn = new StreamIn(mDevice, halStream);
+ }
+ AudioConfig suggestedConfig;
+ HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
+ _hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig);
+ return Void();
+}
+
+Return<bool> Device::supportsAudioPatches() {
+ return version() >= AUDIO_DEVICE_API_VERSION_3_0;
+}
+
+Return<void> Device::createAudioPatch(
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ AudioPatchHandle patch = 0;
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
+ std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
+ audio_patch_handle_t halPatch;
+ retval = analyzeStatus(
+ "create_audio_patch",
+ mDevice->create_audio_patch(
+ mDevice,
+ sources.size(), &halSources[0],
+ sinks.size(), &halSinks[0],
+ &halPatch));
+ if (retval == Result::OK) {
+ patch = static_cast<AudioPatchHandle>(halPatch);
+ }
+ }
+ _hidl_cb(retval, patch);
+ return Void();
+}
+
+Return<Result> Device::releaseAudioPatch(int32_t patch) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ return analyzeStatus(
+ "release_audio_patch",
+ mDevice->release_audio_patch(mDevice, static_cast<audio_patch_handle_t>(patch)));
+ }
+ return Result::NOT_SUPPORTED;
+}
+
+Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+ audio_port halPort;
+ HidlUtils::audioPortToHal(port, &halPort);
+ Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort));
+ AudioPort resultPort = port;
+ if (retval == Result::OK) {
+ HidlUtils::audioPortFromHal(halPort, &resultPort);
+ }
+ _hidl_cb(retval, resultPort);
+ return Void();
+}
+
+Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ struct audio_port_config halPortConfig;
+ HidlUtils::audioPortConfigToHal(config, &halPortConfig);
+ return analyzeStatus(
+ "set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig));
+ }
+ return Result::NOT_SUPPORTED;
+}
+
+Return<AudioHwSync> Device::getHwAvSync() {
+ int halHwAvSync;
+ Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
+ return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID;
+}
+
+Return<Result> Device::setScreenState(bool turnedOn) {
+ return setParam(AudioParameter::keyScreenState, turnedOn);
+}
+
+Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+ getParametersImpl(keys, _hidl_cb);
+ return Void();
+}
+
+Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& parameters) {
+ return setParametersImpl(parameters);
+}
+
+Return<void> Device::debugDump(const hidl_handle& fd) {
+ if (fd->numFds == 1) {
+ analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0]));
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/Device.h b/audio/2.0/default/Device.h
new file mode 100644
index 0000000..46177fc
--- /dev/null
+++ b/audio/2.0/default/Device.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
+
+#include <memory>
+
+#include <media/AudioParameter.h>
+#include <hardware/audio.h>
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "ParametersUtil.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioHwSync;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioPatchHandle;
+using ::android::hardware::audio::common::V2_0::AudioPort;
+using ::android::hardware::audio::common::V2_0::AudioPortConfig;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Device : public IDevice, public ParametersUtil {
+ explicit Device(audio_hw_device_t* device);
+
+ // Methods from ::android::hardware::audio::V2_0::IDevice follow.
+ Return<Result> initCheck() override;
+ Return<Result> setMasterVolume(float volume) override;
+ Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override;
+ Return<Result> setMicMute(bool mute) override;
+ Return<void> getMicMute(getMicMute_cb _hidl_cb) override;
+ Return<Result> setMasterMute(bool mute) override;
+ Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override;
+ Return<void> getInputBufferSize(
+ const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override;
+ Return<void> openOutputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioOutputFlag flags,
+ openOutputStream_cb _hidl_cb) override;
+ Return<void> openInputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioInputFlag flags,
+ AudioSource source,
+ openInputStream_cb _hidl_cb) override;
+ Return<bool> supportsAudioPatches() override;
+ Return<void> createAudioPatch(
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) override;
+ Return<Result> releaseAudioPatch(int32_t patch) override;
+ Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
+ Return<Result> setAudioPortConfig(const AudioPortConfig& config) override;
+ Return<AudioHwSync> getHwAvSync() override;
+ Return<Result> setScreenState(bool turnedOn) override;
+ Return<void> getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
+ Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+
+ // Utility methods for extending interfaces.
+ Result analyzeStatus(const char* funcName, int status);
+ audio_hw_device_t* device() const { return mDevice; }
+
+ private:
+ audio_hw_device_t *mDevice;
+
+ virtual ~Device();
+
+ // Methods from ParametersUtil.
+ char* halGetParameters(const char* keys) override;
+ int halSetParameters(const char* keysAndValues) override;
+
+ uint32_t version() const { return mDevice->common.version; }
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
diff --git a/audio/2.0/default/DevicesFactory.cpp b/audio/2.0/default/DevicesFactory.cpp
new file mode 100644
index 0000000..8825107
--- /dev/null
+++ b/audio/2.0/default/DevicesFactory.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "DevicesFactoryHAL"
+
+#include <string.h>
+
+#include <android/log.h>
+
+#include "Device.h"
+#include "DevicesFactory.h"
+#include "PrimaryDevice.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+// static
+const char* DevicesFactory::deviceToString(IDevicesFactory::Device device) {
+ switch (device) {
+ case IDevicesFactory::Device::PRIMARY: return AUDIO_HARDWARE_MODULE_ID_PRIMARY;
+ case IDevicesFactory::Device::A2DP: return AUDIO_HARDWARE_MODULE_ID_A2DP;
+ case IDevicesFactory::Device::USB: return AUDIO_HARDWARE_MODULE_ID_USB;
+ case IDevicesFactory::Device::R_SUBMIX: return AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX;
+ case IDevicesFactory::Device::STUB: return AUDIO_HARDWARE_MODULE_ID_STUB;
+ }
+}
+
+// static
+int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev)
+{
+ const hw_module_t *mod;
+ int rc;
+
+ rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
+ if (rc) {
+ ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
+ AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+ goto out;
+ }
+ rc = audio_hw_device_open(mod, dev);
+ if (rc) {
+ ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
+ AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+ goto out;
+ }
+ if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
+ ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
+ rc = -EINVAL;
+ audio_hw_device_close(*dev);
+ goto out;
+ }
+ return OK;
+
+out:
+ *dev = NULL;
+ return rc;
+}
+
+// Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow.
+Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
+ audio_hw_device_t *halDevice;
+ int halStatus = loadAudioInterface(deviceToString(device), &halDevice);
+ Result retval(Result::OK);
+ sp<IDevice> result;
+ if (halStatus == OK) {
+ if (device == IDevicesFactory::Device::PRIMARY) {
+ result = new PrimaryDevice(halDevice);
+ } else {
+ result = new ::android::hardware::audio::V2_0::implementation::Device(halDevice);
+ }
+ } else if (halStatus == -EINVAL) {
+ retval = Result::NOT_INITIALIZED;
+ } else {
+ retval = Result::INVALID_ARGUMENTS;
+ }
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
+ return new DevicesFactory();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/DevicesFactory.h b/audio/2.0/default/DevicesFactory.h
new file mode 100644
index 0000000..b046f9f
--- /dev/null
+++ b/audio/2.0/default/DevicesFactory.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
+
+#include <hardware/audio.h>
+
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IDevicesFactory;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct DevicesFactory : public IDevicesFactory {
+ // Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow.
+ Return<void> openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override;
+
+ private:
+ static const char* deviceToString(IDevicesFactory::Device device);
+ static int loadAudioInterface(const char *if_name, audio_hw_device_t **dev);
+
+};
+
+extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
diff --git a/audio/2.0/default/ParametersUtil.cpp b/audio/2.0/default/ParametersUtil.cpp
new file mode 100644
index 0000000..75a60b9
--- /dev/null
+++ b/audio/2.0/default/ParametersUtil.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "ParametersUtil.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+Result ParametersUtil::getParam(const char* name, bool* value) {
+ String8 halValue;
+ Result retval = getParam(name, &halValue);
+ *value = false;
+ if (retval == Result::OK) {
+ *value = !(halValue == AudioParameter::valueOff);
+ }
+ return retval;
+}
+
+Result ParametersUtil::getParam(const char* name, int* value) {
+ const String8 halName(name);
+ AudioParameter keys;
+ keys.addKey(halName);
+ std::unique_ptr<AudioParameter> params = getParams(keys);
+ status_t halStatus = params->getInt(halName, *value);
+ return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS;
+}
+
+Result ParametersUtil::getParam(const char* name, String8* value) {
+ const String8 halName(name);
+ AudioParameter keys;
+ keys.addKey(halName);
+ std::unique_ptr<AudioParameter> params = getParams(keys);
+ status_t halStatus = params->get(halName, *value);
+ return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS;
+}
+
+void ParametersUtil::getParametersImpl(
+ const hidl_vec<hidl_string>& keys,
+ std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb) {
+ AudioParameter halKeys;
+ for (size_t i = 0; i < keys.size(); ++i) {
+ halKeys.addKey(String8(keys[i].c_str()));
+ }
+ std::unique_ptr<AudioParameter> halValues = getParams(halKeys);
+ Result retval(Result::INVALID_ARGUMENTS);
+ hidl_vec<ParameterValue> result;
+ if (halValues->size() > 0) {
+ result.resize(halValues->size());
+ String8 halKey, halValue;
+ for (size_t i = 0; i < halValues->size(); ++i) {
+ status_t status = halValues->getAt(i, halKey, halValue);
+ if (status != OK) {
+ result.resize(0);
+ break;
+ }
+ result[i].key = halKey.string();
+ result[i].value = halValue.string();
+ }
+ if (result.size() != 0) {
+ retval = Result::OK;
+ }
+ }
+ cb(retval, result);
+}
+
+std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) {
+ String8 paramsAndValues;
+ char *halValues = halGetParameters(keys.keysToString().string());
+ if (halValues != NULL) {
+ paramsAndValues.setTo(halValues);
+ free(halValues);
+ } else {
+ paramsAndValues.clear();
+ }
+ return std::unique_ptr<AudioParameter>(new AudioParameter(paramsAndValues));
+}
+
+Result ParametersUtil::setParam(const char* name, bool value) {
+ AudioParameter param;
+ param.add(String8(name), String8(value ? AudioParameter::valueOn : AudioParameter::valueOff));
+ return setParams(param);
+}
+
+Result ParametersUtil::setParam(const char* name, int value) {
+ AudioParameter param;
+ param.addInt(String8(name), value);
+ return setParams(param);
+}
+
+Result ParametersUtil::setParam(const char* name, const char* value) {
+ AudioParameter param;
+ param.add(String8(name), String8(value));
+ return setParams(param);
+}
+
+Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& parameters) {
+ AudioParameter params;
+ for (size_t i = 0; i < parameters.size(); ++i) {
+ params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
+ }
+ return setParams(params);
+}
+
+Result ParametersUtil::setParams(const AudioParameter& param) {
+ int halStatus = halSetParameters(param.toString().string());
+ if (halStatus == OK)
+ return Result::OK;
+ else if (halStatus == -ENOSYS)
+ return Result::INVALID_STATE;
+ else
+ return Result::INVALID_ARGUMENTS;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/ParametersUtil.h b/audio/2.0/default/ParametersUtil.h
new file mode 100644
index 0000000..49036dc
--- /dev/null
+++ b/audio/2.0/default/ParametersUtil.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_audio_V2_0_ParametersUtil_H_
+#define android_hardware_audio_V2_0_ParametersUtil_H_
+
+#include <functional>
+#include <memory>
+
+#include <android/hardware/audio/2.0/types.h>
+#include <hidl/HidlSupport.h>
+#include <media/AudioParameter.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+class ParametersUtil {
+ public:
+ Result getParam(const char* name, bool* value);
+ Result getParam(const char* name, int* value);
+ Result getParam(const char* name, String8* value);
+ void getParametersImpl(
+ const hidl_vec<hidl_string>& keys,
+ std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb);
+ std::unique_ptr<AudioParameter> getParams(const AudioParameter& keys);
+ Result setParam(const char* name, bool value);
+ Result setParam(const char* name, int value);
+ Result setParam(const char* name, const char* value);
+ Result setParametersImpl(const hidl_vec<ParameterValue>& parameters);
+ Result setParams(const AudioParameter& param);
+
+ protected:
+ virtual ~ParametersUtil() {}
+
+ virtual char* halGetParameters(const char* keys) = 0;
+ virtual int halSetParameters(const char* keysAndValues) = 0;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_audio_V2_0_ParametersUtil_H_
diff --git a/audio/2.0/default/PrimaryDevice.cpp b/audio/2.0/default/PrimaryDevice.cpp
new file mode 100644
index 0000000..905203b
--- /dev/null
+++ b/audio/2.0/default/PrimaryDevice.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "PrimaryDeviceHAL"
+
+#include "PrimaryDevice.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+PrimaryDevice::PrimaryDevice(audio_hw_device_t* device)
+ : mDevice(new Device(device)) {
+}
+
+PrimaryDevice::~PrimaryDevice() {}
+
+// Methods from ::android::hardware::audio::V2_0::IDevice follow.
+Return<Result> PrimaryDevice::initCheck() {
+ return mDevice->initCheck();
+}
+
+Return<Result> PrimaryDevice::setMasterVolume(float volume) {
+ return mDevice->setMasterVolume(volume);
+}
+
+Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
+ return mDevice->getMasterVolume(_hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setMicMute(bool mute) {
+ return mDevice->setMicMute(mute);
+}
+
+Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
+ return mDevice->getMicMute(_hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setMasterMute(bool mute) {
+ return mDevice->setMasterMute(mute);
+}
+
+Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
+ return mDevice->getMasterMute(_hidl_cb);
+}
+
+Return<void> PrimaryDevice::getInputBufferSize(
+ const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
+ return mDevice->getInputBufferSize(config, _hidl_cb);
+}
+
+Return<void> PrimaryDevice::openOutputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioOutputFlag flags,
+ openOutputStream_cb _hidl_cb) {
+ return mDevice->openOutputStream(ioHandle, device, config, flags, _hidl_cb);
+}
+
+Return<void> PrimaryDevice::openInputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioInputFlag flags,
+ AudioSource source,
+ openInputStream_cb _hidl_cb) {
+ return mDevice->openInputStream(ioHandle, device, config, flags, source, _hidl_cb);
+}
+
+Return<bool> PrimaryDevice::supportsAudioPatches() {
+ return mDevice->supportsAudioPatches();
+}
+
+Return<void> PrimaryDevice::createAudioPatch(
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) {
+ return mDevice->createAudioPatch(sources, sinks, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
+ return mDevice->releaseAudioPatch(patch);
+}
+
+Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+ return mDevice->getAudioPort(port, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) {
+ return mDevice->setAudioPortConfig(config);
+}
+
+Return<AudioHwSync> PrimaryDevice::getHwAvSync() {
+ return mDevice->getHwAvSync();
+}
+
+Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
+ return mDevice->setScreenState(turnedOn);
+}
+
+Return<void> PrimaryDevice::getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+ return mDevice->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& parameters) {
+ return mDevice->setParameters(parameters);
+}
+
+Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) {
+ return mDevice->debugDump(fd);
+}
+
+
+// Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
+Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
+ return mDevice->analyzeStatus(
+ "set_voice_volume",
+ mDevice->device()->set_voice_volume(mDevice->device(), volume));
+}
+
+Return<Result> PrimaryDevice::setMode(AudioMode mode) {
+ return mDevice->analyzeStatus(
+ "set_mode",
+ mDevice->device()->set_mode(mDevice->device(), static_cast<audio_mode_t>(mode)));
+}
+
+Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) {
+ bool enabled;
+ Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled);
+ _hidl_cb(retval, enabled);
+ return Void();
+}
+
+Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
+ return mDevice->setParam(AudioParameter::keyBtNrec, enabled);
+}
+
+Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) {
+ bool enabled;
+ Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, &enabled);
+ _hidl_cb(retval, enabled);
+ return Void();
+}
+
+Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
+ return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled);
+}
+
+Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
+ int halMode;
+ Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode);
+ TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF;
+ _hidl_cb(retval, mode);
+ return Void();
+}
+
+Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
+ return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, static_cast<int>(mode));
+}
+
+Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
+ bool enabled;
+ Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled);
+ _hidl_cb(retval, enabled);
+ return Void();
+}
+
+Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
+ return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/PrimaryDevice.h b/audio/2.0/default/PrimaryDevice.h
new file mode 100644
index 0000000..d95511b
--- /dev/null
+++ b/audio/2.0/default/PrimaryDevice.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
+
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Device.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioPort;
+using ::android::hardware::audio::common::V2_0::AudioPortConfig;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IPrimaryDevice;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct PrimaryDevice : public IPrimaryDevice {
+ explicit PrimaryDevice(audio_hw_device_t* device);
+
+ // Methods from ::android::hardware::audio::V2_0::IDevice follow.
+ Return<Result> initCheck() override;
+ Return<Result> setMasterVolume(float volume) override;
+ Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override;
+ Return<Result> setMicMute(bool mute) override;
+ Return<void> getMicMute(getMicMute_cb _hidl_cb) override;
+ Return<Result> setMasterMute(bool mute) override;
+ Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override;
+ Return<void> getInputBufferSize(
+ const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override;
+ Return<void> openOutputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioOutputFlag flags,
+ openOutputStream_cb _hidl_cb) override;
+ Return<void> openInputStream(
+ int32_t ioHandle,
+ const DeviceAddress& device,
+ const AudioConfig& config,
+ AudioInputFlag flags,
+ AudioSource source,
+ openInputStream_cb _hidl_cb) override;
+ Return<bool> supportsAudioPatches() override;
+ Return<void> createAudioPatch(
+ const hidl_vec<AudioPortConfig>& sources,
+ const hidl_vec<AudioPortConfig>& sinks,
+ createAudioPatch_cb _hidl_cb) override;
+ Return<Result> releaseAudioPatch(int32_t patch) override;
+ Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
+ Return<Result> setAudioPortConfig(const AudioPortConfig& config) override;
+ Return<AudioHwSync> getHwAvSync() override;
+ Return<Result> setScreenState(bool turnedOn) override;
+ Return<void> getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
+ Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+
+ // Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
+ Return<Result> setVoiceVolume(float volume) override;
+ Return<Result> setMode(AudioMode mode) override;
+ Return<void> getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override;
+ Return<Result> setBtScoNrecEnabled(bool enabled) override;
+ Return<void> getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) override;
+ Return<Result> setBtScoWidebandEnabled(bool enabled) override;
+ Return<void> getTtyMode(getTtyMode_cb _hidl_cb) override;
+ Return<Result> setTtyMode(IPrimaryDevice::TtyMode mode) override;
+ Return<void> getHacEnabled(getHacEnabled_cb _hidl_cb) override;
+ Return<Result> setHacEnabled(bool enabled) override;
+
+ private:
+ sp<Device> mDevice;
+
+ virtual ~PrimaryDevice();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp
new file mode 100644
index 0000000..29946fe
--- /dev/null
+++ b/audio/2.0/default/Stream.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <inttypes.h>
+
+#define LOG_TAG "StreamHAL"
+
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include <media/TypeConverter.h>
+#include <android/log.h>
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+#include "Conversions.h"
+#include "EffectMap.h"
+#include "Stream.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+Stream::Stream(audio_stream_t* stream)
+ : mStream(stream) {
+}
+
+Stream::~Stream() {
+ mStream = nullptr;
+}
+
+// static
+Result Stream::analyzeStatus(const char* funcName, int status, int ignoreError, int ignoreError2) {
+ if (status != 0 && status != -ignoreError && status != -ignoreError2) {
+ ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status));
+ }
+ switch (status) {
+ case 0: return Result::OK;
+ case -EINVAL: return Result::INVALID_ARGUMENTS;
+ case -ENODATA: return Result::INVALID_STATE;
+ case -ENODEV: return Result::NOT_INITIALIZED;
+ case -ENOSYS: return Result::NOT_SUPPORTED;
+ default: return Result::INVALID_STATE;
+ }
+}
+
+char* Stream::halGetParameters(const char* keys) {
+ return mStream->get_parameters(mStream, keys);
+}
+
+int Stream::halSetParameters(const char* keysAndValues) {
+ return mStream->set_parameters(mStream, keysAndValues);
+}
+
+// Methods from ::android::hardware::audio::V2_0::IStream follow.
+Return<uint64_t> Stream::getFrameSize() {
+ // Needs to be implemented by interface subclasses. But can't be declared as pure virtual,
+ // since interface subclasses implementation do not inherit from this class.
+ LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract");
+ return uint64_t {};
+}
+
+Return<uint64_t> Stream::getFrameCount() {
+ int halFrameCount;
+ Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount);
+ return retval == Result::OK ? halFrameCount : 0;
+}
+
+Return<uint64_t> Stream::getBufferSize() {
+ return mStream->get_buffer_size(mStream);
+}
+
+Return<uint32_t> Stream::getSampleRate() {
+ return mStream->get_sample_rate(mStream);
+}
+
+Return<void> Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+ String8 halListValue;
+ Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue);
+ hidl_vec<uint32_t> sampleRates;
+ SortedVector<uint32_t> halSampleRates;
+ if (result == Result::OK) {
+ halSampleRates = samplingRatesFromString(
+ halListValue.string(), AudioParameter::valueListSeparator);
+ sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
+ }
+ _hidl_cb(sampleRates);
+ return Void();
+}
+
+Return<Result> Stream::setSampleRate(uint32_t sampleRateHz) {
+ return setParam(AudioParameter::keySamplingRate, static_cast<int>(sampleRateHz));
+}
+
+Return<AudioChannelMask> Stream::getChannelMask() {
+ return AudioChannelMask(mStream->get_channels(mStream));
+}
+
+Return<void> Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+ String8 halListValue;
+ Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue);
+ hidl_vec<AudioChannelMask> channelMasks;
+ SortedVector<audio_channel_mask_t> halChannelMasks;
+ if (result == Result::OK) {
+ halChannelMasks = channelMasksFromString(
+ halListValue.string(), AudioParameter::valueListSeparator);
+ channelMasks.resize(halChannelMasks.size());
+ for (size_t i = 0; i < halChannelMasks.size(); ++i) {
+ channelMasks[i] = AudioChannelMask(halChannelMasks[i]);
+ }
+ }
+ _hidl_cb(channelMasks);
+ return Void();
+}
+
+Return<Result> Stream::setChannelMask(AudioChannelMask mask) {
+ return setParam(AudioParameter::keyChannels, static_cast<int>(mask));
+}
+
+Return<AudioFormat> Stream::getFormat() {
+ return AudioFormat(mStream->get_format(mStream));
+}
+
+Return<void> Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+ String8 halListValue;
+ Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
+ hidl_vec<AudioFormat> formats;
+ Vector<audio_format_t> halFormats;
+ if (result == Result::OK) {
+ halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
+ formats.resize(halFormats.size());
+ for (size_t i = 0; i < halFormats.size(); ++i) {
+ formats[i] = AudioFormat(halFormats[i]);
+ }
+ }
+ _hidl_cb(formats);
+ return Void();
+}
+
+Return<Result> Stream::setFormat(AudioFormat format) {
+ return setParam(AudioParameter::keyFormat, static_cast<int>(format));
+}
+
+Return<void> Stream::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+ uint32_t halSampleRate = mStream->get_sample_rate(mStream);
+ audio_channel_mask_t halMask = mStream->get_channels(mStream);
+ audio_format_t halFormat = mStream->get_format(mStream);
+ _hidl_cb(halSampleRate, AudioChannelMask(halMask), AudioFormat(halFormat));
+ return Void();
+}
+
+Return<Result> Stream::addEffect(uint64_t effectId) {
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect));
+ } else {
+ ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<Result> Stream::removeEffect(uint64_t effectId) {
+ effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+ if (halEffect != NULL) {
+ return analyzeStatus(
+ "remove_audio_effect", mStream->remove_audio_effect(mStream, halEffect));
+ } else {
+ ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
+ return Result::INVALID_ARGUMENTS;
+ }
+}
+
+Return<Result> Stream::standby() {
+ return analyzeStatus("standby", mStream->standby(mStream));
+}
+
+Return<AudioDevice> Stream::getDevice() {
+ int device;
+ Result retval = getParam(AudioParameter::keyRouting, &device);
+ return retval == Result::OK ? static_cast<AudioDevice>(device) : AudioDevice::NONE;
+}
+
+Return<Result> Stream::setDevice(const DeviceAddress& address) {
+ char* halDeviceAddress =
+ audio_device_address_to_parameter(
+ static_cast<audio_devices_t>(address.device),
+ deviceAddressToHal(address).c_str());
+ AudioParameter params((String8(halDeviceAddress)));
+ free(halDeviceAddress);
+ params.addInt(
+ String8(AudioParameter::keyRouting), static_cast<audio_devices_t>(address.device));
+ return setParams(params);
+}
+
+Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected) {
+ return setParam(
+ connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect,
+ deviceAddressToHal(address).c_str());
+}
+
+Return<Result> Stream::setHwAvSync(uint32_t hwAvSync) {
+ return setParam(AudioParameter::keyStreamHwAvSync, static_cast<int>(hwAvSync));
+}
+
+Return<void> Stream::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+ getParametersImpl(keys, _hidl_cb);
+ return Void();
+}
+
+Return<Result> Stream::setParameters(const hidl_vec<ParameterValue>& parameters) {
+ return setParametersImpl(parameters);
+}
+
+Return<void> Stream::debugDump(const hidl_handle& fd) {
+ if (fd->numFds == 1) {
+ analyzeStatus("dump", mStream->dump(mStream, fd->data[0]));
+ }
+ return Void();
+}
+
+Return<Result> Stream::start() {
+ return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Stream::stop() {
+ return Result::NOT_SUPPORTED;
+}
+
+Return<void> Stream::createMmapBuffer(int32_t minSizeFrames __unused,
+ createMmapBuffer_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ MmapBufferInfo info;
+ _hidl_cb(retval, info);
+ return Void();
+}
+
+Return<void> Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ MmapPosition position;
+ _hidl_cb(retval, position);
+ return Void();
+}
+
+Return<Result> Stream::close() {
+ return Result::NOT_SUPPORTED;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
new file mode 100644
index 0000000..b49e658
--- /dev/null
+++ b/audio/2.0/default/Stream.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
+
+#include <android/hardware/audio/2.0/IStream.h>
+#include <hardware/audio.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "ParametersUtil.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Stream : public IStream, public ParametersUtil {
+ explicit Stream(audio_stream_t* stream);
+
+ // Methods from ::android::hardware::audio::V2_0::IStream follow.
+ Return<uint64_t> getFrameSize() override;
+ Return<uint64_t> getFrameCount() override;
+ Return<uint64_t> getBufferSize() override;
+ Return<uint32_t> getSampleRate() override;
+ Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+ Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+ Return<AudioChannelMask> getChannelMask() override;
+ Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+ Return<Result> setChannelMask(AudioChannelMask mask) override;
+ Return<AudioFormat> getFormat() override;
+ Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+ Return<Result> setFormat(AudioFormat format) override;
+ Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+ Return<Result> addEffect(uint64_t effectId) override;
+ Return<Result> removeEffect(uint64_t effectId) override;
+ Return<Result> standby() override;
+ Return<AudioDevice> getDevice() override;
+ Return<Result> setDevice(const DeviceAddress& address) override;
+ Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+ Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+ Return<void> getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
+ Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+ Return<Result> start() override;
+ Return<Result> stop() override;
+ Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+ Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+ Return<Result> close() override;
+
+ // Utility methods for extending interfaces.
+ static Result analyzeStatus(
+ const char* funcName, int status, int ignoreError = OK, int ignoreError2 = OK);
+
+ private:
+ audio_stream_t *mStream;
+
+ virtual ~Stream();
+
+ // Methods from ParametersUtil.
+ char* halGetParameters(const char* keys) override;
+ int halSetParameters(const char* keysAndValues) override;
+};
+
+
+template <typename T>
+struct StreamMmap : public RefBase {
+ explicit StreamMmap(T* stream) : mStream(stream) {}
+
+ Return<Result> start();
+ Return<Result> stop();
+ Return<void> createMmapBuffer(
+ int32_t minSizeFrames, size_t frameSize, IStream::createMmapBuffer_cb _hidl_cb);
+ Return<void> getMmapPosition(IStream::getMmapPosition_cb _hidl_cb);
+
+ private:
+ StreamMmap() {}
+
+ T *mStream;
+};
+
+template <typename T>
+Return<Result> StreamMmap<T>::start() {
+ if (mStream->start == NULL) return Result::NOT_SUPPORTED;
+ int result = mStream->start(mStream);
+ return Stream::analyzeStatus("start", result);
+}
+
+template <typename T>
+Return<Result> StreamMmap<T>::stop() {
+ if (mStream->stop == NULL) return Result::NOT_SUPPORTED;
+ int result = mStream->stop(mStream);
+ return Stream::analyzeStatus("stop", result);
+}
+
+template <typename T>
+Return<void> StreamMmap<T>::createMmapBuffer(int32_t minSizeFrames, size_t frameSize,
+ IStream::createMmapBuffer_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ MmapBufferInfo info;
+ native_handle_t* hidlHandle = nullptr;
+
+ if (mStream->create_mmap_buffer != NULL) {
+ struct audio_mmap_buffer_info halInfo;
+ retval = Stream::analyzeStatus(
+ "create_mmap_buffer",
+ mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo));
+ if (retval == Result::OK) {
+ hidlHandle = native_handle_create(1, 0);
+ hidlHandle->data[0] = halInfo.shared_memory_fd;
+ info.sharedMemory = hidl_memory("audio_buffer", hidlHandle,
+ frameSize *halInfo.buffer_size_frames);
+ info.bufferSizeFrames = halInfo.buffer_size_frames;
+ info.burstSizeFrames = halInfo.burst_size_frames;
+ }
+ }
+ _hidl_cb(retval, info);
+ if (hidlHandle != nullptr) {
+ native_handle_delete(hidlHandle);
+ }
+ return Void();
+}
+
+template <typename T>
+Return<void> StreamMmap<T>::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ MmapPosition position;
+
+ if (mStream->get_mmap_position != NULL) {
+ struct audio_mmap_position halPosition;
+ retval = Stream::analyzeStatus(
+ "get_mmap_position",
+ mStream->get_mmap_position(mStream, &halPosition));
+ if (retval == Result::OK) {
+ position.timeNanoseconds = halPosition.time_nanoseconds;
+ position.positionFrames = halPosition.position_frames;
+ }
+ }
+ _hidl_cb(retval, position);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
new file mode 100644
index 0000000..b641e82
--- /dev/null
+++ b/audio/2.0/default/StreamIn.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "StreamInHAL"
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <android/log.h>
+#include <hardware/audio.h>
+#include <utils/Trace.h>
+
+#include "StreamIn.h"
+
+using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
+
+namespace {
+
+class ReadThread : public Thread {
+ public:
+ // ReadThread's lifespan never exceeds StreamIn's lifespan.
+ ReadThread(std::atomic<bool>* stop,
+ audio_stream_in_t* stream,
+ StreamIn::CommandMQ* commandMQ,
+ StreamIn::DataMQ* dataMQ,
+ StreamIn::StatusMQ* statusMQ,
+ EventFlag* efGroup)
+ : Thread(false /*canCallJava*/),
+ mStop(stop),
+ mStream(stream),
+ mCommandMQ(commandMQ),
+ mDataMQ(dataMQ),
+ mStatusMQ(statusMQ),
+ mEfGroup(efGroup),
+ mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+ }
+ virtual ~ReadThread() {}
+
+ private:
+ std::atomic<bool>* mStop;
+ audio_stream_in_t* mStream;
+ StreamIn::CommandMQ* mCommandMQ;
+ StreamIn::DataMQ* mDataMQ;
+ StreamIn::StatusMQ* mStatusMQ;
+ EventFlag* mEfGroup;
+ std::unique_ptr<uint8_t[]> mBuffer;
+ IStreamIn::ReadParameters mParameters;
+ IStreamIn::ReadStatus mStatus;
+
+ bool threadLoop() override;
+
+ void doGetCapturePosition();
+ void doRead();
+};
+
+void ReadThread::doRead() {
+ size_t availableToWrite = mDataMQ->availableToWrite();
+ size_t requestedToRead = mParameters.params.read;
+ if (requestedToRead > availableToWrite) {
+ ALOGW("truncating read data from %d to %d due to insufficient data queue space",
+ (int32_t)requestedToRead, (int32_t)availableToWrite);
+ requestedToRead = availableToWrite;
+ }
+ ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
+ mStatus.retval = Result::OK;
+ uint64_t read = 0;
+ if (readResult >= 0) {
+ mStatus.reply.read = readResult;
+ if (!mDataMQ->write(&mBuffer[0], readResult)) {
+ ALOGW("data message queue write failed");
+ }
+ } else {
+ mStatus.retval = Stream::analyzeStatus("read", readResult);
+ }
+}
+
+void ReadThread::doGetCapturePosition() {
+ mStatus.retval = StreamIn::getCapturePositionImpl(
+ mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
+}
+
+bool ReadThread::threadLoop() {
+ // This implementation doesn't return control back to the Thread until it decides to stop,
+ // as the Thread uses mutexes, and this can lead to priority inversion.
+ while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+ uint32_t efState = 0;
+ mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
+ if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
+ continue; // Nothing to do.
+ }
+ if (!mCommandMQ->read(&mParameters)) {
+ continue; // Nothing to do.
+ }
+ mStatus.replyTo = mParameters.command;
+ switch (mParameters.command) {
+ case IStreamIn::ReadCommand::READ:
+ doRead();
+ break;
+ case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
+ doGetCapturePosition();
+ break;
+ default:
+ ALOGE("Unknown read thread command code %d", mParameters.command);
+ mStatus.retval = Result::NOT_SUPPORTED;
+ break;
+ }
+ if (!mStatusMQ->write(&mStatus)) {
+ ALOGW("status message queue write failed");
+ }
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+ }
+
+ return false;
+}
+
+} // namespace
+
+StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
+ : mIsClosed(false), mDevice(device), mStream(stream),
+ mStreamCommon(new Stream(&stream->common)),
+ mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
+ mEfGroup(nullptr), mStopReadThread(false) {
+}
+
+StreamIn::~StreamIn() {
+ ATRACE_CALL();
+ close();
+ if (mReadThread.get()) {
+ ATRACE_NAME("mReadThread->join");
+ status_t status = mReadThread->join();
+ ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
+ }
+ if (mEfGroup) {
+ status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+ ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
+ }
+ mDevice->close_input_stream(mDevice, mStream);
+ mStream = nullptr;
+ mDevice = nullptr;
+}
+
+// Methods from ::android::hardware::audio::V2_0::IStream follow.
+Return<uint64_t> StreamIn::getFrameSize() {
+ return audio_stream_in_frame_size(mStream);
+}
+
+Return<uint64_t> StreamIn::getFrameCount() {
+ return mStreamCommon->getFrameCount();
+}
+
+Return<uint64_t> StreamIn::getBufferSize() {
+ return mStreamCommon->getBufferSize();
+}
+
+Return<uint32_t> StreamIn::getSampleRate() {
+ return mStreamCommon->getSampleRate();
+}
+
+Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+ return mStreamCommon->getSupportedSampleRates(_hidl_cb);
+}
+
+Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
+ return mStreamCommon->setSampleRate(sampleRateHz);
+}
+
+Return<AudioChannelMask> StreamIn::getChannelMask() {
+ return mStreamCommon->getChannelMask();
+}
+
+Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+ return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
+}
+
+Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
+ return mStreamCommon->setChannelMask(mask);
+}
+
+Return<AudioFormat> StreamIn::getFormat() {
+ return mStreamCommon->getFormat();
+}
+
+Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+ return mStreamCommon->getSupportedFormats(_hidl_cb);
+}
+
+Return<Result> StreamIn::setFormat(AudioFormat format) {
+ return mStreamCommon->setFormat(format);
+}
+
+Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+ return mStreamCommon->getAudioProperties(_hidl_cb);
+}
+
+Return<Result> StreamIn::addEffect(uint64_t effectId) {
+ return mStreamCommon->addEffect(effectId);
+}
+
+Return<Result> StreamIn::removeEffect(uint64_t effectId) {
+ return mStreamCommon->removeEffect(effectId);
+}
+
+Return<Result> StreamIn::standby() {
+ return mStreamCommon->standby();
+}
+
+Return<AudioDevice> StreamIn::getDevice() {
+ return mStreamCommon->getDevice();
+}
+
+Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
+ return mStreamCommon->setDevice(address);
+}
+
+Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
+ return mStreamCommon->setConnectedState(address, connected);
+}
+
+Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
+ return mStreamCommon->setHwAvSync(hwAvSync);
+}
+
+Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+ return mStreamCommon->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
+ return mStreamCommon->setParameters(parameters);
+}
+
+Return<void> StreamIn::debugDump(const hidl_handle& fd) {
+ return mStreamCommon->debugDump(fd);
+}
+
+Return<Result> StreamIn::start() {
+ return mStreamMmap->start();
+}
+
+Return<Result> StreamIn::stop() {
+ return mStreamMmap->stop();
+}
+
+Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
+ return mStreamMmap->createMmapBuffer(
+ minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
+}
+
+Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+ return mStreamMmap->getMmapPosition(_hidl_cb);
+}
+
+Return<Result> StreamIn::close() {
+ if (mIsClosed) return Result::INVALID_STATE;
+ mIsClosed = true;
+ if (mReadThread.get()) {
+ mStopReadThread.store(true, std::memory_order_release);
+ }
+ if (mEfGroup) {
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+ }
+ return Result::OK;
+}
+
+// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
+Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
+ int halSource;
+ Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
+ AudioSource source(AudioSource::DEFAULT);
+ if (retval == Result::OK) {
+ source = AudioSource(halSource);
+ }
+ _hidl_cb(retval, source);
+ return Void();
+}
+
+Return<Result> StreamIn::setGain(float gain) {
+ return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
+}
+
+Return<void> StreamIn::prepareForReading(
+ uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) {
+ status_t status;
+ ThreadInfo threadInfo = { 0, 0 };
+ // Create message queues.
+ if (mDataMQ) {
+ ALOGE("the client attempts to call prepareForReading twice");
+ _hidl_cb(Result::INVALID_STATE,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+ std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(frameSize * framesCount, true /* EventFlag */));
+ std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+ if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+ ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
+ ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+ ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+ status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+ if (status != OK || !mEfGroup) {
+ ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+
+ // Create and launch the thread.
+ mReadThread = new ReadThread(
+ &mStopReadThread,
+ mStream,
+ tempCommandMQ.get(),
+ tempDataMQ.get(),
+ tempStatusMQ.get(),
+ mEfGroup);
+ status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
+ if (status != OK) {
+ ALOGW("failed to start reader thread: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+
+ mCommandMQ = std::move(tempCommandMQ);
+ mDataMQ = std::move(tempDataMQ);
+ mStatusMQ = std::move(tempStatusMQ);
+ threadInfo.pid = getpid();
+ threadInfo.tid = mReadThread->getTid();
+ _hidl_cb(Result::OK,
+ *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
+ threadInfo);
+ return Void();
+}
+
+Return<uint32_t> StreamIn::getInputFramesLost() {
+ return mStream->get_input_frames_lost(mStream);
+}
+
+// static
+Result StreamIn::getCapturePositionImpl(
+ audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (stream->get_capture_position != NULL) return retval;
+ int64_t halFrames, halTime;
+ retval = Stream::analyzeStatus(
+ "get_capture_position",
+ stream->get_capture_position(stream, &halFrames, &halTime),
+ // HAL may have a stub function, always returning ENOSYS, don't
+ // spam the log in this case.
+ ENOSYS);
+ if (retval == Result::OK) {
+ *frames = halFrames;
+ *time = halTime;
+ }
+ return retval;
+};
+
+Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
+ uint64_t frames = 0, time = 0;
+ Result retval = getCapturePositionImpl(mStream, &frames, &time);
+ _hidl_cb(retval, frames, time);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h
new file mode 100644
index 0000000..b867387
--- /dev/null
+++ b/audio/2.0/default/StreamIn.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
+
+#include <atomic>
+#include <memory>
+
+#include <android/hardware/audio/2.0/IStreamIn.h>
+#include <hidl/MQDescriptor.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
+
+#include "Stream.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct StreamIn : public IStreamIn {
+ typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ;
+ typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+ typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ;
+
+ StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream);
+
+ // Methods from ::android::hardware::audio::V2_0::IStream follow.
+ Return<uint64_t> getFrameSize() override;
+ Return<uint64_t> getFrameCount() override;
+ Return<uint64_t> getBufferSize() override;
+ Return<uint32_t> getSampleRate() override;
+ Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+ Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+ Return<AudioChannelMask> getChannelMask() override;
+ Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+ Return<Result> setChannelMask(AudioChannelMask mask) override;
+ Return<AudioFormat> getFormat() override;
+ Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+ Return<Result> setFormat(AudioFormat format) override;
+ Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+ Return<Result> addEffect(uint64_t effectId) override;
+ Return<Result> removeEffect(uint64_t effectId) override;
+ Return<Result> standby() override;
+ Return<AudioDevice> getDevice() override;
+ Return<Result> setDevice(const DeviceAddress& address) override;
+ Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+ Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+ Return<void> getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
+ Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
+ Return<void> getAudioSource(getAudioSource_cb _hidl_cb) override;
+ Return<Result> setGain(float gain) override;
+ Return<void> prepareForReading(
+ uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) override;
+ Return<uint32_t> getInputFramesLost() override;
+ Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb) override;
+ Return<Result> start() override;
+ Return<Result> stop() override;
+ Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+ Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+
+ static Result getCapturePositionImpl(
+ audio_stream_in_t *stream, uint64_t *frames, uint64_t *time);
+
+ private:
+ bool mIsClosed;
+ audio_hw_device_t *mDevice;
+ audio_stream_in_t *mStream;
+ sp<Stream> mStreamCommon;
+ sp<StreamMmap<audio_stream_in_t>> mStreamMmap;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<DataMQ> mDataMQ;
+ std::unique_ptr<StatusMQ> mStatusMQ;
+ EventFlag* mEfGroup;
+ std::atomic<bool> mStopReadThread;
+ sp<Thread> mReadThread;
+
+ virtual ~StreamIn();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
new file mode 100644
index 0000000..d820f3c
--- /dev/null
+++ b/audio/2.0/default/StreamOut.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "StreamOutHAL"
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <android/log.h>
+#include <hardware/audio.h>
+#include <utils/Trace.h>
+
+#include "StreamOut.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
+
+namespace {
+
+class WriteThread : public Thread {
+ public:
+ // WriteThread's lifespan never exceeds StreamOut's lifespan.
+ WriteThread(std::atomic<bool>* stop,
+ audio_stream_out_t* stream,
+ StreamOut::CommandMQ* commandMQ,
+ StreamOut::DataMQ* dataMQ,
+ StreamOut::StatusMQ* statusMQ,
+ EventFlag* efGroup)
+ : Thread(false /*canCallJava*/),
+ mStop(stop),
+ mStream(stream),
+ mCommandMQ(commandMQ),
+ mDataMQ(dataMQ),
+ mStatusMQ(statusMQ),
+ mEfGroup(efGroup),
+ mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+ }
+ virtual ~WriteThread() {}
+
+ private:
+ std::atomic<bool>* mStop;
+ audio_stream_out_t* mStream;
+ StreamOut::CommandMQ* mCommandMQ;
+ StreamOut::DataMQ* mDataMQ;
+ StreamOut::StatusMQ* mStatusMQ;
+ EventFlag* mEfGroup;
+ std::unique_ptr<uint8_t[]> mBuffer;
+ IStreamOut::WriteStatus mStatus;
+
+ bool threadLoop() override;
+
+ void doGetLatency();
+ void doGetPresentationPosition();
+ void doWrite();
+};
+
+void WriteThread::doWrite() {
+ const size_t availToRead = mDataMQ->availableToRead();
+ mStatus.retval = Result::OK;
+ mStatus.reply.written = 0;
+ if (mDataMQ->read(&mBuffer[0], availToRead)) {
+ ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
+ if (writeResult >= 0) {
+ mStatus.reply.written = writeResult;
+ } else {
+ mStatus.retval = Stream::analyzeStatus("write", writeResult);
+ }
+ }
+}
+
+void WriteThread::doGetPresentationPosition() {
+ mStatus.retval = StreamOut::getPresentationPositionImpl(
+ mStream,
+ &mStatus.reply.presentationPosition.frames,
+ &mStatus.reply.presentationPosition.timeStamp);
+}
+
+void WriteThread::doGetLatency() {
+ mStatus.retval = Result::OK;
+ mStatus.reply.latencyMs = mStream->get_latency(mStream);
+}
+
+bool WriteThread::threadLoop() {
+ // This implementation doesn't return control back to the Thread until it decides to stop,
+ // as the Thread uses mutexes, and this can lead to priority inversion.
+ while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+ uint32_t efState = 0;
+ mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
+ if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
+ continue; // Nothing to do.
+ }
+ if (!mCommandMQ->read(&mStatus.replyTo)) {
+ continue; // Nothing to do.
+ }
+ switch (mStatus.replyTo) {
+ case IStreamOut::WriteCommand::WRITE:
+ doWrite();
+ break;
+ case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
+ doGetPresentationPosition();
+ break;
+ case IStreamOut::WriteCommand::GET_LATENCY:
+ doGetLatency();
+ break;
+ default:
+ ALOGE("Unknown write thread command code %d", mStatus.replyTo);
+ mStatus.retval = Result::NOT_SUPPORTED;
+ break;
+ }
+ if (!mStatusMQ->write(&mStatus)) {
+ ALOGE("status message queue write failed");
+ }
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+ }
+
+ return false;
+}
+
+} // namespace
+
+StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream)
+ : mIsClosed(false), mDevice(device), mStream(stream),
+ mStreamCommon(new Stream(&stream->common)),
+ mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
+ mEfGroup(nullptr), mStopWriteThread(false) {
+}
+
+StreamOut::~StreamOut() {
+ ATRACE_CALL();
+ close();
+ if (mWriteThread.get()) {
+ ATRACE_NAME("mWriteThread->join");
+ status_t status = mWriteThread->join();
+ ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
+ }
+ if (mEfGroup) {
+ status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+ ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
+ }
+ mCallback.clear();
+ mDevice->close_output_stream(mDevice, mStream);
+ mStream = nullptr;
+ mDevice = nullptr;
+}
+
+// Methods from ::android::hardware::audio::V2_0::IStream follow.
+Return<uint64_t> StreamOut::getFrameSize() {
+ return audio_stream_out_frame_size(mStream);
+}
+
+Return<uint64_t> StreamOut::getFrameCount() {
+ return mStreamCommon->getFrameCount();
+}
+
+Return<uint64_t> StreamOut::getBufferSize() {
+ return mStreamCommon->getBufferSize();
+}
+
+Return<uint32_t> StreamOut::getSampleRate() {
+ return mStreamCommon->getSampleRate();
+}
+
+Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+ return mStreamCommon->getSupportedSampleRates(_hidl_cb);
+}
+
+Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
+ return mStreamCommon->setSampleRate(sampleRateHz);
+}
+
+Return<AudioChannelMask> StreamOut::getChannelMask() {
+ return mStreamCommon->getChannelMask();
+}
+
+Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+ return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
+}
+
+Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
+ return mStreamCommon->setChannelMask(mask);
+}
+
+Return<AudioFormat> StreamOut::getFormat() {
+ return mStreamCommon->getFormat();
+}
+
+Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+ return mStreamCommon->getSupportedFormats(_hidl_cb);
+}
+
+Return<Result> StreamOut::setFormat(AudioFormat format) {
+ return mStreamCommon->setFormat(format);
+}
+
+Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+ return mStreamCommon->getAudioProperties(_hidl_cb);
+}
+
+Return<Result> StreamOut::addEffect(uint64_t effectId) {
+ return mStreamCommon->addEffect(effectId);
+}
+
+Return<Result> StreamOut::removeEffect(uint64_t effectId) {
+ return mStreamCommon->removeEffect(effectId);
+}
+
+Return<Result> StreamOut::standby() {
+ return mStreamCommon->standby();
+}
+
+Return<AudioDevice> StreamOut::getDevice() {
+ return mStreamCommon->getDevice();
+}
+
+Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
+ return mStreamCommon->setDevice(address);
+}
+
+Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
+ return mStreamCommon->setConnectedState(address, connected);
+}
+
+Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
+ return mStreamCommon->setHwAvSync(hwAvSync);
+}
+
+Return<void> StreamOut::getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+ return mStreamCommon->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
+ return mStreamCommon->setParameters(parameters);
+}
+
+Return<void> StreamOut::debugDump(const hidl_handle& fd) {
+ return mStreamCommon->debugDump(fd);
+}
+
+Return<Result> StreamOut::close() {
+ if (mIsClosed) return Result::INVALID_STATE;
+ mIsClosed = true;
+ if (mWriteThread.get()) {
+ mStopWriteThread.store(true, std::memory_order_release);
+ }
+ if (mEfGroup) {
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+ }
+ return Result::OK;
+}
+
+// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
+Return<uint32_t> StreamOut::getLatency() {
+ return mStream->get_latency(mStream);
+}
+
+Return<Result> StreamOut::setVolume(float left, float right) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (mStream->set_volume != NULL) {
+ retval = Stream::analyzeStatus(
+ "set_volume", mStream->set_volume(mStream, left, right));
+ }
+ return retval;
+}
+
+Return<void> StreamOut::prepareForWriting(
+ uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) {
+ status_t status;
+ ThreadInfo threadInfo = { 0, 0 };
+ // Create message queues.
+ if (mDataMQ) {
+ ALOGE("the client attempts to call prepareForWriting twice");
+ _hidl_cb(Result::INVALID_STATE,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+ std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(frameSize * framesCount, true /* EventFlag */));
+ std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+ if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+ ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
+ ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+ ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+ status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+ if (status != OK || !mEfGroup) {
+ ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+
+ // Create and launch the thread.
+ mWriteThread = new WriteThread(
+ &mStopWriteThread,
+ mStream,
+ tempCommandMQ.get(),
+ tempDataMQ.get(),
+ tempStatusMQ.get(),
+ mEfGroup);
+ status = mWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
+ if (status != OK) {
+ ALOGW("failed to start writer thread: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo);
+ return Void();
+ }
+
+ mCommandMQ = std::move(tempCommandMQ);
+ mDataMQ = std::move(tempDataMQ);
+ mStatusMQ = std::move(tempStatusMQ);
+ threadInfo.pid = getpid();
+ threadInfo.tid = mWriteThread->getTid();
+ _hidl_cb(Result::OK,
+ *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
+ threadInfo);
+ return Void();
+}
+
+Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
+ uint32_t halDspFrames;
+ Result retval = Stream::analyzeStatus(
+ "get_render_position", mStream->get_render_position(mStream, &halDspFrames));
+ _hidl_cb(retval, halDspFrames);
+ return Void();
+}
+
+Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
+ Result retval(Result::NOT_SUPPORTED);
+ int64_t timestampUs = 0;
+ if (mStream->get_next_write_timestamp != NULL) {
+ retval = Stream::analyzeStatus(
+ "get_next_write_timestamp",
+ mStream->get_next_write_timestamp(mStream, ×tampUs));
+ }
+ _hidl_cb(retval, timestampUs);
+ return Void();
+}
+
+Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
+ if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
+ int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
+ if (result == 0) {
+ mCallback = callback;
+ }
+ return Stream::analyzeStatus("set_callback", result);
+}
+
+Return<Result> StreamOut::clearCallback() {
+ if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
+ mCallback.clear();
+ return Result::OK;
+}
+
+// static
+int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
+ wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie));
+ sp<StreamOut> self = weakSelf.promote();
+ if (self == nullptr || self->mCallback == nullptr) return 0;
+ ALOGV("asyncCallback() event %d", event);
+ switch (event) {
+ case STREAM_CBK_EVENT_WRITE_READY:
+ self->mCallback->onWriteReady();
+ break;
+ case STREAM_CBK_EVENT_DRAIN_READY:
+ self->mCallback->onDrainReady();
+ break;
+ case STREAM_CBK_EVENT_ERROR:
+ self->mCallback->onError();
+ break;
+ default:
+ ALOGW("asyncCallback() unknown event %d", event);
+ break;
+ }
+ return 0;
+}
+
+Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
+ _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
+ return Void();
+}
+
+Return<Result> StreamOut::pause() {
+ return mStream->pause != NULL ?
+ Stream::analyzeStatus("pause", mStream->pause(mStream)) :
+ Result::NOT_SUPPORTED;
+}
+
+Return<Result> StreamOut::resume() {
+ return mStream->resume != NULL ?
+ Stream::analyzeStatus("resume", mStream->resume(mStream)) :
+ Result::NOT_SUPPORTED;
+}
+
+Return<bool> StreamOut::supportsDrain() {
+ return mStream->drain != NULL;
+}
+
+Return<Result> StreamOut::drain(AudioDrain type) {
+ return mStream->drain != NULL ?
+ Stream::analyzeStatus(
+ "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) :
+ Result::NOT_SUPPORTED;
+}
+
+Return<Result> StreamOut::flush() {
+ return mStream->flush != NULL ?
+ Stream::analyzeStatus("flush", mStream->flush(mStream)) :
+ Result::NOT_SUPPORTED;
+}
+
+// static
+Result StreamOut::getPresentationPositionImpl(
+ audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp) {
+ Result retval(Result::NOT_SUPPORTED);
+ if (stream->get_presentation_position == NULL) return retval;
+ struct timespec halTimeStamp;
+ retval = Stream::analyzeStatus(
+ "get_presentation_position",
+ stream->get_presentation_position(stream, frames, &halTimeStamp),
+ // Don't logspam on EINVAL--it's normal for get_presentation_position
+ // to return it sometimes. EAGAIN may be returned by A2DP audio HAL
+ // implementation.
+ EINVAL, EAGAIN);
+ if (retval == Result::OK) {
+ timeStamp->tvSec = halTimeStamp.tv_sec;
+ timeStamp->tvNSec = halTimeStamp.tv_nsec;
+ }
+ return retval;
+}
+
+Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
+ uint64_t frames = 0;
+ TimeSpec timeStamp = { 0, 0 };
+ Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp);
+ _hidl_cb(retval, frames, timeStamp);
+ return Void();
+}
+
+Return<Result> StreamOut::start() {
+ return mStreamMmap->start();
+}
+
+Return<Result> StreamOut::stop() {
+ return mStreamMmap->stop();
+}
+
+Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
+ return mStreamMmap->createMmapBuffer(
+ minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
+}
+
+Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+ return mStreamMmap->getMmapPosition(_hidl_cb);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h
new file mode 100644
index 0000000..bbe64a1
--- /dev/null
+++ b/audio/2.0/default/StreamOut.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
+
+#include <atomic>
+#include <memory>
+
+#include <android/hardware/audio/2.0/IStreamOut.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <utils/Thread.h>
+
+#include "Stream.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::V2_0::AudioDrain;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::IStreamOutCallback;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::TimeSpec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct StreamOut : public IStreamOut {
+ typedef MessageQueue<WriteCommand, kSynchronizedReadWrite> CommandMQ;
+ typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+ typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ;
+
+ StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream);
+
+ // Methods from ::android::hardware::audio::V2_0::IStream follow.
+ Return<uint64_t> getFrameSize() override;
+ Return<uint64_t> getFrameCount() override;
+ Return<uint64_t> getBufferSize() override;
+ Return<uint32_t> getSampleRate() override;
+ Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+ Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+ Return<AudioChannelMask> getChannelMask() override;
+ Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+ Return<Result> setChannelMask(AudioChannelMask mask) override;
+ Return<AudioFormat> getFormat() override;
+ Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+ Return<Result> setFormat(AudioFormat format) override;
+ Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+ Return<Result> addEffect(uint64_t effectId) override;
+ Return<Result> removeEffect(uint64_t effectId) override;
+ Return<Result> standby() override;
+ Return<AudioDevice> getDevice() override;
+ Return<Result> setDevice(const DeviceAddress& address) override;
+ Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+ Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+ Return<void> getParameters(
+ const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
+ Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
+ Return<uint32_t> getLatency() override;
+ Return<Result> setVolume(float left, float right) override;
+ Return<void> prepareForWriting(
+ uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) override;
+ Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb) override;
+ Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) override;
+ Return<Result> setCallback(const sp<IStreamOutCallback>& callback) override;
+ Return<Result> clearCallback() override;
+ Return<void> supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) override;
+ Return<Result> pause() override;
+ Return<Result> resume() override;
+ Return<bool> supportsDrain() override;
+ Return<Result> drain(AudioDrain type) override;
+ Return<Result> flush() override;
+ Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) override;
+ Return<Result> start() override;
+ Return<Result> stop() override;
+ Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+ Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+
+ static Result getPresentationPositionImpl(
+ audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp);
+
+ private:
+ bool mIsClosed;
+ audio_hw_device_t *mDevice;
+ audio_stream_out_t *mStream;
+ sp<Stream> mStreamCommon;
+ sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
+ sp<IStreamOutCallback> mCallback;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<DataMQ> mDataMQ;
+ std::unique_ptr<StatusMQ> mStatusMQ;
+ EventFlag* mEfGroup;
+ std::atomic<bool> mStopWriteThread;
+ sp<Thread> mWriteThread;
+
+ virtual ~StreamOut();
+
+ static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
diff --git a/audio/2.0/default/android.hardware.audio@2.0-service.rc b/audio/2.0/default/android.hardware.audio@2.0-service.rc
new file mode 100644
index 0000000..eeaf71b
--- /dev/null
+++ b/audio/2.0/default/android.hardware.audio@2.0-service.rc
@@ -0,0 +1,11 @@
+service audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
+ class hal
+ user audioserver
+ # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+ group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ # audioflinger restarts itself when it loses connection with the hal
+ # and its .rc file has an "onrestart restart audio-hal" rule, thus
+ # an additional auto-restart from the init process isn't needed.
+ oneshot
diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp
new file mode 100644
index 0000000..f3a858a
--- /dev/null
+++ b/audio/2.0/default/service.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "audiohalservice"
+
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+
+using android::hardware::audio::effect::V2_0::IEffectsFactory;
+using android::hardware::audio::V2_0::IDevicesFactory;
+using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using android::hardware::registerPassthroughServiceImplementation;
+namespace broadcastradio = android::hardware::broadcastradio;
+
+#ifdef TARGET_USES_BCRADIO_FUTURE_FEATURES
+static const bool useBroadcastRadioFutureFeatures = true;
+#else
+static const bool useBroadcastRadioFutureFeatures = false;
+#endif
+
+using android::OK;
+
+int main(int /* argc */, char* /* argv */ []) {
+ configureRpcThreadpool(16, true /*callerWillJoin*/);
+ android::status_t status;
+ status = registerPassthroughServiceImplementation<IDevicesFactory>();
+ LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio service: %d", status);
+ status = registerPassthroughServiceImplementation<IEffectsFactory>();
+ LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status);
+ // Soundtrigger and FM radio might be not present.
+ status = registerPassthroughServiceImplementation<ISoundTriggerHw>("sound_trigger.primary");
+ ALOGE_IF(status != OK, "Error while registering soundtrigger service: %d", status);
+ if (useBroadcastRadioFutureFeatures) {
+ status = registerPassthroughServiceImplementation<
+ broadcastradio::V1_1::IBroadcastRadioFactory>();
+ } else {
+ status = registerPassthroughServiceImplementation<
+ broadcastradio::V1_0::IBroadcastRadioFactory>();
+ }
+ ALOGE_IF(status != OK, "Error while registering fm radio service: %d", status);
+ joinRpcThreadpool();
+ return status;
+}
diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal
new file mode 100644
index 0000000..8e9ff14
--- /dev/null
+++ b/audio/2.0/types.hal
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 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.audio@2.0;
+
+import android.hardware.audio.common@2.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+ /* drain() returns when all data has been played. */
+ ALL,
+ /* drain() returns a short time before all data from the current track has
+ been played to give time for gapless track switch. */
+ EARLY_NOTIFY
+};
+
+/*
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+ uint64_t tvSec; // seconds
+ uint64_t tvNSec; // nanoseconds
+};
+
+/*
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+struct ParameterValue {
+ string key;
+ string value;
+};
+
+/*
+ * Specifies a device in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+ AudioDevice device; // discriminator
+ union Address {
+ MacAddress mac; // used for BLUETOOTH_A2DP_*
+ uint8_t[4] ipv4; // used for IP
+ struct Alsa {
+ int32_t card;
+ int32_t device;
+ } alsa; // used for USB_*
+ } address;
+ string busAddress; // used for BUS
+ string rSubmixAddress; // used for REMOTE_SUBMIX
+};
+
+/*
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+ memory sharedMemory; // mmap memory buffer
+ int32_t bufferSizeFrames; // total buffer size in frames
+ int32_t burstSizeFrames; // transfer size granularity in frames
+};
+
+/*
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+ int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+ int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/*
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ NOT_EMPTY = 1 << 0,
+ NOT_FULL = 1 << 1
+};
diff --git a/audio/2.0/vts/functional/Android.bp b/audio/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..f5ab76f
--- /dev/null
+++ b/audio/2.0/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalAudioV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["AudioPrimaryHidlHalTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "libcutils",
+ "android.hardware.audio@2.0",
+ "android.hardware.audio.common@2.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..1021569
--- /dev/null
+++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,1176 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "VtsHalAudioV2_0TargetTest"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+#include <limits>
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
+#include <android/hardware/audio/2.0/types.h>
+#include <android/hardware/audio/common/2.0/types.h>
+
+#include "utility/ReturnIn.h"
+#include "utility/AssertOk.h"
+#include "utility/PrettyPrintAudioTypes.h"
+
+using std::string;
+using std::to_string;
+using std::vector;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::audio::V2_0::AudioDrain;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IPrimaryDevice;
+using TtyMode = ::android::hardware::audio::V2_0::IPrimaryDevice::TtyMode;
+using ::android::hardware::audio::V2_0::IDevicesFactory;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::TimeSpec;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::IStreamOutCallback;
+using ::android::hardware::audio::V2_0::MmapBufferInfo;
+using ::android::hardware::audio::V2_0::MmapPosition;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::AudioHandleConsts;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioIoHandle;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
+
+using utility::returnIn;
+
+namespace doc {
+/** Document the current test case.
+ * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test will output:
+ * <testcase name="debugDump" status="run" time="6" classname="AudioPrimaryHidlTest"
+ description="Dump the state of the hal." />
+ * see https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
+ */
+void test(const std::string& testCaseDocumentation) {
+ ::testing::Test::RecordProperty("description", testCaseDocumentation);
+}
+
+/** Document why a test was not fully run. Usually due to an optional feature not implemented. */
+void partialTest(const std::string& reason) {
+ ::testing::Test::RecordProperty("partialyRunTest", reason);
+}
+}
+
+// Register callback for static object destruction
+// Avoid destroying static objects after main return.
+// Post main return destruction leads to incorrect gtest timing measurements as well as harder
+// debuging if anything goes wrong during destruction.
+class Environment : public ::testing::Environment {
+public:
+ using TearDownFunc = std::function<void ()>;
+ void registerTearDown(TearDownFunc&& tearDown) {
+ tearDowns.push_back(std::move(tearDown));
+ }
+
+private:
+ void TearDown() override {
+ // Call the tear downs in reverse order of insertion
+ for (auto& tearDown : tearDowns) {
+ tearDown();
+ }
+ }
+ std::list<TearDownFunc> tearDowns;
+};
+// Instance to register global tearDown
+static Environment* environment;
+
+class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
+protected:
+ // Convenient member to store results
+ Result res;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////// getService audio_devices_factory //////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlTest : public HidlTest {
+public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
+
+ if (devicesFactory == nullptr) {
+ environment->registerTearDown([]{ devicesFactory.clear(); });
+ devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>();
+ }
+ ASSERT_TRUE(devicesFactory != nullptr);
+ }
+
+protected:
+ // Cache the devicesFactory retrieval to speed up each test by ~0.5s
+ static sp<IDevicesFactory> devicesFactory;
+};
+sp<IDevicesFactory> AudioHidlTest::devicesFactory;
+
+TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+ doc::test("test the getService (called in SetUp)");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice primary ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test the primary device
+class AudioPrimaryHidlTest : public AudioHidlTest {
+public:
+ /** Primary HAL test are NOT thread safe. */
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
+
+ if (device == nullptr) {
+ IDevicesFactory::Result result;
+ sp<IDevice> baseDevice;
+ ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
+ returnIn(result, baseDevice)));
+ ASSERT_TRUE(baseDevice != nullptr);
+
+ environment->registerTearDown([]{ device.clear(); });
+ device = IPrimaryDevice::castFrom(baseDevice);
+ ASSERT_TRUE(device != nullptr);
+ }
+ }
+
+protected:
+ // Cache the device opening to speed up each test by ~0.5s
+ static sp<IPrimaryDevice> device;
+};
+sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
+
+TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+ doc::test("Test the openDevice (called in SetUp)");
+}
+
+TEST_F(AudioPrimaryHidlTest, Init) {
+ doc::test("Test that the audio primary hal initialized correctly");
+ ASSERT_OK(device->initCheck());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Property>
+class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
+protected:
+
+ /** Test a property getter and setter. */
+ template <class Getter, class Setter>
+ void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+ Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
+
+ Property initialValue; // Save initial value to restore it at the end of the test
+ ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+ ASSERT_OK(res);
+
+ for (Property setValue : valuesToTest) {
+ SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
+ testing::PrintToString(setValue));
+ ASSERT_OK((device.get()->*setter)(setValue));
+ Property getValue;
+ // Make sure the getter returns the same value just set
+ ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+ ASSERT_OK(res);
+ EXPECT_EQ(setValue, getValue);
+ }
+
+ for (Property invalidValue : invalidValues) {
+ SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
+ testing::PrintToString(invalidValue));
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue));
+ }
+
+ ASSERT_OK((device.get()->*setter)(initialValue)); // restore initial value
+ }
+
+ /** Test the getter and setter of an optional feature. */
+ template <class Getter, class Setter>
+ void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+ Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
+ doc::test("Test the optional " + propertyName + " getters and setter");
+ {
+ SCOPED_TRACE("Test feature support by calling the getter");
+ Property initialValue;
+ ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest(propertyName + " getter is not supported");
+ return;
+ }
+ ASSERT_OK(res); // If it is supported it must succeed
+ }
+ // The feature is supported, test it
+ testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
+ }
+};
+
+using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
+
+TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+ doc::test("Check that the mic can be muted and unmuted");
+ testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute);
+ // TODO: check that the mic is really muted (all sample are 0)
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+ doc::test("If master mute is supported, try to mute and unmute the master output");
+ testOptionalAccessors("master mute", {true, false, true},
+ &IDevice::setMasterMute, &IDevice::getMasterMute);
+ // TODO: check that the master volume is really muted
+}
+
+using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
+TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+ doc::test("Test the master volume if supported");
+ testOptionalAccessors("master volume", {0, 0.5, 1},
+ &IDevice::setMasterVolume, &IDevice::getMasterVolume,
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY,
+ 1 + std::numeric_limits<float>::epsilon()});
+ // TODO: check that the master volume is really changed
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// AudioPatches ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
+protected:
+ bool areAudioPatchesSupported() {
+ auto result = device->supportsAudioPatches();
+ EXPECT_TRUE(result.isOk());
+ return result;
+ }
+};
+
+TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+ doc::test("Test if audio patches are supported");
+ if (!areAudioPatchesSupported()) {
+ doc::partialTest("Audio patches are not supported");
+ return;
+ }
+ // TODO: test audio patches
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////// Required and recommended audio format support ///////////////
+// From: https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
+// From: https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
+/////////// TODO: move to the beginning of the file for easier update ////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
+public:
+ // Cache result ?
+ static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+ {8000, 11025, 16000, 22050, 32000, 44100},
+ {AudioFormat::PCM_16_BIT});
+ }
+
+ static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+ {24000, 48000},
+ {AudioFormat::PCM_16_BIT});
+ }
+
+ static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
+ // TODO: retrieve audio config supported by the platform
+ // as declared in the policy configuration
+ return {};
+ }
+
+ static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::IN_MONO},
+ {8000, 11025, 16000, 44100},
+ {AudioFormat::PCM_16_BIT});
+ }
+ static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::IN_STEREO},
+ {22050, 48000},
+ {AudioFormat::PCM_16_BIT});
+ }
+ static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
+ // TODO: retrieve audio config supported by the platform
+ // as declared in the policy configuration
+ return {};
+ }
+private:
+ static const vector<AudioConfig> combineAudioConfig(
+ vector<AudioChannelMask> channelMasks,
+ vector<uint32_t> sampleRates,
+ vector<AudioFormat> formats) {
+ vector<AudioConfig> configs;
+ for (auto channelMask: channelMasks) {
+ for (auto sampleRate : sampleRates) {
+ for (auto format : formats) {
+ AudioConfig config{};
+ // leave offloadInfo to 0
+ config.channelMask = channelMask;
+ config.sampleRateHz = sampleRate;
+ config.format = format;
+ // FIXME: leave frameCount to 0 ?
+ configs.push_back(config);
+ }
+ }
+ }
+ return configs;
+ }
+};
+
+/** Generate a test name based on an audio config.
+ *
+ * As the only parameter changing are channel mask and sample rate,
+ * only print those ones in the test name.
+ */
+static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
+ const AudioConfig& config = info.param;
+ return to_string(info.index) + "__" + to_string(config.sampleRateHz)+ "_" +
+ // "MONO" is more clear than "FRONT_LEFT"
+ ((config.channelMask == AudioChannelMask::OUT_MONO ||
+ config.channelMask == AudioChannelMask::IN_MONO) ?
+ "MONO" : toString(config.channelMask));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////// getInputBufferSize /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: execute input test only if platform declares android.hardware.microphone
+// how to get this value ? is it a property ???
+
+class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
+ public ::testing::WithParamInterface<AudioConfig> {
+protected:
+ void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
+ uint64_t bufferSize;
+ ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+
+ switch (res) {
+ case Result::INVALID_ARGUMENTS:
+ EXPECT_FALSE(supportRequired);
+ break;
+ case Result::OK:
+ // Check that the buffer is of a sane size
+ // For now only that it is > 0
+ EXPECT_GT(bufferSize, uint64_t(0));
+ break;
+ default:
+ FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+ }
+ }
+};
+
+// Test that the required capture config and those declared in the policy are indeed supported
+class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
+ doc::test("Input buffer size must be retrievable for a format with required support.");
+ inputBufferSizeTest(GetParam(), true);
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
+
+// Test that the recommended capture config are supported or lead to a INVALID_ARGUMENTS return
+class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
+ doc::test("Input buffer size should be retrievable for a format with recommended support.");
+ inputBufferSizeTest(GetParam(), false);
+}
+INSTANTIATE_TEST_CASE_P(
+ RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// setScreenState ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setScreenState) {
+ doc::test("Check that the hal can receive the screen state");
+ for (bool turnedOn : {false, true, true, false, false}) {
+ auto ret = device->setScreenState(turnedOn);
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ ASSERT_TRUE(result == Result::OK || result == Result::NOT_SUPPORTED) << toString(result);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////// {get,set}Parameters /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, getParameters) {
+ doc::test("Check that the hal can set and get parameters");
+ hidl_vec<hidl_string> keys;
+ hidl_vec<ParameterValue> values;
+ ASSERT_OK(device->getParameters(keys, returnIn(res, values)));
+ ASSERT_OK(device->setParameters(values));
+ values.resize(0);
+ ASSERT_OK(device->setParameters(values));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// debugDebug //////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class DebugDump>
+static void testDebugDump(DebugDump debugDump) {
+ FILE* file = tmpfile();
+ ASSERT_NE(nullptr, file) << errno;
+
+ auto* nativeHandle = native_handle_create(1, 0);
+ ASSERT_NE(nullptr, nativeHandle);
+ nativeHandle->data[0] = fileno(file);
+
+ hidl_handle handle;
+ handle.setTo(nativeHandle, true /*take ownership*/);
+
+ // TODO: debugDump does not return a Result.
+ // This mean that the hal can not report that it not implementing the function.
+ ASSERT_OK(debugDump(handle));
+
+ rewind(file); // can not fail
+
+ // Check that at least one bit was written by the hal
+ char buff;
+ ASSERT_EQ(size_t{1}, fread(&buff, sizeof(buff), 1, file));
+ EXPECT_EQ(0, fclose(file)) << errno;
+}
+
+TEST_F(AudioPrimaryHidlTest, debugDump) {
+ doc::test("Check that the hal can dump its state without error");
+ testDebugDump([this](const auto& handle){ return device->debugDump(handle); });
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////// open{Output,Input}Stream //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Stream>
+class OpenStreamTest : public AudioConfigPrimaryTest,
+ public ::testing::WithParamInterface<AudioConfig> {
+protected:
+ template <class Open>
+ void testOpen(Open openStream, const AudioConfig& config) {
+ // FIXME: Open a stream without an IOHandle
+ // This is not required to be accepted by hal implementations
+ AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+ AudioConfig suggestedConfig{};
+ ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig)));
+
+ // TODO: only allow failure for RecommendedPlaybackAudioConfig
+ switch (res) {
+ case Result::OK:
+ ASSERT_TRUE(stream != nullptr);
+ audioConfig = config;
+ break;
+ case Result::INVALID_ARGUMENTS:
+ ASSERT_TRUE(stream == nullptr);
+ AudioConfig suggestedConfigRetry;
+ // Could not open stream with config, try again with the suggested one
+ ASSERT_OK(openStream(ioHandle, suggestedConfig,
+ returnIn(res, stream, suggestedConfigRetry)));
+ // This time it must succeed
+ ASSERT_OK(res);
+ ASSERT_TRUE(stream == nullptr);
+ audioConfig = suggestedConfig;
+ break;
+ default:
+ FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+ }
+ open = true;
+ }
+
+ Return<Result> closeStream() {
+ open = false;
+ return stream->close();
+ }
+private:
+ void TearDown() override {
+ if (open) {
+ ASSERT_OK(stream->close());
+ }
+ }
+
+protected:
+
+ AudioConfig audioConfig;
+ DeviceAddress address = {};
+ sp<Stream> stream;
+ bool open = false;
+};
+
+////////////////////////////// openOutputStream //////////////////////////////
+
+class OutputStreamTest : public OpenStreamTest<IStreamOut> {
+ virtual void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ address.device = AudioDevice::OUT_DEFAULT;
+ const AudioConfig& config = GetParam();
+ AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination
+ testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
+ { return device->openOutputStream(handle, address, config, flags, cb); },
+ config);
+ }
+};
+TEST_P(OutputStreamTest, OpenOutputStreamTest) {
+ doc::test("Check that output streams can be open with the required and recommended config");
+ // Open done in SetUp
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedOutputStreamConfig, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
+ &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+ RecommendedOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
+ &generateTestName);
+
+////////////////////////////// openInputStream //////////////////////////////
+
+class InputStreamTest : public OpenStreamTest<IStreamIn> {
+
+ virtual void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ address.device = AudioDevice::IN_DEFAULT;
+ const AudioConfig& config = GetParam();
+ AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination
+ AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination
+ testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
+ { return device->openInputStream(handle, address, config, flags, source, cb); },
+ config);
+ }
+};
+
+TEST_P(InputStreamTest, OpenInputStreamTest) {
+ doc::test("Check that input streams can be open with the required and recommended config");
+ // Open done in setup
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredInputStreamConfigSupport, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedInputStreamConfig, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+ RecommendedInputStreamConfigSupport, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// IStream getters ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return an undefined value. */
+template <class R>
+static R extract(Return<R> ret) {
+ if (!ret.isOk()) {
+ ADD_FAILURE();
+ return R{};
+ }
+ return ret;
+}
+
+/* Could not find a way to write a test for two parametrized class fixure
+ * thus use this macro do duplicate tests for Input and Output stream */
+#define TEST_IO_STREAM(test_name, documentation, code) \
+ TEST_P(InputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ } \
+ TEST_P(OutputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ }
+
+TEST_IO_STREAM(GetFrameCount, "Check that the stream frame count == the one it was opened with",
+ ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount())))
+
+TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
+ ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
+
+TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with",
+ ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask())))
+
+TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
+ ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+
+// TODO: for now only check that the framesize is not incoherent
+TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
+ ASSERT_GT(extract(stream->getFrameSize()), 0U))
+
+TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with",
+ ASSERT_GE(extract(stream->getBufferSize()), \
+ extract(stream->getFrameSize())));
+
+template <class Property, class CapabilityGetter, class Getter, class Setter>
+static void testCapabilityGetter(const string& name, IStream* stream, Property currentValue,
+ CapabilityGetter capablityGetter, Getter getter, Setter setter) {
+ hidl_vec<Property> capabilities;
+ ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
+ if (capabilities.size() == 0) {
+ // The default hal should probably return a NOT_SUPPORTED if the hal does not expose
+ // capability retrieval. For now it returns an empty list if not implemented
+ doc::partialTest(name + " is not supported");
+ return;
+ };
+ // TODO: This code has never been tested on a hal that supports getSupportedSampleRates
+ EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
+ capabilities.end())
+ << "current " << name << " is not in the list of the supported ones "
+ << toString(capabilities);
+
+ // Check that all declared supported values are indeed supported
+ for (auto capability : capabilities) {
+ ASSERT_OK((stream->*setter)(capability));
+ ASSERT_EQ(capability, extract((stream->*getter)()));
+ }
+}
+
+TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
+ testCapabilityGetter("getSupportedSampleRate", stream.get(), \
+ extract(stream->getSampleRate()), \
+ &IStream::getSupportedSampleRates, \
+ &IStream::getSampleRate, &IStream::setSampleRate))
+
+TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
+ testCapabilityGetter("getSupportedChannelMask", stream.get(), \
+ extract(stream->getChannelMask()), \
+ &IStream::getSupportedChannelMasks, \
+ &IStream::getChannelMask, &IStream::setChannelMask))
+
+TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
+ testCapabilityGetter("getSupportedFormat", stream.get(), \
+ extract(stream->getFormat()), \
+ &IStream::getSupportedFormats, \
+ &IStream::getFormat, &IStream::setFormat))
+
+static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
+ auto ret = stream->getDevice();
+ ASSERT_TRUE(ret.isOk());
+ AudioDevice device = ret;
+ ASSERT_EQ(expectedDevice, device);
+}
+
+TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \
+ testGetDevice(stream.get(), address.device))
+
+static void testSetDevice(IStream* stream, const DeviceAddress& address) {
+ DeviceAddress otherAddress = address;
+ otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ?
+ AudioDevice::OUT_SPEAKER : AudioDevice::IN_BUILTIN_MIC;
+ EXPECT_OK(stream->setDevice(otherAddress));
+
+ ASSERT_OK(stream->setDevice(address)); // Go back to the original value
+}
+
+TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \
+ testSetDevice(stream.get(), address))
+
+static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+ uint32_t sampleRateHz;
+ AudioChannelMask mask;
+ AudioFormat format;
+
+ stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+
+ // FIXME: the qcom hal it does not currently negotiate the sampleRate & channel mask
+ EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
+ EXPECT_EQ(expectedConfig.channelMask, mask);
+ EXPECT_EQ(expectedConfig.format, format);
+}
+
+TEST_IO_STREAM(GetAudioProperties,
+ "Check that the stream audio properties == the ones it was opened with",
+ testGetAudioProperties(stream.get(), audioConfig))
+
+static void testConnectedState(IStream* stream) {
+ DeviceAddress address = {};
+ using AD = AudioDevice;
+ for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+ address.device = device;
+
+ ASSERT_OK(stream->setConnectedState(address, true));
+ ASSERT_OK(stream->setConnectedState(address, false));
+ }
+}
+TEST_IO_STREAM(SetConnectedState,
+ "Check that the stream can be notified of device connection and deconnection",
+ testConnectedState(stream.get()))
+
+
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+ ASSERT_RESULT(invalidArgsOrNotSupported, stream->setHwAvSync(666)))
+
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
+ ASSERT_TRUE(device->getHwAvSync().isOk()))
+
+static void checkGetParameter(IStream* stream, hidl_vec<hidl_string> keys,
+ vector<Result> expectedResults) {
+ hidl_vec<ParameterValue> parameters;
+ Result res;
+ ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
+ ASSERT_RESULT(expectedResults, res);
+ if (res == Result::OK) {
+ ASSERT_EQ(0U, parameters.size());
+ }
+}
+
+/* Get/Set parameter is intended to be an opaque channel between vendors app and their HALs.
+ * Thus can not be meaningfully tested.
+ * TODO: Doc missing. Should asking for an empty set of params raise an error ?
+ */
+TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
+ checkGetParameter(stream.get(), {} /* keys */,
+ {Result::OK, Result::INVALID_ARGUMENTS}))
+
+
+TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter",
+ checkGetParameter(stream.get(), {"Non existing key"} /* keys */,
+ {Result::INVALID_ARGUMENTS}))
+
+static vector<Result> okOrInvalidArguments = {Result::OK, Result::INVALID_ARGUMENTS};
+TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
+ ASSERT_RESULT(okOrInvalidArguments, stream->setParameters({})))
+
+TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS,
+ stream->setParameters({{"non existing key", "0"}})))
+
+TEST_IO_STREAM(DebugDump,
+ "Check that a stream can dump its state without error",
+ testDebugDump([this](const auto& handle){ return stream->debugDump(handle); }))
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// addRemoveEffect ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666)))
+TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666)))
+
+//TODO: positive tests
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Control ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
+ ASSERT_OK(stream->standby())) // can not fail
+
+static vector<Result> invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
+
+TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
+
+TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
+ ASSERT_OK(closeStream()); \
+ ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+
+static void testCreateTooBigMmapBuffer(IStream* stream) {
+ MmapBufferInfo info;
+ Result res;
+ // Assume that int max is a value too big to be allocated
+ // This is true currently with a 32bit media server, but might not when it will run in 64 bit
+ auto minSizeFrames = std::numeric_limits<int32_t>::max();
+ ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
+ testCreateTooBigMmapBuffer(stream.get()))
+
+
+static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
+ Result res;
+ MmapPosition position;
+ ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream,
+ "Retrieving the mmap position of a non mmaped stream should fail",
+ testGetMmapPositionOfNonMmapedStream(stream.get()))
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(InputStreamTest, GetAudioSource) {
+ doc::test("Retrieving the audio source of an input stream should always succeed");
+ AudioSource source;
+ ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
+ ASSERT_OK(res);
+ ASSERT_EQ(AudioSource::DEFAULT, source);
+}
+
+static void testUnitaryGain(std::function<Return<Result> (float)> setGain) {
+ for (float value : {0.0, 0.01, 0.5, 0.09, 1.0}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ ASSERT_OK(setGain(value));
+ }
+ for (float value : (float[]){-INFINITY,-1.0, -0.0,
+ 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY,
+ NAN}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ // FIXME: NAN should never be accepted
+ // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ?
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, setGain(value));
+ }
+}
+
+TEST_P(InputStreamTest, SetGain) {
+ doc::test("The gain of an input stream should only be set between [0,1]");
+ testUnitaryGain([this](float volume) { return stream->setGain(volume); });
+}
+
+static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) {
+ Result res;
+ // Ignore output parameters as the call should fail
+ ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
+ [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ EXPECT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
+ doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail");
+ testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) {
+ doc::test("Preparing a stream for reading with a overflowing sized buffer should fail");
+ auto uintMax = std::numeric_limits<uint32_t>::max();
+ testPrepareForReading(stream.get(), uintMax, uintMax);
+}
+
+TEST_P(InputStreamTest, GetInputFramesLost) {
+ doc::test("The number of frames lost on a never started stream should be 0");
+ auto ret = stream->getInputFramesLost();
+ ASSERT_TRUE(ret.isOk());
+ uint32_t framesLost{ret};
+ ASSERT_EQ(0U, framesLost);
+}
+
+TEST_P(InputStreamTest, getCapturePosition) {
+ doc::test("The capture position of a non prepared stream should not be retrievable");
+ uint64_t frames;
+ uint64_t time;
+ ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
+ ASSERT_RESULT(invalidStateOrNotSupported, res);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(OutputStreamTest, getLatency) {
+ doc::test("Make sure latency is over 0");
+ auto result = stream->getLatency();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_GT(result, 0U);
+}
+
+TEST_P(OutputStreamTest, setVolume) {
+ doc::test("Try to set the output volume");
+ auto result = stream->setVolume(1, 1);
+ ASSERT_TRUE(result.isOk());
+ if (result == Result::NOT_SUPPORTED) {
+ doc::partialTest("setVolume is not supported");
+ return;
+ }
+ testUnitaryGain([this](float volume) { return stream->setVolume(volume, volume); });
+}
+
+static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize, uint32_t framesCount) {
+ Result res;
+ // Ignore output parameters as the call should fail
+ ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
+ [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ EXPECT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) {
+ doc::test("Preparing a stream for writing with a 2^32 sized buffer should fail");
+ testPrepareForWriting(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) {
+ doc::test("Preparing a stream for writing with a overflowing sized buffer should fail");
+ auto uintMax = std::numeric_limits<uint32_t>::max();
+ testPrepareForWriting(stream.get(), uintMax, uintMax);
+}
+
+struct Capability {
+ Capability(IStreamOut* stream) {
+ EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
+ auto ret = stream->supportsDrain();
+ EXPECT_TRUE(ret.isOk());
+ if (ret.isOk()) {
+ drain = ret;
+ }
+ }
+ bool pause = false;
+ bool resume = false;
+ bool drain = false;
+};
+
+TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) {
+ Capability(stream.get());
+}
+
+TEST_P(OutputStreamTest, GetRenderPosition) {
+ uint32_t dspFrames;
+ ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getRenderPosition is not supported");
+ return;
+ }
+ ASSERT_OK(res);
+ ASSERT_EQ(0U, dspFrames);
+}
+
+TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
+ uint64_t timestampUs;
+ ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getNextWriteTimestamp is not supported");
+ return;
+ }
+ ASSERT_EQ(Result::INVALID_STATE, res);
+}
+
+/** Stub implementation of out stream callback. */
+class MockOutCallbacks : public IStreamOutCallback {
+ Return<void> onWriteReady() override { return {}; }
+ Return<void> onDrainReady() override { return {}; }
+ Return<void> onError() override { return {}; }
+};
+
+static bool isAsyncModeSupported(IStreamOut *stream) {
+ auto res = stream->setCallback(new MockOutCallbacks);
+ stream->clearCallback(); // try to restore the no callback state, ignore any error
+ auto okOrNotSupported = { Result::OK, Result::NOT_SUPPORTED };
+ EXPECT_RESULT(okOrNotSupported, res);
+ return res.isOk() ? res == Result::OK : false;
+}
+
+TEST_P(OutputStreamTest, SetCallback) {
+ if (!isAsyncModeSupported(stream.get())) {
+ doc::partialTest("The stream does not support async operations");
+ return;
+ }
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+}
+
+TEST_P(OutputStreamTest, clearCallback) {
+ if (!isAsyncModeSupported(stream.get())) {
+ doc::partialTest("The stream does not support async operations");
+ return;
+ }
+ // TODO: Clarify if clearing a non existing callback should fail
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+ ASSERT_OK(stream->clearCallback());
+}
+
+TEST_P(OutputStreamTest, Resume) {
+ if (!Capability(stream.get()).resume) {
+ doc::partialTest("The output stream does not support resume");
+ return;
+ }
+ ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+TEST_P(OutputStreamTest, Pause) {
+ if (!Capability(stream.get()).pause) {
+ doc::partialTest("The output stream does not support pause");
+ return;
+ }
+ ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+static void testDrain(IStreamOut *stream, AudioDrain type) {
+ if (!Capability(stream).drain) {
+ doc::partialTest("The output stream does not support pause");
+ return;
+ }
+ ASSERT_RESULT(Result::OK, stream->drain(type));
+}
+
+TEST_P(OutputStreamTest, DrainAll) {
+ testDrain(stream.get(), AudioDrain::ALL);
+}
+
+TEST_P(OutputStreamTest, DrainEarlyNotify) {
+ testDrain(stream.get(), AudioDrain::EARLY_NOTIFY);
+}
+
+TEST_P(OutputStreamTest, FlushStop) {
+ auto ret = stream->flush();
+ ASSERT_TRUE(ret.isOk());
+ if (ret == Result::NOT_SUPPORTED) {
+ doc::partialTest("Flush is not supported");
+ return;
+ }
+ ASSERT_OK(ret);
+}
+
+TEST_P(OutputStreamTest, GetPresentationPositionStop) {
+ uint64_t frames;
+ TimeSpec mesureTS;
+ ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getpresentationPosition is not supported");
+ return;
+ }
+ ASSERT_EQ(0U, frames);
+
+ struct timespec currentTS;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤tTS)) << errno;
+
+ auto toMicroSec = [](uint64_t sec, auto nsec) { return sec * 1e+6 + nsec / 1e+3; };
+ auto currentTime = toMicroSec(currentTS.tv_sec, currentTS.tv_nsec);
+ auto mesureTime = toMicroSec(mesureTS.tvSec, mesureTS.tvNSec);
+ ASSERT_PRED2([](auto c, auto m){ return c - m < 1e+6; }, currentTime, mesureTime);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// PrimaryDevice ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+ doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
+ testUnitaryGain([this](float volume) { return device->setVoiceVolume(volume); });
+}
+
+TEST_F(AudioPrimaryHidlTest, setMode) {
+ doc::test("Make sure setMode always succeeds if mode is valid");
+ for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION,
+ AudioMode::RINGTONE, AudioMode::CURRENT,
+ AudioMode::NORMAL /* Make sure to leave the test in normal mode */ }) {
+ SCOPED_TRACE("mode=" + toString(mode));
+ ASSERT_OK(device->setMode(mode));
+ }
+
+ // FIXME: Missing api doc. What should the impl do if the mode is invalid ?
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode::INVALID));
+}
+
+
+TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+ doc::test("Query and set the BT SCO NR&EC state");
+ testOptionalAccessors("BtScoNrecEnabled", {true, false, true},
+ &IPrimaryDevice::setBtScoNrecEnabled,
+ &IPrimaryDevice::getBtScoNrecEnabled);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+ doc::test("Query and set the SCO whideband state");
+ testOptionalAccessors("BtScoWideband", {true, false, true},
+ &IPrimaryDevice::setBtScoWidebandEnabled,
+ &IPrimaryDevice::getBtScoWidebandEnabled);
+}
+
+using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>;
+TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+ doc::test("Query and set the TTY mode state");
+ testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
+ &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+ doc::test("Query and set the HAC state");
+ testAccessors("HAC", {true, false, true},
+ &IPrimaryDevice::setHacEnabled,
+ &IPrimaryDevice::getHacEnabled);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Clean caches on global tear down ////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char** argv) {
+ environment = new Environment;
+ ::testing::AddGlobalTestEnvironment(environment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h
new file mode 100644
index 0000000..10b088c
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/AssertOk.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <vector>
+#include <algorithm>
+
+#include <hidl/Status.h>
+
+namespace detail {
+
+// This is a detail namespace, thus it is OK to import a class as nobody else is allowed to use it
+using ::android::hardware::Return;
+using ::android::hardware::audio::V2_0::Result;
+
+inline void assertResult(Result expected, Result result) {
+ ASSERT_EQ(expected, result);
+}
+
+inline void assertResult(Result expected, const Return<Result> &ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertResult(const std::vector<Result> &expected, Result result) {
+ if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
+ return; // result is in expected
+ }
+ FAIL() << "Expected result " << ::testing::PrintToString(result)
+ << " to be one of " << ::testing::PrintToString(expected);
+}
+
+inline void assertResult(const std::vector<Result> &expected, const Return<Result> &ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertOk(const Return<void> &ret) {
+ ASSERT_TRUE(ret.isOk());
+}
+
+inline void assertOk(Result result) {
+ assertResult(Result::OK, result);
+}
+
+inline void assertOk(const Return<Result> &ret) {
+ assertResult(Result::OK, ret);
+}
+
+}
+
+// Test anything provided is and contains only OK
+#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret))
+#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret))
+
+#define ASSERT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
+#define EXPECT_RESULT(expected, ret) EXPECT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
new file mode 100644
index 0000000..025cd1c
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#include <type_traits>
+
+/** @file Use HIDL generated toString methods to pretty print gtest errors */
+
+namespace detail {
+
+// Print the value of an enum as hex
+template <class Enum>
+inline void printUnderlyingValue(Enum value, ::std::ostream* os) {
+ *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")";
+}
+
+} // namespace detail
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace V2_0 {
+
+inline void PrintTo(const Result& result, ::std::ostream* os) {
+ *os << toString(result);
+ detail::printUnderlyingValue(result, os);
+}
+
+} // namespace V2_0
+namespace common {
+namespace V2_0 {
+
+inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
+ *os << toString(config);
+}
+
+inline void PrintTo(const AudioDevice& device, ::std::ostream* os) {
+ *os << toString(device);
+ detail::printUnderlyingValue(device, os);
+}
+
+inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) {
+ *os << toString(channelMask);
+ detail::printUnderlyingValue(channelMask, os);
+}
+
+} // namespace V2_0
+} // namespace common
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/2.0/vts/functional/utility/ReturnIn.h b/audio/2.0/vts/functional/utility/ReturnIn.h
new file mode 100644
index 0000000..bb2389a
--- /dev/null
+++ b/audio/2.0/vts/functional/utility/ReturnIn.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <tuple>
+
+namespace utility {
+
+namespace detail {
+// Helper class to generate the HIDL synchronous callback
+template <class... ResultStore>
+class ReturnIn {
+ public:
+ // Provide to the constructor the variables where the output parameters must be copied
+ // TODO: take pointers to match google output parameter style ?
+ ReturnIn(ResultStore&... ts) : results(ts...) {}
+ // Synchronous callback
+ template <class... Results>
+ void operator() (Results&&...results) {
+ set(std::forward<Results>(results)...);
+ }
+ private:
+ // Recursively set all output parameters
+ template <class Head, class... Tail>
+ void set(Head&& head, Tail&&... tail) {
+ std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results)
+ = std::forward<Head>(head);
+ set(tail...);
+ }
+ // Trivial case
+ void set() {}
+
+ // All variables to set are stored here
+ std::tuple<ResultStore&...> results;
+};
+} // namespace detail
+
+// Generate the HIDL synchronous callback with a copy policy
+// Input: the variables (lvalue reference) where to save the return values
+// Output: the callback to provide to a HIDL call with a synchronous callback
+// The output parameters *will be copied* do not use this function if you have
+// a zero copy policy
+template <class... ResultStore>
+detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) { return {ts...};}
+
+}
diff --git a/audio/Android.bp b/audio/Android.bp
new file mode 100644
index 0000000..8a1e892
--- /dev/null
+++ b/audio/Android.bp
@@ -0,0 +1,8 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "2.0",
+ "2.0/vts/functional",
+ "common/2.0",
+ "effect/2.0",
+ "effect/2.0/vts/functional",
+]
diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp
new file mode 100644
index 0000000..5330086
--- /dev/null
+++ b/audio/common/2.0/Android.bp
@@ -0,0 +1,53 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.audio.common@2.0_hal",
+ srcs: [
+ "types.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio.common@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.common@2.0",
+ srcs: [
+ ":android.hardware.audio.common@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/common/2.0/types.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio.common@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.common@2.0",
+ srcs: [
+ ":android.hardware.audio.common@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/common/2.0/types.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.audio.common@2.0",
+ generated_sources: ["android.hardware.audio.common@2.0_genc++"],
+ generated_headers: ["android.hardware.audio.common@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.audio.common@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+}
diff --git a/audio/common/2.0/Android.mk b/audio/common/2.0/Android.mk
new file mode 100644
index 0000000..7d62779
--- /dev/null
+++ b/audio/common/2.0/Android.mk
@@ -0,0 +1,39 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio.common@2.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/audio/common/V2_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.audio.common@2.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/common/2.0/default/Android.mk b/audio/common/2.0/default/Android.mk
new file mode 100644
index 0000000..8e2fed4
--- /dev/null
+++ b/audio/common/2.0/default/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2016 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio.common@2.0-util
+LOCAL_SRC_FILES := \
+ EffectMap.cpp \
+ HidlUtils.cpp \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libhidlbase \
+ android.hardware.audio.common@2.0 \
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/common/2.0/default/EffectMap.cpp b/audio/common/2.0/default/EffectMap.cpp
new file mode 100644
index 0000000..703b91c
--- /dev/null
+++ b/audio/common/2.0/default/EffectMap.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <atomic>
+
+#include "EffectMap.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(EffectMap);
+
+// static
+const uint64_t EffectMap::INVALID_ID = 0;
+
+// static
+uint64_t EffectMap::makeUniqueId() {
+ static std::atomic<uint64_t> counter{INVALID_ID + 1};
+ return counter++;
+}
+
+uint64_t EffectMap::add(effect_handle_t handle) {
+ uint64_t newId = makeUniqueId();
+ std::lock_guard<std::mutex> lock(mLock);
+ mEffects.add(newId, handle);
+ return newId;
+}
+
+effect_handle_t EffectMap::get(const uint64_t& id) {
+ std::lock_guard<std::mutex> lock(mLock);
+ ssize_t idx = mEffects.indexOfKey(id);
+ return idx >= 0 ? mEffects[idx] : NULL;
+}
+
+void EffectMap::remove(effect_handle_t handle) {
+ std::lock_guard<std::mutex> lock(mLock);
+ for (size_t i = 0; i < mEffects.size(); ++i) {
+ if (mEffects[i] == handle) {
+ mEffects.removeItemsAt(i);
+ break;
+ }
+ }
+}
+
+} // namespace android
diff --git a/audio/common/2.0/default/EffectMap.h b/audio/common/2.0/default/EffectMap.h
new file mode 100644
index 0000000..82bbb1f
--- /dev/null
+++ b/audio/common/2.0/default/EffectMap.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_audio_V2_0_EffectMap_H_
+#define android_hardware_audio_V2_0_EffectMap_H_
+
+#include <mutex>
+
+#include <hardware/audio_effect.h>
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+
+namespace android {
+
+// This class needs to be in 'android' ns because Singleton macros require that.
+class EffectMap : public Singleton<EffectMap> {
+ public:
+ static const uint64_t INVALID_ID;
+
+ uint64_t add(effect_handle_t handle);
+ effect_handle_t get(const uint64_t& id);
+ void remove(effect_handle_t handle);
+
+ private:
+ static uint64_t makeUniqueId();
+
+ std::mutex mLock;
+ KeyedVector<uint64_t, effect_handle_t> mEffects;
+};
+
+} // namespace android
+
+#endif // android_hardware_audio_V2_0_EffectMap_H_
diff --git a/audio/common/2.0/default/HidlUtils.cpp b/audio/common/2.0/default/HidlUtils.cpp
new file mode 100644
index 0000000..241ca90
--- /dev/null
+++ b/audio/common/2.0/default/HidlUtils.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <string.h>
+
+#include "HidlUtils.h"
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::AudioGainMode;
+using ::android::hardware::audio::common::V2_0::AudioMixLatencyClass;
+using ::android::hardware::audio::common::V2_0::AudioPortConfigMask;
+using ::android::hardware::audio::common::V2_0::AudioPortRole;
+using ::android::hardware::audio::common::V2_0::AudioPortType;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::AudioStreamType;
+
+namespace android {
+
+void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
+ config->sampleRateHz = halConfig.sample_rate;
+ config->channelMask = AudioChannelMask(halConfig.channel_mask);
+ config->format = AudioFormat(halConfig.format);
+ audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
+ config->frameCount = halConfig.frame_count;
+}
+
+void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
+ memset(halConfig, 0, sizeof(audio_config_t));
+ halConfig->sample_rate = config.sampleRateHz;
+ halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+ halConfig->format = static_cast<audio_format_t>(config.format);
+ audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info);
+ halConfig->frame_count = config.frameCount;
+}
+
+void HidlUtils::audioGainConfigFromHal(
+ const struct audio_gain_config& halConfig, AudioGainConfig* config) {
+ config->index = halConfig.index;
+ config->mode = AudioGainMode(halConfig.mode);
+ config->channelMask = AudioChannelMask(halConfig.channel_mask);
+ for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
+ config->values[i] = halConfig.values[i];
+ }
+ config->rampDurationMs = halConfig.ramp_duration_ms;
+}
+
+void HidlUtils::audioGainConfigToHal(
+ const AudioGainConfig& config, struct audio_gain_config* halConfig) {
+ halConfig->index = config.index;
+ halConfig->mode = static_cast<audio_gain_mode_t>(config.mode);
+ halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+ memset(halConfig->values, 0, sizeof(halConfig->values));
+ for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
+ halConfig->values[i] = config.values[i];
+ }
+ halConfig->ramp_duration_ms = config.rampDurationMs;
+}
+
+void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) {
+ gain->mode = AudioGainMode(halGain.mode);
+ gain->channelMask = AudioChannelMask(halGain.channel_mask);
+ gain->minValue = halGain.min_value;
+ gain->maxValue = halGain.max_value;
+ gain->defaultValue = halGain.default_value;
+ gain->stepValue = halGain.step_value;
+ gain->minRampMs = halGain.min_ramp_ms;
+ gain->maxRampMs = halGain.max_ramp_ms;
+}
+
+void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
+ halGain->mode = static_cast<audio_gain_mode_t>(gain.mode);
+ halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask);
+ halGain->min_value = gain.minValue;
+ halGain->max_value = gain.maxValue;
+ halGain->default_value = gain.defaultValue;
+ halGain->step_value = gain.stepValue;
+ halGain->min_ramp_ms = gain.minRampMs;
+ halGain->max_ramp_ms = gain.maxRampMs;
+}
+
+void HidlUtils::audioOffloadInfoFromHal(
+ const audio_offload_info_t& halOffload, AudioOffloadInfo* offload) {
+ offload->sampleRateHz = halOffload.sample_rate;
+ offload->channelMask = AudioChannelMask(halOffload.channel_mask);
+ offload->format = AudioFormat(halOffload.format);
+ offload->streamType = AudioStreamType(halOffload.stream_type);
+ offload->bitRatePerSecond = halOffload.bit_rate;
+ offload->durationMicroseconds = halOffload.duration_us;
+ offload->hasVideo = halOffload.has_video;
+ offload->isStreaming = halOffload.is_streaming;
+}
+
+void HidlUtils::audioOffloadInfoToHal(
+ const AudioOffloadInfo& offload, audio_offload_info_t* halOffload) {
+ *halOffload = AUDIO_INFO_INITIALIZER;
+ halOffload->sample_rate = offload.sampleRateHz;
+ halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask);
+ halOffload->format = static_cast<audio_format_t>(offload.format);
+ halOffload->stream_type = static_cast<audio_stream_type_t>(offload.streamType);
+ halOffload->bit_rate = offload.bitRatePerSecond;
+ halOffload->duration_us = offload.durationMicroseconds;
+ halOffload->has_video = offload.hasVideo;
+ halOffload->is_streaming = offload.isStreaming;
+ halOffload->bit_width = offload.bitWidth;
+ halOffload->offload_buffer_size = offload.bufferSize;
+ halOffload->usage = static_cast<audio_usage_t>(offload.usage);
+}
+
+void HidlUtils::audioPortConfigFromHal(
+ const struct audio_port_config& halConfig, AudioPortConfig* config) {
+ config->id = halConfig.id;
+ config->role = AudioPortRole(halConfig.role);
+ config->type = AudioPortType(halConfig.type);
+ config->configMask = AudioPortConfigMask(halConfig.config_mask);
+ config->sampleRateHz = halConfig.sample_rate;
+ config->channelMask = AudioChannelMask(halConfig.channel_mask);
+ config->format = AudioFormat(halConfig.format);
+ audioGainConfigFromHal(halConfig.gain, &config->gain);
+ switch (halConfig.type) {
+ case AUDIO_PORT_TYPE_NONE: break;
+ case AUDIO_PORT_TYPE_DEVICE: {
+ config->ext.device.hwModule = halConfig.ext.device.hw_module;
+ config->ext.device.type = AudioDevice(halConfig.ext.device.type);
+ memcpy(config->ext.device.address.data(),
+ halConfig.ext.device.address,
+ AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ }
+ case AUDIO_PORT_TYPE_MIX: {
+ config->ext.mix.hwModule = halConfig.ext.mix.hw_module;
+ config->ext.mix.ioHandle = halConfig.ext.mix.handle;
+ if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) {
+ config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source);
+ } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) {
+ config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream);
+ }
+ break;
+ }
+ case AUDIO_PORT_TYPE_SESSION: {
+ config->ext.session.session = halConfig.ext.session.session;
+ break;
+ }
+ }
+}
+
+void HidlUtils::audioPortConfigToHal(
+ const AudioPortConfig& config, struct audio_port_config* halConfig) {
+ memset(halConfig, 0, sizeof(audio_port_config));
+ halConfig->id = config.id;
+ halConfig->role = static_cast<audio_port_role_t>(config.role);
+ halConfig->type = static_cast<audio_port_type_t>(config.type);
+ halConfig->config_mask = static_cast<unsigned int>(config.configMask);
+ halConfig->sample_rate = config.sampleRateHz;
+ halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+ halConfig->format = static_cast<audio_format_t>(config.format);
+ audioGainConfigToHal(config.gain, &halConfig->gain);
+ switch (config.type) {
+ case AudioPortType::NONE: break;
+ case AudioPortType::DEVICE: {
+ halConfig->ext.device.hw_module = config.ext.device.hwModule;
+ halConfig->ext.device.type = static_cast<audio_devices_t>(config.ext.device.type);
+ memcpy(halConfig->ext.device.address,
+ config.ext.device.address.data(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ }
+ case AudioPortType::MIX: {
+ halConfig->ext.mix.hw_module = config.ext.mix.hwModule;
+ halConfig->ext.mix.handle = config.ext.mix.ioHandle;
+ if (config.role == AudioPortRole::SOURCE) {
+ halConfig->ext.mix.usecase.source =
+ static_cast<audio_source_t>(config.ext.mix.useCase.source);
+ } else if (config.role == AudioPortRole::SINK) {
+ halConfig->ext.mix.usecase.stream =
+ static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream);
+ }
+ break;
+ }
+ case AudioPortType::SESSION: {
+ halConfig->ext.session.session =
+ static_cast<audio_session_t>(config.ext.session.session);
+ break;
+ }
+ }
+}
+
+void HidlUtils::audioPortConfigsFromHal(
+ unsigned int numHalConfigs, const struct audio_port_config *halConfigs,
+ hidl_vec<AudioPortConfig> *configs) {
+ configs->resize(numHalConfigs);
+ for (unsigned int i = 0; i < numHalConfigs; ++i) {
+ audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
+ }
+}
+
+std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal(
+ const hidl_vec<AudioPortConfig>& configs) {
+ std::unique_ptr<audio_port_config[]> halConfigs(new audio_port_config[configs.size()]);
+ for (size_t i = 0; i < configs.size(); ++i) {
+ audioPortConfigToHal(configs[i], &halConfigs[i]);
+ }
+ return halConfigs;
+}
+
+void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
+ port->id = halPort.id;
+ port->role = AudioPortRole(halPort.role);
+ port->type = AudioPortType(halPort.type);
+ port->name.setToExternal(halPort.name, strlen(halPort.name));
+ port->sampleRates.resize(halPort.num_sample_rates);
+ for (size_t i = 0; i < halPort.num_sample_rates; ++i) {
+ port->sampleRates[i] = halPort.sample_rates[i];
+ }
+ port->channelMasks.resize(halPort.num_channel_masks);
+ for (size_t i = 0; i < halPort.num_channel_masks; ++i) {
+ port->channelMasks[i] = AudioChannelMask(halPort.channel_masks[i]);
+ }
+ port->formats.resize(halPort.num_formats);
+ for (size_t i = 0; i < halPort.num_formats; ++i) {
+ port->formats[i] = AudioFormat(halPort.formats[i]);
+ }
+ port->gains.resize(halPort.num_gains);
+ for (size_t i = 0; i < halPort.num_gains; ++i) {
+ audioGainFromHal(halPort.gains[i], &port->gains[i]);
+ }
+ audioPortConfigFromHal(halPort.active_config, &port->activeConfig);
+ switch (halPort.type) {
+ case AUDIO_PORT_TYPE_NONE: break;
+ case AUDIO_PORT_TYPE_DEVICE: {
+ port->ext.device.hwModule = halPort.ext.device.hw_module;
+ port->ext.device.type = AudioDevice(halPort.ext.device.type);
+ memcpy(port->ext.device.address.data(),
+ halPort.ext.device.address,
+ AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ }
+ case AUDIO_PORT_TYPE_MIX: {
+ port->ext.mix.hwModule = halPort.ext.mix.hw_module;
+ port->ext.mix.ioHandle = halPort.ext.mix.handle;
+ port->ext.mix.latencyClass = AudioMixLatencyClass(halPort.ext.mix.latency_class);
+ break;
+ }
+ case AUDIO_PORT_TYPE_SESSION: {
+ port->ext.session.session = halPort.ext.session.session;
+ break;
+ }
+ }
+}
+
+void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
+ memset(halPort, 0, sizeof(audio_port));
+ halPort->id = port.id;
+ halPort->role = static_cast<audio_port_role_t>(port.role);
+ halPort->type = static_cast<audio_port_type_t>(port.type);
+ memcpy(halPort->name,
+ port.name.c_str(),
+ std::min(port.name.size(), static_cast<size_t>(AUDIO_PORT_MAX_NAME_LEN)));
+ halPort->num_sample_rates =
+ std::min(port.sampleRates.size(), static_cast<size_t>(AUDIO_PORT_MAX_SAMPLING_RATES));
+ for (size_t i = 0; i < halPort->num_sample_rates; ++i) {
+ halPort->sample_rates[i] = port.sampleRates[i];
+ }
+ halPort->num_channel_masks =
+ std::min(port.channelMasks.size(), static_cast<size_t>(AUDIO_PORT_MAX_CHANNEL_MASKS));
+ for (size_t i = 0; i < halPort->num_channel_masks; ++i) {
+ halPort->channel_masks[i] = static_cast<audio_channel_mask_t>(port.channelMasks[i]);
+ }
+ halPort->num_formats =
+ std::min(port.formats.size(), static_cast<size_t>(AUDIO_PORT_MAX_FORMATS));
+ for (size_t i = 0; i < halPort->num_formats; ++i) {
+ halPort->formats[i] = static_cast<audio_format_t>(port.formats[i]);
+ }
+ halPort->num_gains = std::min(port.gains.size(), static_cast<size_t>(AUDIO_PORT_MAX_GAINS));
+ for (size_t i = 0; i < halPort->num_gains; ++i) {
+ audioGainToHal(port.gains[i], &halPort->gains[i]);
+ }
+ audioPortConfigToHal(port.activeConfig, &halPort->active_config);
+ switch (port.type) {
+ case AudioPortType::NONE: break;
+ case AudioPortType::DEVICE: {
+ halPort->ext.device.hw_module = port.ext.device.hwModule;
+ halPort->ext.device.type = static_cast<audio_devices_t>(port.ext.device.type);
+ memcpy(halPort->ext.device.address,
+ port.ext.device.address.data(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ break;
+ }
+ case AudioPortType::MIX: {
+ halPort->ext.mix.hw_module = port.ext.mix.hwModule;
+ halPort->ext.mix.handle = port.ext.mix.ioHandle;
+ halPort->ext.mix.latency_class =
+ static_cast<audio_mix_latency_class_t>(port.ext.mix.latencyClass);
+ break;
+ }
+ case AudioPortType::SESSION: {
+ halPort->ext.session.session = static_cast<audio_session_t>(port.ext.session.session);
+ break;
+ }
+ }
+}
+
+void HidlUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) {
+ uuid->timeLow = halUuid.timeLow;
+ uuid->timeMid = halUuid.timeMid;
+ uuid->versionAndTimeHigh = halUuid.timeHiAndVersion;
+ uuid->variantAndClockSeqHigh = halUuid.clockSeq;
+ memcpy(uuid->node.data(), halUuid.node, uuid->node.size());
+}
+
+void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) {
+ halUuid->timeLow = uuid.timeLow;
+ halUuid->timeMid = uuid.timeMid;
+ halUuid->timeHiAndVersion = uuid.versionAndTimeHigh;
+ halUuid->clockSeq = uuid.variantAndClockSeqHigh;
+ memcpy(halUuid->node, uuid.node.data(), uuid.node.size());
+}
+
+} // namespace android
diff --git a/audio/common/2.0/default/HidlUtils.h b/audio/common/2.0/default/HidlUtils.h
new file mode 100644
index 0000000..3fde4d7
--- /dev/null
+++ b/audio/common/2.0/default/HidlUtils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_audio_V2_0_Hidl_Utils_H_
+#define android_hardware_audio_V2_0_Hidl_Utils_H_
+
+#include <memory>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <system/audio.h>
+
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioGain;
+using ::android::hardware::audio::common::V2_0::AudioGainConfig;
+using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
+using ::android::hardware::audio::common::V2_0::AudioPort;
+using ::android::hardware::audio::common::V2_0::AudioPortConfig;
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+
+class HidlUtils {
+ public:
+ static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
+ static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
+ static void audioGainConfigFromHal(
+ const struct audio_gain_config& halConfig, AudioGainConfig* config);
+ static void audioGainConfigToHal(
+ const AudioGainConfig& config, struct audio_gain_config* halConfig);
+ static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain);
+ static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
+ static void audioOffloadInfoFromHal(
+ const audio_offload_info_t& halOffload, AudioOffloadInfo* offload);
+ static void audioOffloadInfoToHal(
+ const AudioOffloadInfo& offload, audio_offload_info_t* halOffload);
+ static void audioPortConfigFromHal(
+ const struct audio_port_config& halConfig, AudioPortConfig* config);
+ static void audioPortConfigToHal(
+ const AudioPortConfig& config, struct audio_port_config* halConfig);
+ static void audioPortConfigsFromHal(
+ unsigned int numHalConfigs, const struct audio_port_config *halConfigs,
+ hidl_vec<AudioPortConfig> *configs);
+ static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
+ const hidl_vec<AudioPortConfig>& configs);
+ static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
+ static void audioPortToHal(const AudioPort& port, struct audio_port* halPort);
+ static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
+ static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid);
+};
+
+} // namespace android
+
+#endif // android_hardware_audio_V2_0_Hidl_Utils_H_
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal
new file mode 100644
index 0000000..dd7281d
--- /dev/null
+++ b/audio/common/2.0/types.hal
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2016 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.audio.common@2.0;
+
+/*
+ *
+ * IDs and Handles
+ *
+ */
+
+/*
+ * Handle type for identifying audio sources and sinks.
+ */
+typedef int32_t AudioIoHandle;
+
+/*
+ * Audio hw module handle functions or structures referencing a module.
+ */
+typedef int32_t AudioModuleHandle;
+
+/*
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/*
+ * Each patch is identified by a handle at the interface used to create that
+ * patch. For instance, when a patch is created by the audio HAL, the HAL
+ * allocates and returns a handle. This handle is unique to a given audio HAL
+ * hardware module. But the same patch receives another system wide unique
+ * handle allocated by the framework. This unique handle is used for all
+ * transactions inside the framework.
+ */
+typedef int32_t AudioPatchHandle;
+
+/*
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/*
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+@export(name="")
+enum AudioHandleConsts : int32_t {
+ AUDIO_IO_HANDLE_NONE = 0,
+ AUDIO_MODULE_HANDLE_NONE = 0,
+ AUDIO_PORT_HANDLE_NONE = 0,
+ AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+/*
+ * Commonly used structure for passing unique identifieds (UUID).
+ * For the definition of UUID, refer to ITU-T X.667 spec.
+ */
+struct Uuid {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t versionAndTimeHigh;
+ uint16_t variantAndClockSeqHigh;
+ uint8_t[6] node;
+};
+
+
+/*
+ *
+ * Audio streams
+ *
+ */
+
+/*
+ * Audio stream type describing the intented use case of a stream.
+ */
+@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
+enum AudioStreamType : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/AudioSystem.java
+ DEFAULT = -1,
+ MIN = 0,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be
+ // routed to speaker
+ DTMF = 8,
+ TTS = 9, // Transmitted Through Speaker. Plays over speaker
+ // only, silent on other devices
+ ACCESSIBILITY = 10, // For accessibility talk back prompts
+ REROUTING = 11, // For dynamic policy output mixes
+ PATCH = 12, // For internal audio flinger tracks. Fixed volume
+ PUBLIC_CNT = ACCESSIBILITY + 1,
+ // Number of streams considered by audio policy for volume and routing
+ FOR_POLICY_CNT = PATCH,
+ CNT = PATCH + 1
+};
+
+@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
+enum AudioSource : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/MediaRecorder.java,
+ // frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ // system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+ DEFAULT = 0,
+ MIC = 1,
+ VOICE_UPLINK = 2,
+ VOICE_DOWNLINK = 3,
+ VOICE_CALL = 4,
+ CAMCORDER = 5,
+ VOICE_RECOGNITION = 6,
+ VOICE_COMMUNICATION = 7,
+ /*
+ * Source for the mix to be presented remotely. An example of remote
+ * presentation is Wifi Display where a dongle attached to a TV can be used
+ * to play the mix captured by this audio source.
+ */
+ REMOTE_SUBMIX = 8,
+ /*
+ * Source for unprocessed sound. Usage examples include level measurement
+ * and raw signal analysis.
+ */
+ UNPROCESSED = 9,
+
+ CNT,
+ MAX = CNT - 1,
+ FM_TUNER = 1998,
+ /*
+ * A low-priority, preemptible audio source for for background software
+ * hotword detection. Same tuning as VOICE_RECOGNITION. Used only
+ * internally by the framework.
+ */
+ HOTWORD = 1999
+};
+
+typedef int32_t AudioSession;
+/*
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+ /*
+ * Session for effects attached to a particular output stream
+ * (value must be less than 0)
+ */
+ OUTPUT_STAGE = -1,
+ /*
+ * Session for effects applied to output mix. These effects can
+ * be moved by audio policy manager to another output stream
+ * (value must be 0)
+ */
+ OUTPUT_MIX = 0,
+ /*
+ * Application does not specify an explicit session ID to be used, and
+ * requests a new session ID to be allocated. Corresponds to
+ * AudioManager.AUDIO_SESSION_ID_GENERATE and
+ * AudioSystem.AUDIO_SESSION_ALLOCATE.
+ */
+ ALLOCATE = 0,
+ /*
+ * For use with AudioRecord::start(), this indicates no trigger session.
+ * It is also used with output tracks and patch tracks, which never have a
+ * session.
+ */
+ NONE = 0
+};
+
+/*
+ * Audio format is a 32-bit word that consists of:
+ * main format field (upper 8 bits)
+ * sub format field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field indicates
+ * options and parameters for each format. The sub format is mainly used for
+ * record to indicate for instance the requested bitrate or profile. It can
+ * also be used for certain formats to give informations not present in the
+ * encoded audio stream (e.g. octet alignement for AMR).
+ */
+@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
+enum AudioFormat : uint32_t {
+ INVALID = 0xFFFFFFFFUL,
+ DEFAULT = 0,
+ PCM = 0x00000000UL, /* DO NOT CHANGE */
+ MP3 = 0x01000000UL,
+ AMR_NB = 0x02000000UL,
+ AMR_WB = 0x03000000UL,
+ AAC = 0x04000000UL,
+ HE_AAC_V1 = 0x05000000UL, /* Deprecated, Use AAC_HE_V1*/
+ HE_AAC_V2 = 0x06000000UL, /* Deprecated, Use AAC_HE_V2*/
+ VORBIS = 0x07000000UL,
+ OPUS = 0x08000000UL,
+ AC3 = 0x09000000UL,
+ E_AC3 = 0x0A000000UL,
+ DTS = 0x0B000000UL,
+ DTS_HD = 0x0C000000UL,
+ // IEC61937 is encoded audio wrapped in 16-bit PCM.
+ IEC61937 = 0x0D000000UL,
+ DOLBY_TRUEHD = 0x0E000000UL,
+ EVRC = 0x10000000UL,
+ EVRCB = 0x11000000UL,
+ EVRCWB = 0x12000000UL,
+ EVRCNW = 0x13000000UL,
+ AAC_ADIF = 0x14000000UL,
+ WMA = 0x15000000UL,
+ WMA_PRO = 0x16000000UL,
+ AMR_WB_PLUS = 0x17000000UL,
+ MP2 = 0x18000000UL,
+ QCELP = 0x19000000UL,
+ DSD = 0x1A000000UL,
+ FLAC = 0x1B000000UL,
+ ALAC = 0x1C000000UL,
+ APE = 0x1D000000UL,
+ AAC_ADTS = 0x1E000000UL,
+ SBC = 0x1F000000UL,
+ APTX = 0x20000000UL,
+ APTX_HD = 0x21000000UL,
+ AC4 = 0x22000000UL,
+ LDAC = 0x23000000UL,
+ MAIN_MASK = 0xFF000000UL, /* Deprecated */
+ SUB_MASK = 0x00FFFFFFUL,
+
+ /* Subformats */
+ PCM_SUB_16_BIT = 0x1, // PCM signed 16 bits
+ PCM_SUB_8_BIT = 0x2, // PCM unsigned 8 bits
+ PCM_SUB_32_BIT = 0x3, // PCM signed .31 fixed point
+ PCM_SUB_8_24_BIT = 0x4, // PCM signed 8.23 fixed point
+ PCM_SUB_FLOAT = 0x5, // PCM single-precision float pt
+ PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
+
+ MP3_SUB_NONE = 0x0,
+
+ AMR_SUB_NONE = 0x0,
+
+ AAC_SUB_MAIN = 0x1,
+ AAC_SUB_LC = 0x2,
+ AAC_SUB_SSR = 0x4,
+ AAC_SUB_LTP = 0x8,
+ AAC_SUB_HE_V1 = 0x10,
+ AAC_SUB_SCALABLE = 0x20,
+ AAC_SUB_ERLC = 0x40,
+ AAC_SUB_LD = 0x80,
+ AAC_SUB_HE_V2 = 0x100,
+ AAC_SUB_ELD = 0x200,
+
+ VORBIS_SUB_NONE = 0x0,
+
+ /* Aliases */
+ /* note != AudioFormat.ENCODING_PCM_16BIT */
+ PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
+ /* note != AudioFormat.ENCODING_PCM_8BIT */
+ PCM_8_BIT = (PCM | PCM_SUB_8_BIT),
+ PCM_32_BIT = (PCM | PCM_SUB_32_BIT),
+ PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT),
+ PCM_FLOAT = (PCM | PCM_SUB_FLOAT),
+ PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED),
+ AAC_MAIN = (AAC | AAC_SUB_MAIN),
+ AAC_LC = (AAC | AAC_SUB_LC),
+ AAC_SSR = (AAC | AAC_SUB_SSR),
+ AAC_LTP = (AAC | AAC_SUB_LTP),
+ AAC_HE_V1 = (AAC | AAC_SUB_HE_V1),
+ AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE),
+ AAC_ERLC = (AAC | AAC_SUB_ERLC),
+ AAC_LD = (AAC | AAC_SUB_LD),
+ AAC_HE_V2 = (AAC | AAC_SUB_HE_V2),
+ AAC_ELD = (AAC | AAC_SUB_ELD),
+ AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN),
+ AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC),
+ AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR),
+ AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP),
+ AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1),
+ AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE),
+ AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC),
+ AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD),
+ AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2),
+ AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD)
+};
+
+/*
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@export(name="")
+enum FixedChannelCount : int32_t {
+ FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
+ FCC_8 = 8 // This is typically due to audio mixer and resampler limitations
+};
+
+/*
+ * A channel mask per se only defines the presence or absence of a channel, not
+ * the order. See AUDIO_INTERLEAVE_* for the platform convention of order.
+ *
+ * AudioChannelMask is an opaque type and its internal layout should not be
+ * assumed as it may change in the future. Instead, always use functions
+ * to examine it.
+ *
+ * These are the current representations:
+ *
+ * REPRESENTATION_POSITION
+ * is a channel mask representation for position assignment. Each low-order
+ * bit corresponds to the spatial position of a transducer (output), or
+ * interpretation of channel (input). The user of a channel mask needs to
+ * know the context of whether it is for output or input. The constants
+ * OUT_* or IN_* apply to the bits portion. It is not permitted for no bits
+ * to be set.
+ *
+ * REPRESENTATION_INDEX
+ * is a channel mask representation for index assignment. Each low-order
+ * bit corresponds to a selected channel. There is no platform
+ * interpretation of the various bits. There is no concept of output or
+ * input. It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but
+ * this will not the be case in future revisions of the platform. Wherever there
+ * is an ambiguity between input and output that is currently resolved by
+ * checking the channel mask, the implementer should look for ways to fix it
+ * with additional information outside of the mask.
+ */
+@export(name="", value_prefix="AUDIO_CHANNEL_")
+enum AudioChannelMask : uint32_t {
+ REPRESENTATION_POSITION = 0, /* must be 0 for compatibility */
+ /* 1 is reserved for future use */
+ REPRESENTATION_INDEX = 2,
+ /* 3 is reserved for future use */
+
+ /* These can be a complete value of AudioChannelMask */
+ NONE = 0x0,
+ INVALID = 0xC0000000,
+
+ /*
+ * These can be the bits portion of an AudioChannelMask
+ * with representation REPRESENTATION_POSITION.
+ */
+
+ /* output channels */
+ OUT_FRONT_LEFT = 0x1,
+ OUT_FRONT_RIGHT = 0x2,
+ OUT_FRONT_CENTER = 0x4,
+ OUT_LOW_FREQUENCY = 0x8,
+ OUT_BACK_LEFT = 0x10,
+ OUT_BACK_RIGHT = 0x20,
+ OUT_FRONT_LEFT_OF_CENTER = 0x40,
+ OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+ OUT_BACK_CENTER = 0x100,
+ OUT_SIDE_LEFT = 0x200,
+ OUT_SIDE_RIGHT = 0x400,
+ OUT_TOP_CENTER = 0x800,
+ OUT_TOP_FRONT_LEFT = 0x1000,
+ OUT_TOP_FRONT_CENTER = 0x2000,
+ OUT_TOP_FRONT_RIGHT = 0x4000,
+ OUT_TOP_BACK_LEFT = 0x8000,
+ OUT_TOP_BACK_CENTER = 0x10000,
+ OUT_TOP_BACK_RIGHT = 0x20000,
+
+ OUT_MONO = OUT_FRONT_LEFT,
+ OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+ OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+ OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT),
+ OUT_QUAD_BACK = OUT_QUAD,
+ /* like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+ OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_BACK_CENTER),
+ OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+ OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT),
+ OUT_5POINT1_BACK = OUT_5POINT1,
+ /* like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+ OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT |
+ OUT_BACK_CENTER),
+ /* matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
+ OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_ALL = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+ OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+ OUT_BACK_LEFT | OUT_BACK_RIGHT |
+ OUT_FRONT_LEFT_OF_CENTER | OUT_FRONT_RIGHT_OF_CENTER |
+ OUT_BACK_CENTER |
+ OUT_SIDE_LEFT | OUT_SIDE_RIGHT |
+ OUT_TOP_CENTER |
+ OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_CENTER | OUT_TOP_FRONT_RIGHT |
+ OUT_TOP_BACK_LEFT | OUT_TOP_BACK_CENTER | OUT_TOP_BACK_RIGHT),
+
+ /* These are bits only, not complete values */
+
+ /* input channels */
+ IN_LEFT = 0x4,
+ IN_RIGHT = 0x8,
+ IN_FRONT = 0x10,
+ IN_BACK = 0x20,
+ IN_LEFT_PROCESSED = 0x40,
+ IN_RIGHT_PROCESSED = 0x80,
+ IN_FRONT_PROCESSED = 0x100,
+ IN_BACK_PROCESSED = 0x200,
+ IN_PRESSURE = 0x400,
+ IN_X_AXIS = 0x800,
+ IN_Y_AXIS = 0x1000,
+ IN_Z_AXIS = 0x2000,
+ IN_VOICE_UPLINK = 0x4000,
+ IN_VOICE_DNLINK = 0x8000,
+
+ IN_MONO = IN_FRONT,
+ IN_STEREO = (IN_LEFT | IN_RIGHT),
+ IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+ IN_6 = (IN_LEFT | IN_RIGHT |
+ IN_FRONT | IN_BACK |
+ IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
+ IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+ IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+ IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO |
+ IN_VOICE_DNLINK_MONO),
+ IN_ALL = (IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK|
+ IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED |
+ IN_FRONT_PROCESSED | IN_BACK_PROCESSED|
+ IN_PRESSURE |
+ IN_X_AXIS | IN_Y_AXIS | IN_Z_AXIS |
+ IN_VOICE_UPLINK | IN_VOICE_DNLINK),
+
+ COUNT_MAX = 30,
+ INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX,
+ INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
+ INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
+ INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
+ INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
+ INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
+ INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
+ INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
+ INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1)
+};
+
+
+/*
+ * Expresses the convention when stereo audio samples are stored interleaved
+ * in an array. This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit to most
+ * significant channel mask bit, with unused bits skipped. Any exceptions
+ * to this convention will be noted at the appropriate API.
+ */
+@export(name="", value_prefix="AUDIO_INTERLEAVE_")
+enum AudioInterleave : int32_t {
+ LEFT = 0,
+ RIGHT = 1,
+};
+
+/*
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+ INVALID = -2,
+ CURRENT = -1,
+ NORMAL = 0,
+ RINGTONE = 1,
+ IN_CALL = 2,
+ IN_COMMUNICATION = 3,
+
+ CNT,
+ MAX = CNT - 1,
+};
+
+@export(name="", value_prefix="AUDIO_DEVICE_")
+enum AudioDevice : uint32_t {
+ NONE = 0x0,
+ /* reserved bits */
+ BIT_IN = 0x80000000,
+ BIT_DEFAULT = 0x40000000,
+ /* output devices */
+ OUT_EARPIECE = 0x1,
+ OUT_SPEAKER = 0x2,
+ OUT_WIRED_HEADSET = 0x4,
+ OUT_WIRED_HEADPHONE = 0x8,
+ OUT_BLUETOOTH_SCO = 0x10,
+ OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ OUT_BLUETOOTH_A2DP = 0x80,
+ OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ OUT_AUX_DIGITAL = 0x400,
+ OUT_HDMI = OUT_AUX_DIGITAL,
+ /* uses an analog connection (multiplexed over the USB pins for instance) */
+ OUT_ANLG_DOCK_HEADSET = 0x800,
+ OUT_DGTL_DOCK_HEADSET = 0x1000,
+ /* USB accessory mode: Android device is USB device and dock is USB host */
+ OUT_USB_ACCESSORY = 0x2000,
+ /* USB host mode: Android device is USB host and dock is USB device */
+ OUT_USB_DEVICE = 0x4000,
+ OUT_REMOTE_SUBMIX = 0x8000,
+ /* Telephony voice TX path */
+ OUT_TELEPHONY_TX = 0x10000,
+ /* Analog jack with line impedance detected */
+ OUT_LINE = 0x20000,
+ /* HDMI Audio Return Channel */
+ OUT_HDMI_ARC = 0x40000,
+ /* S/PDIF out */
+ OUT_SPDIF = 0x80000,
+ /* FM transmitter out */
+ OUT_FM = 0x100000,
+ /* Line out for av devices */
+ OUT_AUX_LINE = 0x200000,
+ /* limited-output speaker device for acoustic safety */
+ OUT_SPEAKER_SAFE = 0x400000,
+ OUT_IP = 0x800000,
+ /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
+ OUT_BUS = 0x1000000,
+ OUT_PROXY = 0x2000000,
+ OUT_USB_HEADSET = 0x4000000,
+ OUT_DEFAULT = BIT_DEFAULT,
+ OUT_ALL = (OUT_EARPIECE |
+ OUT_SPEAKER |
+ OUT_WIRED_HEADSET |
+ OUT_WIRED_HEADPHONE |
+ OUT_BLUETOOTH_SCO |
+ OUT_BLUETOOTH_SCO_HEADSET |
+ OUT_BLUETOOTH_SCO_CARKIT |
+ OUT_BLUETOOTH_A2DP |
+ OUT_BLUETOOTH_A2DP_HEADPHONES |
+ OUT_BLUETOOTH_A2DP_SPEAKER |
+ OUT_HDMI |
+ OUT_ANLG_DOCK_HEADSET |
+ OUT_DGTL_DOCK_HEADSET |
+ OUT_USB_ACCESSORY |
+ OUT_USB_DEVICE |
+ OUT_REMOTE_SUBMIX |
+ OUT_TELEPHONY_TX |
+ OUT_LINE |
+ OUT_HDMI_ARC |
+ OUT_SPDIF |
+ OUT_FM |
+ OUT_AUX_LINE |
+ OUT_SPEAKER_SAFE |
+ OUT_IP |
+ OUT_BUS |
+ OUT_PROXY |
+ OUT_USB_HEADSET |
+ OUT_DEFAULT),
+ OUT_ALL_A2DP = (OUT_BLUETOOTH_A2DP |
+ OUT_BLUETOOTH_A2DP_HEADPHONES |
+ OUT_BLUETOOTH_A2DP_SPEAKER),
+ OUT_ALL_SCO = (OUT_BLUETOOTH_SCO |
+ OUT_BLUETOOTH_SCO_HEADSET |
+ OUT_BLUETOOTH_SCO_CARKIT),
+ OUT_ALL_USB = (OUT_USB_ACCESSORY | OUT_USB_DEVICE | OUT_USB_HEADSET),
+ /* input devices */
+ IN_COMMUNICATION = BIT_IN | 0x1,
+ IN_AMBIENT = BIT_IN | 0x2,
+ IN_BUILTIN_MIC = BIT_IN | 0x4,
+ IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
+ IN_WIRED_HEADSET = BIT_IN | 0x10,
+ IN_AUX_DIGITAL = BIT_IN | 0x20,
+ IN_HDMI = IN_AUX_DIGITAL,
+ /* Telephony voice RX path */
+ IN_VOICE_CALL = BIT_IN | 0x40,
+ IN_TELEPHONY_RX = IN_VOICE_CALL,
+ IN_BACK_MIC = BIT_IN | 0x80,
+ IN_REMOTE_SUBMIX = BIT_IN | 0x100,
+ IN_ANLG_DOCK_HEADSET = BIT_IN | 0x200,
+ IN_DGTL_DOCK_HEADSET = BIT_IN | 0x400,
+ IN_USB_ACCESSORY = BIT_IN | 0x800,
+ IN_USB_DEVICE = BIT_IN | 0x1000,
+ /* FM tuner input */
+ IN_FM_TUNER = BIT_IN | 0x2000,
+ /* TV tuner input */
+ IN_TV_TUNER = BIT_IN | 0x4000,
+ /* Analog jack with line impedance detected */
+ IN_LINE = BIT_IN | 0x8000,
+ /* S/PDIF in */
+ IN_SPDIF = BIT_IN | 0x10000,
+ IN_BLUETOOTH_A2DP = BIT_IN | 0x20000,
+ IN_LOOPBACK = BIT_IN | 0x40000,
+ IN_IP = BIT_IN | 0x80000,
+ /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
+ IN_BUS = BIT_IN | 0x100000,
+ IN_PROXY = BIT_IN | 0x1000000,
+ IN_USB_HEADSET = BIT_IN | 0x2000000,
+ IN_DEFAULT = BIT_IN | BIT_DEFAULT,
+
+ IN_ALL = (IN_COMMUNICATION |
+ IN_AMBIENT |
+ IN_BUILTIN_MIC |
+ IN_BLUETOOTH_SCO_HEADSET |
+ IN_WIRED_HEADSET |
+ IN_HDMI |
+ IN_TELEPHONY_RX |
+ IN_BACK_MIC |
+ IN_REMOTE_SUBMIX |
+ IN_ANLG_DOCK_HEADSET |
+ IN_DGTL_DOCK_HEADSET |
+ IN_USB_ACCESSORY |
+ IN_USB_DEVICE |
+ IN_FM_TUNER |
+ IN_TV_TUNER |
+ IN_LINE |
+ IN_SPDIF |
+ IN_BLUETOOTH_A2DP |
+ IN_LOOPBACK |
+ IN_IP |
+ IN_BUS |
+ IN_PROXY |
+ IN_USB_HEADSET |
+ IN_DEFAULT),
+ IN_ALL_SCO = IN_BLUETOOTH_SCO_HEADSET,
+ IN_ALL_USB = (IN_USB_ACCESSORY | IN_USB_DEVICE | IN_USB_HEADSET),
+};
+
+/*
+ * The audio output flags serve two purposes:
+ *
+ * - when an AudioTrack is created they indicate a "wish" to be connected to an
+ * output stream with attributes corresponding to the specified flags;
+ *
+ * - when present in an output profile descriptor listed for a particular audio
+ * hardware module, they indicate that an output stream can be opened that
+ * supports the attributes indicated by the flags.
+ *
+ * The audio policy manager will try to match the flags in the request
+ * (when getOuput() is called) to an available output stream.
+ */
+@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
+enum AudioOutputFlag : int32_t {
+ NONE = 0x0, // no attributes
+ DIRECT = 0x1, // this output directly connects a track
+ // to one output stream: no software mixer
+ PRIMARY = 0x2, // this output is the primary output of the device. It is
+ // unique and must be present. It is opened by default and
+ // receives routing, audio mode and volume controls related
+ // to voice calls.
+ FAST = 0x4, // output supports "fast tracks", defined elsewhere
+ DEEP_BUFFER = 0x8, // use deep audio buffers
+ COMPRESS_OFFLOAD = 0x10, // offload playback of compressed streams to
+ // hardware codec
+ NON_BLOCKING = 0x20, // use non-blocking write
+ HW_AV_SYNC = 0x40, // output uses a hardware A/V sync
+ TTS = 0x80, // output for streams transmitted through speaker at a
+ // sample rate high enough to accommodate lower-range
+ // ultrasonic p/b
+ RAW = 0x100, // minimize signal processing
+ SYNC = 0x200, // synchronize I/O streams
+ IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
+ // data bursts, not PCM.
+ DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs
+ // to pass through compress path for DSP post proc.
+ MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+ VOIP_RX = 0x8000, // preferred output for VoIP calls.
+};
+
+/*
+ * The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
+enum AudioInputFlag : int32_t {
+ NONE = 0x0, // no attributes
+ FAST = 0x1, // prefer an input that supports "fast tracks"
+ HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
+ RAW = 0x4, // minimize signal processing
+ SYNC = 0x8, // synchronize I/O streams
+ MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+ VOIP_TX = 0x20, // preferred input for VoIP calls.
+};
+
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+ // These values must kept in sync with
+ // frameworks/base/media/java/android/media/AudioAttributes.java
+ UNKNOWN = 0,
+ MEDIA = 1,
+ VOICE_COMMUNICATION = 2,
+ VOICE_COMMUNICATION_SIGNALLING = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ NOTIFICATION_TELEPHONY_RINGTONE = 6,
+ NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ NOTIFICATION_EVENT = 10,
+ ASSISTANCE_ACCESSIBILITY = 11,
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ ASSISTANCE_SONIFICATION = 13,
+ GAME = 14,
+ VIRTUAL_SOURCE = 15,
+ ASSISTANT = 16,
+
+ CNT,
+ MAX = CNT - 1,
+};
+
+/*
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+ uint32_t sampleRateHz;
+ AudioChannelMask channelMask;
+ AudioFormat format;
+ AudioStreamType streamType;
+ uint32_t bitRatePerSecond;
+ int64_t durationMicroseconds; // -1 if unknown
+ bool hasVideo;
+ bool isStreaming;
+ uint32_t bitWidth;
+ uint32_t bufferSize;
+ AudioUsage usage;
+};
+
+/*
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+ uint32_t sampleRateHz;
+ AudioChannelMask channelMask;
+ AudioFormat format;
+ AudioOffloadInfo offloadInfo;
+ uint64_t frameCount;
+};
+
+
+/*
+ *
+ * Volume control
+ *
+ */
+
+/*
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+ JOINT = 0x1, // supports joint channel gain control
+ CHANNELS = 0x2, // supports separate channel gain control
+ RAMP = 0x4 // supports gain ramps
+};
+
+/*
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+ AudioGainMode mode;
+ AudioChannelMask channelMask; // channels which gain an be controlled
+ int32_t minValue; // minimum gain value in millibels
+ int32_t maxValue; // maximum gain value in millibels
+ int32_t defaultValue; // default gain value in millibels
+ uint32_t stepValue; // gain step in millibels
+ uint32_t minRampMs; // minimum ramp duration in ms
+ uint32_t maxRampMs; // maximum ramp duration in ms
+};
+
+/*
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+ int32_t index; // index of the corresponding AudioGain in AudioPort.gains
+ AudioGainMode mode;
+ AudioChannelMask channelMask; // channels which gain value follows
+ /*
+ * 4 = sizeof(AudioChannelMask),
+ * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
+ * Gain values in millibels for each channel ordered from LSb to MSb in
+ * channel mask. The number of values is 1 in joint mode or
+ * popcount(channel_mask).
+ */
+ int32_t[4 * 8] values;
+ uint32_t rampDurationMs; // ramp duration in ms
+};
+
+
+/*
+ *
+ * Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface.
+ */
+
+/* Audio port role: either source or sink */
+@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
+enum AudioPortRole : int32_t {
+ NONE,
+ SOURCE,
+ SINK,
+};
+
+/*
+ * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
+ * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ */
+@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
+enum AudioPortType : int32_t {
+ NONE,
+ DEVICE,
+ MIX,
+ SESSION,
+};
+
+/*
+ * Extension for audio port configuration structure when the audio port is a
+ * hardware device.
+ */
+struct AudioPortConfigDeviceExt {
+ AudioModuleHandle hwModule; // module the device is attached to
+ AudioDevice type; // device type (e.g OUT_SPEAKER)
+ uint8_t[32] address; // device address. "" if N/A
+};
+
+/*
+ * Extension for audio port configuration structure when the audio port is an
+ * audio session.
+ */
+struct AudioPortConfigSessionExt {
+ AudioSession session;
+};
+
+/*
+ * Flags indicating which fields are to be considered in AudioPortConfig.
+ */
+@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
+enum AudioPortConfigMask : uint32_t {
+ SAMPLE_RATE = 0x1,
+ CHANNEL_MASK = 0x2,
+ FORMAT = 0x4,
+ GAIN = 0x8,
+ ALL = SAMPLE_RATE | CHANNEL_MASK | FORMAT | GAIN
+};
+
+/*
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+ AudioPortHandle id;
+ AudioPortConfigMask configMask;
+ uint32_t sampleRateHz;
+ AudioChannelMask channelMask;
+ AudioFormat format;
+ AudioGainConfig gain;
+ AudioPortType type; // type is used as a discriminator for Ext union
+ AudioPortRole role; // role is used as a discriminator for UseCase union
+ union Ext {
+ AudioPortConfigDeviceExt device;
+ struct AudioPortConfigMixExt {
+ AudioModuleHandle hwModule; // module the stream is attached to
+ AudioIoHandle ioHandle; // I/O handle of the input/output stream
+ union UseCase {
+ AudioStreamType stream;
+ AudioSource source;
+ } useCase;
+ } mix;
+ AudioPortConfigSessionExt session;
+ } ext;
+};
+
+/*
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+struct AudioPortDeviceExt {
+ AudioModuleHandle hwModule; // module the device is attached to
+ AudioDevice type;
+ uint8_t[32] address;
+};
+
+/*
+ * Latency class of the audio mix.
+ */
+@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
+enum AudioMixLatencyClass : int32_t {
+ LOW,
+ NORMAL
+} ;
+
+struct AudioPortMixExt {
+ AudioModuleHandle hwModule; // module the stream is attached to
+ AudioIoHandle ioHandle; // I/O handle of the stream
+ AudioMixLatencyClass latencyClass;
+};
+
+/*
+ * Extension for audio port structure when the audio port is an audio session.
+ */
+struct AudioPortSessionExt {
+ AudioSession session;
+};
+
+struct AudioPort {
+ AudioPortHandle id;
+ AudioPortRole role;
+ string name;
+ vec<uint32_t> sampleRates;
+ vec<AudioChannelMask> channelMasks;
+ vec<AudioFormat> formats;
+ vec<AudioGain> gains;
+ AudioPortConfig activeConfig; // current audio port configuration
+ AudioPortType type; // type is used as a discriminator
+ union Ext {
+ AudioPortDeviceExt device;
+ AudioPortMixExt mix;
+ AudioPortSessionExt session;
+ } ext;
+};
+
+struct ThreadInfo {
+ int64_t pid;
+ int64_t tid;
+};
diff --git a/audio/common/Android.mk b/audio/common/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/audio/common/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/audio/effect/2.0/Android.bp b/audio/effect/2.0/Android.bp
new file mode 100644
index 0000000..83a702a
--- /dev/null
+++ b/audio/effect/2.0/Android.bp
@@ -0,0 +1,155 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.audio.effect@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IAcousticEchoCancelerEffect.hal",
+ "IAutomaticGainControlEffect.hal",
+ "IBassBoostEffect.hal",
+ "IDownmixEffect.hal",
+ "IEffect.hal",
+ "IEffectBufferProviderCallback.hal",
+ "IEffectsFactory.hal",
+ "IEnvironmentalReverbEffect.hal",
+ "IEqualizerEffect.hal",
+ "ILoudnessEnhancerEffect.hal",
+ "INoiseSuppressionEffect.hal",
+ "IPresetReverbEffect.hal",
+ "IVirtualizerEffect.hal",
+ "IVisualizerEffect.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio.effect@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.effect@2.0",
+ srcs: [
+ ":android.hardware.audio.effect@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/effect/2.0/types.cpp",
+ "android/hardware/audio/effect/2.0/AcousticEchoCancelerEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/AutomaticGainControlEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/BassBoostEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/DownmixEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/EffectAll.cpp",
+ "android/hardware/audio/effect/2.0/EffectBufferProviderCallbackAll.cpp",
+ "android/hardware/audio/effect/2.0/EffectsFactoryAll.cpp",
+ "android/hardware/audio/effect/2.0/EnvironmentalReverbEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/EqualizerEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/LoudnessEnhancerEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/NoiseSuppressionEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/PresetReverbEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/VirtualizerEffectAll.cpp",
+ "android/hardware/audio/effect/2.0/VisualizerEffectAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.audio.effect@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.effect@2.0",
+ srcs: [
+ ":android.hardware.audio.effect@2.0_hal",
+ ],
+ out: [
+ "android/hardware/audio/effect/2.0/types.h",
+ "android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h",
+ "android/hardware/audio/effect/2.0/IHwAcousticEchoCancelerEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwAcousticEchoCancelerEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwAcousticEchoCancelerEffect.h",
+ "android/hardware/audio/effect/2.0/BsAcousticEchoCancelerEffect.h",
+ "android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h",
+ "android/hardware/audio/effect/2.0/IHwAutomaticGainControlEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwAutomaticGainControlEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwAutomaticGainControlEffect.h",
+ "android/hardware/audio/effect/2.0/BsAutomaticGainControlEffect.h",
+ "android/hardware/audio/effect/2.0/IBassBoostEffect.h",
+ "android/hardware/audio/effect/2.0/IHwBassBoostEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwBassBoostEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwBassBoostEffect.h",
+ "android/hardware/audio/effect/2.0/BsBassBoostEffect.h",
+ "android/hardware/audio/effect/2.0/IDownmixEffect.h",
+ "android/hardware/audio/effect/2.0/IHwDownmixEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwDownmixEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwDownmixEffect.h",
+ "android/hardware/audio/effect/2.0/BsDownmixEffect.h",
+ "android/hardware/audio/effect/2.0/IEffect.h",
+ "android/hardware/audio/effect/2.0/IHwEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwEffect.h",
+ "android/hardware/audio/effect/2.0/BsEffect.h",
+ "android/hardware/audio/effect/2.0/IEffectBufferProviderCallback.h",
+ "android/hardware/audio/effect/2.0/IHwEffectBufferProviderCallback.h",
+ "android/hardware/audio/effect/2.0/BnHwEffectBufferProviderCallback.h",
+ "android/hardware/audio/effect/2.0/BpHwEffectBufferProviderCallback.h",
+ "android/hardware/audio/effect/2.0/BsEffectBufferProviderCallback.h",
+ "android/hardware/audio/effect/2.0/IEffectsFactory.h",
+ "android/hardware/audio/effect/2.0/IHwEffectsFactory.h",
+ "android/hardware/audio/effect/2.0/BnHwEffectsFactory.h",
+ "android/hardware/audio/effect/2.0/BpHwEffectsFactory.h",
+ "android/hardware/audio/effect/2.0/BsEffectsFactory.h",
+ "android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h",
+ "android/hardware/audio/effect/2.0/IHwEnvironmentalReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwEnvironmentalReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwEnvironmentalReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BsEnvironmentalReverbEffect.h",
+ "android/hardware/audio/effect/2.0/IEqualizerEffect.h",
+ "android/hardware/audio/effect/2.0/IHwEqualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwEqualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwEqualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BsEqualizerEffect.h",
+ "android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h",
+ "android/hardware/audio/effect/2.0/IHwLoudnessEnhancerEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwLoudnessEnhancerEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwLoudnessEnhancerEffect.h",
+ "android/hardware/audio/effect/2.0/BsLoudnessEnhancerEffect.h",
+ "android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h",
+ "android/hardware/audio/effect/2.0/IHwNoiseSuppressionEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwNoiseSuppressionEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwNoiseSuppressionEffect.h",
+ "android/hardware/audio/effect/2.0/BsNoiseSuppressionEffect.h",
+ "android/hardware/audio/effect/2.0/IPresetReverbEffect.h",
+ "android/hardware/audio/effect/2.0/IHwPresetReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwPresetReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwPresetReverbEffect.h",
+ "android/hardware/audio/effect/2.0/BsPresetReverbEffect.h",
+ "android/hardware/audio/effect/2.0/IVirtualizerEffect.h",
+ "android/hardware/audio/effect/2.0/IHwVirtualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwVirtualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwVirtualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BsVirtualizerEffect.h",
+ "android/hardware/audio/effect/2.0/IVisualizerEffect.h",
+ "android/hardware/audio/effect/2.0/IHwVisualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BnHwVisualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BpHwVisualizerEffect.h",
+ "android/hardware/audio/effect/2.0/BsVisualizerEffect.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.audio.effect@2.0",
+ generated_sources: ["android.hardware.audio.effect@2.0_genc++"],
+ generated_headers: ["android.hardware.audio.effect@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.audio.effect@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/audio/effect/2.0/Android.mk b/audio/effect/2.0/Android.mk
new file mode 100644
index 0000000..d71255e
--- /dev/null
+++ b/audio/effect/2.0/Android.mk
@@ -0,0 +1,53 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio.effect@2.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/audio/effect/V2_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IAcousticEchoCancelerEffect.hal
+$(GEN): $(LOCAL_PATH)/IAutomaticGainControlEffect.hal
+$(GEN): $(LOCAL_PATH)/IBassBoostEffect.hal
+$(GEN): $(LOCAL_PATH)/IDownmixEffect.hal
+$(GEN): $(LOCAL_PATH)/IEffect.hal
+$(GEN): $(LOCAL_PATH)/IEffectBufferProviderCallback.hal
+$(GEN): $(LOCAL_PATH)/IEffectsFactory.hal
+$(GEN): $(LOCAL_PATH)/IEnvironmentalReverbEffect.hal
+$(GEN): $(LOCAL_PATH)/IEqualizerEffect.hal
+$(GEN): $(LOCAL_PATH)/ILoudnessEnhancerEffect.hal
+$(GEN): $(LOCAL_PATH)/INoiseSuppressionEffect.hal
+$(GEN): $(LOCAL_PATH)/IPresetReverbEffect.hal
+$(GEN): $(LOCAL_PATH)/IVirtualizerEffect.hal
+$(GEN): $(LOCAL_PATH)/IVisualizerEffect.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.audio.effect@2.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/effect/2.0/IAcousticEchoCancelerEffect.hal b/audio/effect/2.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..9e2e0c3
--- /dev/null
+++ b/audio/effect/2.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+ /*
+ * Sets echo delay value in milliseconds.
+ */
+ setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+ /*
+ * Gets echo delay value in milliseconds.
+ */
+ getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/2.0/IAutomaticGainControlEffect.hal b/audio/effect/2.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..a02002d
--- /dev/null
+++ b/audio/effect/2.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+ /*
+ * Sets target level in millibels.
+ */
+ setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+ /*
+ * Gets target level.
+ */
+ getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+ /*
+ * Sets gain in the compression range in millibels.
+ */
+ setCompGain(int16_t compGainMb) generates (Result retval);
+
+ /*
+ * Gets gain in the compression range.
+ */
+ getCompGain() generates (Result retval, int16_t compGainMb);
+
+ /*
+ * Enables or disables limiter.
+ */
+ setLimiterEnabled(bool enabled) generates (Result retval);
+
+ /*
+ * Returns whether limiter is enabled.
+ */
+ isLimiterEnabled() generates (Result retval, bool enabled);
+
+ struct AllProperties {
+ int16_t targetLevelMb;
+ int16_t compGainMb;
+ bool limiterEnabled;
+ };
+
+ /*
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /*
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/2.0/IBassBoostEffect.hal b/audio/effect/2.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..bcf7b7d
--- /dev/null
+++ b/audio/effect/2.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+ /*
+ * Returns whether setting bass boost strength is supported.
+ */
+ isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /*
+ * Sets bass boost strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /*
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/2.0/IDownmixEffect.hal b/audio/effect/2.0/IDownmixEffect.hal
new file mode 100644
index 0000000..06409a3
--- /dev/null
+++ b/audio/effect/2.0/IDownmixEffect.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+ enum Type : int32_t {
+ STRIP, // throw away the extra channels
+ FOLD // mix the extra channels with FL/FR
+ };
+
+ setType(Type preset) generates (Result retval);
+
+ getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/2.0/IEffect.hal b/audio/effect/2.0/IEffect.hal
new file mode 100644
index 0000000..d254e8c
--- /dev/null
+++ b/audio/effect/2.0/IEffect.hal
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+ /*
+ * Initialize effect engine--all configurations return to default.
+ *
+ * @return retval operation completion status.
+ */
+ @entry
+ @callflow(next={"*"})
+ init() generates (Result retval);
+
+ /*
+ * Apply new audio parameters configurations for input and output buffers.
+ * The provider callbacks may be empty, but in this case the buffer
+ * must be provided in the EffectConfig structure.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setConfig(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /*
+ * Reset the effect engine. Keep configuration but resets state and buffer
+ * content.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ reset() generates (Result retval);
+
+ /*
+ * Enable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"prepareForProcessing"})
+ enable() generates (Result retval);
+
+ /*
+ * Disable processing.
+ *
+ * @return retval operation completion status.
+ */
+ @callflow(next={"close"})
+ disable() generates (Result retval);
+
+ /*
+ * Set the rendering device the audio output path is connected to. The
+ * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+ * descriptor to receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the output chain.
+ *
+ * @param device output device specification.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setDevice(AudioDevice device) generates (Result retval);
+
+ /*
+ * Set and get volume. Used by audio framework to delegate volume control to
+ * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+ * flag in its descriptor to receive this command. The effect engine must
+ * return the volume that should be applied before the effect is
+ * processed. The overall volume (the volume actually applied by the effect
+ * engine multiplied by the returned value) should match the value indicated
+ * in the command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return result updated volume values.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setAndGetVolume(vec<uint32_t> volumes)
+ generates (Result retval, vec<uint32_t> result);
+
+ /*
+ * Notify the effect of the volume change. The effect implementation must
+ * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+ * command.
+ *
+ * @param volumes vector containing volume for each channel defined in
+ * EffectConfig for output buffer expressed in 8.24 fixed
+ * point format.
+ * @return retval operation completion status.
+ */
+ volumeChangeNotification(vec<uint32_t> volumes)
+ generates (Result retval);
+
+ /*
+ * Set the audio mode. The effect implementation must set
+ * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+ * when the audio mode changes.
+ *
+ * @param mode desired audio mode.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setAudioMode(AudioMode mode) generates (Result retval);
+
+ /*
+ * Apply new audio parameters configurations for input and output buffers of
+ * reverse stream. An example of reverse stream is the echo reference
+ * supplied to an Acoustic Echo Canceler.
+ *
+ * @param config configuration descriptor.
+ * @param inputBufferProvider optional buffer provider reference.
+ * @param outputBufferProvider optional buffer provider reference.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setConfigReverse(EffectConfig config,
+ IEffectBufferProviderCallback inputBufferProvider,
+ IEffectBufferProviderCallback outputBufferProvider)
+ generates (Result retval);
+
+ /*
+ * Set the capture device the audio input path is connected to. The effect
+ * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+ * receive this command when the device changes.
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param device input device specification.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setInputDevice(AudioDevice device) generates (Result retval);
+
+ /*
+ * Read audio parameters configurations for input and output buffers.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ @callflow(next={"*"})
+ getConfig() generates (Result retval, EffectConfig config);
+
+ /*
+ * Read audio parameters configurations for input and output buffers of
+ * reverse stream.
+ *
+ * @return retval operation completion status.
+ * @return config configuration descriptor.
+ */
+ @callflow(next={"*"})
+ getConfigReverse() generates (Result retval, EffectConfig config);
+
+ /*
+ * Queries for supported combinations of main and auxiliary channels
+ * (e.g. for a multi-microphone noise suppressor).
+ *
+ * @param maxConfigs maximum number of the combinations to return.
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+ * the number of supported combinations exceeds 'maxConfigs'.
+ * @return result list of configuration descriptors.
+ */
+ @callflow(next={"*"})
+ getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+ generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+ /*
+ * Retrieves the current configuration of main and auxiliary channels.
+ *
+ * @return retval absence of the feature support is indicated using
+ * NOT_SUPPORTED code.
+ * @return result configuration descriptor.
+ */
+ @callflow(next={"*"})
+ getAuxChannelsConfig()
+ generates (Result retval, EffectAuxChannelsConfig result);
+
+ /*
+ * Sets the current configuration of main and auxiliary channels.
+ *
+ * @return retval operation completion status; absence of the feature
+ * support is indicated using NOT_SUPPORTED code.
+ */
+ @callflow(next={"*"})
+ setAuxChannelsConfig(EffectAuxChannelsConfig config)
+ generates (Result retval);
+
+ /*
+ * Set the audio source the capture path is configured for (Camcorder, voice
+ * recognition...).
+ *
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
+ * @param source source descriptor.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setAudioSource(AudioSource source) generates (Result retval);
+
+ /*
+ * This command indicates if the playback thread the effect is attached to
+ * is offloaded or not, and updates the I/O handle of the playback thread
+ * the effect is attached to.
+ *
+ * @param param effect offload descriptor.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ offload(EffectOffloadParameter param) generates (Result retval);
+
+ /*
+ * Returns the effect descriptor.
+ *
+ * @return retval operation completion status.
+ * @return descriptor effect descriptor.
+ */
+ @callflow(next={"*"})
+ getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+ /*
+ * Set up required transports for passing audio buffers to the effect.
+ *
+ * The transport consists of shared memory and a message queue for reporting
+ * effect processing operation status. The shared memory is set up
+ * separately using 'setProcessBuffers' method.
+ *
+ * Processing is requested by setting 'REQUEST_PROCESS' or
+ * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+ * queue. The result of processing may be one of the following:
+ * OK if there were no errors during processing;
+ * INVALID_ARGUMENTS if audio buffers are invalid;
+ * INVALID_STATE if the engine has finished the disable phase;
+ * NOT_INITIALIZED if the audio buffers were not set;
+ * NOT_SUPPORTED if the requested processing type is not supported by
+ * the effect.
+ *
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queue.
+ * @return statusMQ a message queue used for passing status from the effect.
+ */
+ @callflow(next={"setProcessBuffers"})
+ prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
+
+ /*
+ * Set up input and output buffers for processing audio data. The effect
+ * may modify both the input and the output buffer during the operation.
+ * Buffers may be set multiple times during effect lifetime.
+ *
+ * The input and the output buffer may be reused between different effects,
+ * and the input buffer may be used as an output buffer. Buffers are
+ * distinguished using 'AudioBuffer.id' field.
+ *
+ * @param inBuffer input audio buffer.
+ * @param outBuffer output audio buffer.
+ * @return retval OK if both buffers were mapped successfully.
+ * INVALID_ARGUMENTS if there was a problem with mapping
+ * any of the buffers.
+ */
+ @callflow(next={"*"})
+ setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) generates (
+ Result retval);
+
+ /*
+ * Execute a vendor specific command on the effect. The command code
+ * and data, as well as result data are not interpreted by Android
+ * Framework and are passed as-is between the application and the effect.
+ *
+ * The effect must use standard POSIX.1-2001 error codes for the operation
+ * completion status.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param commandId the ID of the command.
+ * @param data command data.
+ * @param resultMaxSize maximum size in bytes of the result; can be 0.
+ * @return status command completion status.
+ * @return result result data.
+ */
+ command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+ generates (int32_t status, vec<uint8_t> result);
+
+ /*
+ * Set a vendor-specific parameter and apply it immediately. The parameter
+ * code and data are not interpreted by Android Framework and are passed
+ * as-is between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown or if provided parameter data is invalid. If the effect does not
+ * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param value the value of the parameter.
+ * @return retval operation completion status.
+ */
+ @callflow(next={"*"})
+ setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+ generates (Result retval);
+
+ /*
+ * Get a vendor-specific parameter value. The parameter code and returned
+ * data are not interpreted by Android Framework and are passed as-is
+ * between the application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+ * unknown. If the effect does not support setting vendor-specific
+ * parameters, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param parameter identifying data of the parameter.
+ * @param valueMaxSize maximum size in bytes of the value.
+ * @return retval operation completion status.
+ * @return result the value of the parameter.
+ */
+ @callflow(next={"*"})
+ getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+ generates (Result retval, vec<uint8_t> value);
+
+ /*
+ * Get supported configs for a vendor-specific feature. The configs returned
+ * are not interpreted by Android Framework and are passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific feature
+ * configs, it must return NOT_SUPPORTED. If the feature is supported but
+ * the total number of supported configurations exceeds the maximum number
+ * indicated by the caller, the method must return RESULT_TOO_BIG.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param maxConfigs maximum number of configs to return.
+ * @param configSize size of each config in bytes.
+ * @return retval operation completion status.
+ * @return configsCount number of configs returned.
+ * @return configsData data for all the configs returned.
+ */
+ @callflow(next={"*"})
+ getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize) generates (
+ Result retval,
+ uint32_t configsCount,
+ vec<uint8_t> configsData);
+
+ /*
+ * Get the current config for a vendor-specific feature. The config returned
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configSize size of the config in bytes.
+ * @return retval operation completion status.
+ * @return configData config data.
+ */
+ @callflow(next={"*"})
+ getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+ generates (Result retval, vec<uint8_t> configData);
+
+ /*
+ * Set the current config for a vendor-specific feature. The config data
+ * is not interpreted by Android Framework and is passed as-is between the
+ * application and the effect.
+ *
+ * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+ * unknown. If the effect does not support getting vendor-specific
+ * feature configs, it must return NOT_SUPPORTED.
+ *
+ * Use this method only if the effect is provided by a third party, and
+ * there is no interface defined for it. This method only works for effects
+ * implemented in software.
+ *
+ * @param featureId feature identifier.
+ * @param configData config data.
+ * @return retval operation completion status.
+ */
+ setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+ generates (Result retval);
+
+ /*
+ * Called by the framework to deinitialize the effect and free up
+ * all the currently allocated resources. It is recommended to close
+ * the effect on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * INVALID_STATE if the effect was already closed.
+ */
+ @exit
+ close() generates (Result retval);
+};
diff --git a/audio/effect/2.0/IEffectBufferProviderCallback.hal b/audio/effect/2.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..53f4d6e
--- /dev/null
+++ b/audio/effect/2.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+/*
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+ /*
+ * Called to retrieve a buffer where data should read from by 'process'
+ * function.
+ *
+ * @return buffer audio buffer for processing
+ */
+ getBuffer() generates (AudioBuffer buffer);
+
+ /*
+ * Called to provide a buffer with the data written by 'process' function.
+ *
+ * @param buffer audio buffer for processing
+ */
+ putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/2.0/IEffectsFactory.hal b/audio/effect/2.0/IEffectsFactory.hal
new file mode 100644
index 0000000..c82b4a2
--- /dev/null
+++ b/audio/effect/2.0/IEffectsFactory.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IEffectsFactory {
+ /*
+ * Returns descriptors of different effects in all loaded libraries.
+ *
+ * @return retval operation completion status.
+ * @return result list of effect descriptors.
+ */
+ getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+ /*
+ * Returns a descriptor of a particular effect.
+ *
+ * @return retval operation completion status.
+ * @return result effect descriptor.
+ */
+ getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+ /*
+ * Creates an effect engine of the specified type. To release the effect
+ * engine, it is necessary to release references to the returned effect
+ * object.
+ *
+ * @param uid effect uuid.
+ * @param session audio session to which this effect instance will be
+ * attached. All effects created with the same session ID
+ * are connected in series and process the same signal
+ * stream.
+ * @param ioHandle identifies the output or input stream this effect is
+ * directed to in audio HAL.
+ * @return retval operation completion status.
+ * @return result the interface for the created effect.
+ * @return effectId the unique ID of the effect to be used with
+ * IStream::addEffect and IStream::removeEffect methods.
+ */
+ createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+ generates (Result retval, IEffect result, uint64_t effectId);
+
+ /*
+ * Dumps information about effects into the provided file descriptor.
+ * This is used for the dumpsys facility.
+ *
+ * @param fd dump file descriptor.
+ */
+ debugDump(handle fd);
+};
diff --git a/audio/effect/2.0/IEnvironmentalReverbEffect.hal b/audio/effect/2.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..d9b1ee6
--- /dev/null
+++ b/audio/effect/2.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+ /*
+ * Sets whether the effect should be bypassed.
+ */
+ setBypass(bool bypass) generates (Result retval);
+
+ /*
+ * Gets whether the effect should be bypassed.
+ */
+ getBypass() generates (Result retval, bool bypass);
+
+ enum ParamRange : int16_t {
+ ROOM_LEVEL_MIN = -6000,
+ ROOM_LEVEL_MAX = 0,
+ ROOM_HF_LEVEL_MIN = -4000,
+ ROOM_HF_LEVEL_MAX = 0,
+ DECAY_TIME_MIN = 100,
+ DECAY_TIME_MAX = 20000,
+ DECAY_HF_RATIO_MIN = 100,
+ DECAY_HF_RATIO_MAX = 1000,
+ REFLECTIONS_LEVEL_MIN = -6000,
+ REFLECTIONS_LEVEL_MAX = 0,
+ REFLECTIONS_DELAY_MIN = 0,
+ REFLECTIONS_DELAY_MAX = 65,
+ REVERB_LEVEL_MIN = -6000,
+ REVERB_LEVEL_MAX = 0,
+ REVERB_DELAY_MIN = 0,
+ REVERB_DELAY_MAX = 65,
+ DIFFUSION_MIN = 0,
+ DIFFUSION_MAX = 1000,
+ DENSITY_MIN = 0,
+ DENSITY_MAX = 1000
+ };
+
+ /*
+ * Sets the room level.
+ */
+ setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+ /*
+ * Gets the room level.
+ */
+ getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+ /*
+ * Sets the room high frequences level.
+ */
+ setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+ /*
+ * Gets the room high frequences level.
+ */
+ getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+ /*
+ * Sets the room decay time.
+ */
+ setDecayTime(uint32_t decayTime) generates (Result retval);
+
+ /*
+ * Gets the room decay time.
+ */
+ getDecayTime() generates (Result retval, uint32_t decayTime);
+
+ /*
+ * Sets the ratio of high frequences decay.
+ */
+ setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+ /*
+ * Gets the ratio of high frequences decay.
+ */
+ getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+ /*
+ * Sets the level of reflections in the room.
+ */
+ setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+ /*
+ * Gets the level of reflections in the room.
+ */
+ getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+ /*
+ * Sets the reflections delay in the room.
+ */
+ setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+ /*
+ * Gets the reflections delay in the room.
+ */
+ getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+ /*
+ * Sets the reverb level of the room.
+ */
+ setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+ /*
+ * Gets the reverb level of the room.
+ */
+ getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+ /*
+ * Sets the reverb delay of the room.
+ */
+ setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+ /*
+ * Gets the reverb delay of the room.
+ */
+ getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+ /*
+ * Sets room diffusion.
+ */
+ setDiffusion(int16_t diffusion) generates (Result retval);
+
+ /*
+ * Gets room diffusion.
+ */
+ getDiffusion() generates (Result retval, int16_t diffusion);
+
+ /*
+ * Sets room wall density.
+ */
+ setDensity(int16_t density) generates (Result retval);
+
+ /*
+ * Gets room wall density.
+ */
+ getDensity() generates (Result retval, int16_t density);
+
+ struct AllProperties {
+ int16_t roomLevel; // in millibels, range -6000 to 0
+ int16_t roomHfLevel; // in millibels, range -4000 to 0
+ uint32_t decayTime; // in milliseconds, range 100 to 20000
+ int16_t decayHfRatio; // in permilles, range 100 to 1000
+ int16_t reflectionsLevel; // in millibels, range -6000 to 0
+ uint32_t reflectionsDelay; // in milliseconds, range 0 to 65
+ int16_t reverbLevel; // in millibels, range -6000 to 0
+ uint32_t reverbDelay; // in milliseconds, range 0 to 65
+ int16_t diffusion; // in permilles, range 0 to 1000
+ int16_t density; // in permilles, range 0 to 1000
+ };
+
+ /*
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /*
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/2.0/IEqualizerEffect.hal b/audio/effect/2.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..b8fa177
--- /dev/null
+++ b/audio/effect/2.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+ /*
+ * Gets the number of frequency bands that the equalizer supports.
+ */
+ getNumBands() generates (Result retval, uint16_t numBands);
+
+ /*
+ * Returns the minimum and maximum band levels supported.
+ */
+ getLevelRange()
+ generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+ /*
+ * Sets the gain for the given equalizer band.
+ */
+ setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+ /*
+ * Gets the gain for the given equalizer band.
+ */
+ getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+ /*
+ * Gets the center frequency of the given band, in milliHertz.
+ */
+ getBandCenterFrequency(uint16_t band)
+ generates (Result retval, uint32_t centerFreqmHz);
+
+ /*
+ * Gets the frequency range of the given frequency band, in milliHertz.
+ */
+ getBandFrequencyRange(uint16_t band)
+ generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+ /*
+ * Gets the band that has the most effect on the given frequency
+ * in milliHertz.
+ */
+ getBandForFrequency(uint32_t freqmHz)
+ generates (Result retval, uint16_t band);
+
+ /*
+ * Gets the names of all presets the equalizer supports.
+ */
+ getPresetNames() generates (Result retval, vec<string> names);
+
+ /*
+ * Sets the current preset using the index of the preset in the names
+ * vector returned via 'getPresetNames'.
+ */
+ setCurrentPreset(uint16_t preset) generates (Result retval);
+
+ /*
+ * Gets the current preset.
+ */
+ getCurrentPreset() generates (Result retval, uint16_t preset);
+
+ struct AllProperties {
+ uint16_t curPreset;
+ vec<int16_t> bandLevels;
+ };
+
+ /*
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /*
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/2.0/ILoudnessEnhancerEffect.hal b/audio/effect/2.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..3e1ee4e
--- /dev/null
+++ b/audio/effect/2.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+ /*
+ * Sets target gain expressed in millibels.
+ */
+ setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+ /*
+ * Gets target gain expressed in millibels.
+ */
+ getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/2.0/INoiseSuppressionEffect.hal b/audio/effect/2.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..ae2bfb5
--- /dev/null
+++ b/audio/effect/2.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+ enum Level : int32_t {
+ LOW,
+ MEDIUM,
+ HIGH
+ };
+
+ /*
+ * Sets suppression level.
+ */
+ setSuppressionLevel(Level level) generates (Result retval);
+
+ /*
+ * Gets suppression level.
+ */
+ getSuppressionLevel() generates (Result retval, Level level);
+
+ enum Type : int32_t {
+ SINGLE_CHANNEL,
+ MULTI_CHANNEL
+ };
+
+ /*
+ * Set suppression type.
+ */
+ setSuppressionType(Type type) generates (Result retval);
+
+ /*
+ * Get suppression type.
+ */
+ getSuppressionType() generates (Result retval, Type type);
+
+ struct AllProperties {
+ Level level;
+ Type type;
+ };
+
+ /*
+ * Sets all properties at once.
+ */
+ setAllProperties(AllProperties properties) generates (Result retval);
+
+ /*
+ * Gets all properties at once.
+ */
+ getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/2.0/IPresetReverbEffect.hal b/audio/effect/2.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..2237bc4
--- /dev/null
+++ b/audio/effect/2.0/IPresetReverbEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+ enum Preset : int32_t {
+ NONE, // no reverb or reflections
+ SMALLROOM, // a small room less than five meters in length
+ MEDIUMROOM, // a medium room with a length of ten meters or less
+ LARGEROOM, // a large-sized room suitable for live performances
+ MEDIUMHALL, // a medium-sized hall
+ LARGEHALL, // a large-sized hall suitable for a full orchestra
+ PLATE, // synthesis of the traditional plate reverb
+ LAST = PLATE
+ };
+
+ setPreset(Preset preset) generates (Result retval);
+
+ getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/2.0/IVirtualizerEffect.hal b/audio/effect/2.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..2b7116c
--- /dev/null
+++ b/audio/effect/2.0/IVirtualizerEffect.hal
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+ /*
+ * Returns whether setting virtualization strength is supported.
+ */
+ isStrengthSupported() generates (bool strengthSupported);
+
+ enum StrengthRange : uint16_t {
+ MIN = 0,
+ MAX = 1000
+ };
+
+ /*
+ * Sets virtualization strength.
+ *
+ * @param strength strength of the effect. The valid range for strength
+ * strength is [0, 1000], where 0 per mille designates the
+ * mildest effect and 1000 per mille designates the
+ * strongest.
+ * @return retval operation completion status.
+ */
+ setStrength(uint16_t strength) generates (Result retval);
+
+ /*
+ * Gets virtualization strength.
+ */
+ getStrength() generates (Result retval, uint16_t strength);
+
+ struct SpeakerAngle {
+ AudioChannelMask mask; // speaker channel mask (1 bit set).
+ // all angles are expressed in degrees and
+ // are relative to the listener.
+ int16_t azimuth; // 0 is the direction the listener faces
+ // 180 is behind the listener
+ // -90 is to their left
+ int16_t elevation; // 0 is the horizontal plane
+ // +90 is above the listener, -90 is below
+ };
+ /*
+ * Retrieves virtual speaker angles for the given channel mask on the
+ * specified device.
+ */
+ getVirtualSpeakerAngles(AudioChannelMask mask, AudioDevice device)
+ generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+ /*
+ * Forces the virtualizer effect for the given output device.
+ */
+ forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+ /*
+ * Returns audio device reflecting the current virtualization mode,
+ * AUDIO_DEVICE_NONE when not virtualizing.
+ */
+ getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/2.0/IVisualizerEffect.hal b/audio/effect/2.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..79dc9ee
--- /dev/null
+++ b/audio/effect/2.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+ enum CaptureSizeRange : int32_t {
+ MAX = 1024, // maximum capture size in samples
+ MIN = 128 // minimum capture size in samples
+ };
+
+ /*
+ * Sets the number PCM samples in the capture.
+ */
+ setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+ /*
+ * Gets the number PCM samples in the capture.
+ */
+ getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+ enum ScalingMode : int32_t {
+ // Keep in sync with SCALING_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NORMALIZED = 0,
+ AS_PLAYED = 1
+ };
+
+ /*
+ * Specifies the way the captured data is scaled.
+ */
+ setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+ /*
+ * Retrieves the way the captured data is scaled.
+ */
+ getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+ /*
+ * Informs the visualizer about the downstream latency.
+ */
+ setLatency(uint32_t latencyMs) generates (Result retval);
+
+ /*
+ * Gets the downstream latency.
+ */
+ getLatency() generates (Result retval, uint32_t latencyMs);
+
+ enum MeasurementMode : int32_t {
+ // Keep in sync with MEASUREMENT_MODE_... in
+ // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+ NONE = 0x0,
+ PEAK_RMS = 0x1
+ };
+
+ /*
+ * Specifies which measurements are to be made.
+ */
+ setMeasurementMode(MeasurementMode measurementMode)
+ generates (Result retval);
+
+ /*
+ * Retrieves which measurements are to be made.
+ */
+ getMeasurementMode() generates (
+ Result retval, MeasurementMode measurementMode);
+
+ /*
+ * Retrieves the latest PCM snapshot captured by the visualizer engine. The
+ * number of samples to capture is specified by 'setCaptureSize' parameter.
+ *
+ * @return retval operation completion status.
+ * @return samples samples in 8 bit unsigned format (0 = 0x80)
+ */
+ capture() generates (Result retval, vec<uint8_t> samples);
+
+ struct Measurement {
+ MeasurementMode mode; // discriminator
+ union Values {
+ struct PeakAndRms {
+ int32_t peakMb; // millibels
+ int32_t rmsMb; // millibels
+ } peakAndRms;
+ } value;
+ };
+ /*
+ * Retrieves the lastest measurements. The measurements to be made
+ * are specified by 'setMeasurementMode' parameter.
+ *
+ * @return retval operation completion status.
+ * @return result measurement.
+ */
+ measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
new file mode 100644
index 0000000..7b9ca30
--- /dev/null
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "AEC_Effect_HAL"
+#include <system/audio_effects/effect_aec.h>
+#include <android/log.h>
+
+#include "AcousticEchoCancelerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+AcousticEchoCancelerEffect::~AcousticEchoCancelerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> AcousticEchoCancelerEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> AcousticEchoCancelerEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AcousticEchoCancelerEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> AcousticEchoCancelerEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> AcousticEchoCancelerEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> AcousticEchoCancelerEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> AcousticEchoCancelerEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> AcousticEchoCancelerEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> AcousticEchoCancelerEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> AcousticEchoCancelerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> AcousticEchoCancelerEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> AcousticEchoCancelerEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> AcousticEchoCancelerEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
+Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs) {
+ return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs);
+}
+
+Return<void> AcousticEchoCancelerEffect::getEchoDelay(getEchoDelay_cb _hidl_cb) {
+ return mEffect->getIntegerParam(AEC_PARAM_ECHO_DELAY, _hidl_cb);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
new file mode 100644
index 0000000..1ac925d
--- /dev/null
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect {
+ explicit AcousticEchoCancelerEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
+ Return<Result> setEchoDelay(uint32_t echoDelayMs) override;
+ Return<void> getEchoDelay(getEchoDelay_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~AcousticEchoCancelerEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
diff --git a/audio/effect/2.0/default/Android.mk b/audio/effect/2.0/default/Android.mk
new file mode 100644
index 0000000..bbcf298
--- /dev/null
+++ b/audio/effect/2.0/default/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.audio.effect@2.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ AcousticEchoCancelerEffect.cpp \
+ AudioBufferManager.cpp \
+ AutomaticGainControlEffect.cpp \
+ BassBoostEffect.cpp \
+ Conversions.cpp \
+ DownmixEffect.cpp \
+ Effect.cpp \
+ EffectsFactory.cpp \
+ EnvironmentalReverbEffect.cpp \
+ EqualizerEffect.cpp \
+ LoudnessEnhancerEffect.cpp \
+ NoiseSuppressionEffect.cpp \
+ PresetReverbEffect.cpp \
+ VirtualizerEffect.cpp \
+ VisualizerEffect.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libeffects \
+ libfmq \
+ libhidlbase \
+ libhidlmemory \
+ libhidltransport \
+ liblog \
+ libutils \
+ android.hardware.audio.common@2.0 \
+ android.hardware.audio.common@2.0-util \
+ android.hardware.audio.effect@2.0 \
+ android.hidl.memory@1.0 \
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/effect/2.0/default/AudioBufferManager.cpp b/audio/effect/2.0/default/AudioBufferManager.cpp
new file mode 100644
index 0000000..603dbb8
--- /dev/null
+++ b/audio/effect/2.0/default/AudioBufferManager.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <atomic>
+
+#include <hidlmemory/mapping.h>
+
+#include "AudioBufferManager.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager);
+
+bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) {
+ // Check if we have this buffer already
+ std::lock_guard<std::mutex> lock(mLock);
+ ssize_t idx = mBuffers.indexOfKey(buffer.id);
+ if (idx >= 0) {
+ *wrapper = mBuffers[idx].promote();
+ if (*wrapper != nullptr) return true;
+ mBuffers.removeItemsAt(idx);
+ }
+ // Need to create and init a new AudioBufferWrapper.
+ sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer));
+ if (!tempBuffer->init()) return false;
+ *wrapper = tempBuffer;
+ mBuffers.add(buffer.id, *wrapper);
+ return true;
+}
+
+void AudioBufferManager::removeEntry(uint64_t id) {
+ std::lock_guard<std::mutex> lock(mLock);
+ ssize_t idx = mBuffers.indexOfKey(id);
+ if (idx >= 0) mBuffers.removeItemsAt(idx);
+}
+
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) :
+ mHidlBuffer(buffer), mHalBuffer{ 0, { nullptr } } {
+}
+
+AudioBufferWrapper::~AudioBufferWrapper() {
+ AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id);
+}
+
+bool AudioBufferWrapper::init() {
+ if (mHalBuffer.raw != nullptr) {
+ ALOGE("An attempt to init AudioBufferWrapper twice");
+ return false;
+ }
+ mHidlMemory = mapMemory(mHidlBuffer.data);
+ if (mHidlMemory == nullptr) {
+ ALOGE("Could not map HIDL memory to IMemory");
+ return false;
+ }
+ mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer());
+ if (mHalBuffer.raw == nullptr) {
+ ALOGE("IMemory buffer pointer is null");
+ return false;
+ }
+ mHalBuffer.frameCount = mHidlBuffer.frameCount;
+ return true;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/AudioBufferManager.h b/audio/effect/2.0/default/AudioBufferManager.h
new file mode 100644
index 0000000..6d65995
--- /dev/null
+++ b/audio/effect/2.0/default/AudioBufferManager.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_audio_effect_V2_0_AudioBufferManager_H_
+#define android_hardware_audio_effect_V2_0_AudioBufferManager_H_
+
+#include <mutex>
+
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <system/audio_effect.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+class AudioBufferWrapper : public RefBase {
+ public:
+ explicit AudioBufferWrapper(const AudioBuffer& buffer);
+ virtual ~AudioBufferWrapper();
+ bool init();
+ audio_buffer_t* getHalBuffer() { return &mHalBuffer; }
+ private:
+ AudioBufferWrapper(const AudioBufferWrapper&) = delete;
+ void operator=(AudioBufferWrapper) = delete;
+
+ AudioBuffer mHidlBuffer;
+ sp<IMemory> mHidlMemory;
+ audio_buffer_t mHalBuffer;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+using ::android::hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
+
+namespace android {
+
+// This class needs to be in 'android' ns because Singleton macros require that.
+class AudioBufferManager : public Singleton<AudioBufferManager> {
+ public:
+ bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper);
+
+ private:
+ friend class hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
+
+ // Called by AudioBufferWrapper.
+ void removeEntry(uint64_t id);
+
+ std::mutex mLock;
+ KeyedVector<uint64_t, wp<AudioBufferWrapper>> mBuffers;
+};
+
+} // namespace android
+
+#endif // android_hardware_audio_effect_V2_0_AudioBufferManager_H_
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
new file mode 100644
index 0000000..62fe5f7
--- /dev/null
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "AGC_Effect_HAL"
+#include <android/log.h>
+
+#include "AutomaticGainControlEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+AutomaticGainControlEffect::AutomaticGainControlEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+AutomaticGainControlEffect::~AutomaticGainControlEffect() {}
+
+void AutomaticGainControlEffect::propertiesFromHal(
+ const t_agc_settings& halProperties,
+ IAutomaticGainControlEffect::AllProperties* properties) {
+ properties->targetLevelMb = halProperties.targetLevel;
+ properties->compGainMb = halProperties.compGain;
+ properties->limiterEnabled = halProperties.limiterEnabled;
+}
+
+void AutomaticGainControlEffect::propertiesToHal(
+ const IAutomaticGainControlEffect::AllProperties& properties,
+ t_agc_settings* halProperties) {
+ halProperties->targetLevel = properties.targetLevelMb;
+ halProperties->compGain = properties.compGainMb;
+ halProperties->limiterEnabled = properties.limiterEnabled;
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> AutomaticGainControlEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> AutomaticGainControlEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AutomaticGainControlEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> AutomaticGainControlEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> AutomaticGainControlEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> AutomaticGainControlEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> AutomaticGainControlEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> AutomaticGainControlEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> AutomaticGainControlEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AutomaticGainControlEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> AutomaticGainControlEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> AutomaticGainControlEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> AutomaticGainControlEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> AutomaticGainControlEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> AutomaticGainControlEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> AutomaticGainControlEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> AutomaticGainControlEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
+Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb) {
+ return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb);
+}
+
+Return<void> AutomaticGainControlEffect::getTargetLevel(getTargetLevel_cb _hidl_cb) {
+ return mEffect->getIntegerParam(AGC_PARAM_TARGET_LEVEL, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setCompGain(int16_t compGainMb) {
+ return mEffect->setParam(AGC_PARAM_COMP_GAIN, compGainMb);
+}
+
+Return<void> AutomaticGainControlEffect::getCompGain(getCompGain_cb _hidl_cb) {
+ return mEffect->getIntegerParam(AGC_PARAM_COMP_GAIN, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setLimiterEnabled(bool enabled) {
+ return mEffect->setParam(AGC_PARAM_LIMITER_ENA, enabled);
+}
+
+Return<void> AutomaticGainControlEffect::isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) {
+ return mEffect->getIntegerParam(AGC_PARAM_LIMITER_ENA, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setAllProperties(const IAutomaticGainControlEffect::AllProperties& properties) {
+ t_agc_settings halProperties;
+ propertiesToHal(properties, &halProperties);
+ return mEffect->setParam(AGC_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> AutomaticGainControlEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+ t_agc_settings halProperties;
+ Result retval = mEffect->getParam(AGC_PARAM_PROPERTIES, halProperties);
+ AllProperties properties;
+ propertiesFromHal(halProperties, &properties);
+ _hidl_cb(retval, properties);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.h b/audio/effect/2.0/default/AutomaticGainControlEffect.h
new file mode 100644
index 0000000..5e1f279
--- /dev/null
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
+
+#include <system/audio_effects/effect_agc.h>
+
+#include <android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct AutomaticGainControlEffect : public IAutomaticGainControlEffect {
+ explicit AutomaticGainControlEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
+ Return<Result> setTargetLevel(int16_t targetLevelMb) override;
+ Return<void> getTargetLevel(getTargetLevel_cb _hidl_cb) override;
+ Return<Result> setCompGain(int16_t compGainMb) override;
+ Return<void> getCompGain(getCompGain_cb _hidl_cb) override;
+ Return<Result> setLimiterEnabled(bool enabled) override;
+ Return<void> isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) override;
+ Return<Result> setAllProperties(
+ const IAutomaticGainControlEffect::AllProperties& properties) override;
+ Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~AutomaticGainControlEffect();
+
+ void propertiesFromHal(
+ const t_agc_settings& halProperties,
+ IAutomaticGainControlEffect::AllProperties* properties);
+ void propertiesToHal(
+ const IAutomaticGainControlEffect::AllProperties& properties,
+ t_agc_settings* halProperties);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
diff --git a/audio/effect/2.0/default/BassBoostEffect.cpp b/audio/effect/2.0/default/BassBoostEffect.cpp
new file mode 100644
index 0000000..8f35e5f
--- /dev/null
+++ b/audio/effect/2.0/default/BassBoostEffect.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "BassBoost_HAL"
+#include <system/audio_effects/effect_bassboost.h>
+#include <android/log.h>
+
+#include "BassBoostEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+BassBoostEffect::BassBoostEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+BassBoostEffect::~BassBoostEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> BassBoostEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> BassBoostEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> BassBoostEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> BassBoostEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> BassBoostEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> BassBoostEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> BassBoostEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> BassBoostEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> BassBoostEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> BassBoostEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> BassBoostEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> BassBoostEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> BassBoostEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> BassBoostEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> BassBoostEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> BassBoostEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> BassBoostEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
+Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb) {
+ return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setStrength(uint16_t strength) {
+ return mEffect->setParam(BASSBOOST_PARAM_STRENGTH, strength);
+}
+
+Return<void> BassBoostEffect::getStrength(getStrength_cb _hidl_cb) {
+ return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH, _hidl_cb);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/BassBoostEffect.h b/audio/effect/2.0/default/BassBoostEffect.h
new file mode 100644
index 0000000..1e5053b
--- /dev/null
+++ b/audio/effect/2.0/default/BassBoostEffect.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IBassBoostEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::effect::V2_0::IBassBoostEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct BassBoostEffect : public IBassBoostEffect {
+ explicit BassBoostEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
+ Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb) override;
+ Return<Result> setStrength(uint16_t strength) override;
+ Return<void> getStrength(getStrength_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~BassBoostEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
diff --git a/audio/effect/2.0/default/Conversions.cpp b/audio/effect/2.0/default/Conversions.cpp
new file mode 100644
index 0000000..e7d4c46
--- /dev/null
+++ b/audio/effect/2.0/default/Conversions.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <memory.h>
+#include <stdio.h>
+
+#include "Conversions.h"
+#include "HidlUtils.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+void effectDescriptorFromHal(
+ const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor) {
+ HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
+ HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
+ descriptor->flags = EffectFlags(halDescriptor.flags);
+ descriptor->cpuLoad = halDescriptor.cpuLoad;
+ descriptor->memoryUsage = halDescriptor.memoryUsage;
+ memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size());
+ memcpy(descriptor->implementor.data(),
+ halDescriptor.implementor, descriptor->implementor.size());
+}
+
+std::string uuidToString(const effect_uuid_t& halUuid) {
+ char str[64];
+ snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ halUuid.timeLow,
+ halUuid.timeMid,
+ halUuid.timeHiAndVersion,
+ halUuid.clockSeq,
+ halUuid.node[0],
+ halUuid.node[1],
+ halUuid.node[2],
+ halUuid.node[3],
+ halUuid.node[4],
+ halUuid.node[5]);
+ return str;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/Conversions.h b/audio/effect/2.0/default/Conversions.h
new file mode 100644
index 0000000..7cef362
--- /dev/null
+++ b/audio/effect/2.0/default/Conversions.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_audio_effect_V2_0_Conversions_H_
+#define android_hardware_audio_effect_V2_0_Conversions_H_
+
+#include <string>
+
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <system/audio_effect.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+
+void effectDescriptorFromHal(
+ const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor);
+std::string uuidToString(const effect_uuid_t& halUuid);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_audio_effect_V2_0_Conversions_H_
diff --git a/audio/effect/2.0/default/DownmixEffect.cpp b/audio/effect/2.0/default/DownmixEffect.cpp
new file mode 100644
index 0000000..92f15bd
--- /dev/null
+++ b/audio/effect/2.0/default/DownmixEffect.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "Downmix_HAL"
+#include <system/audio_effects/effect_downmix.h>
+#include <android/log.h>
+
+#include "DownmixEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+DownmixEffect::DownmixEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+DownmixEffect::~DownmixEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> DownmixEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> DownmixEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> DownmixEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> DownmixEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> DownmixEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> DownmixEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> DownmixEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> DownmixEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> DownmixEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> DownmixEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> DownmixEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> DownmixEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> DownmixEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> DownmixEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> DownmixEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> DownmixEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> DownmixEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> DownmixEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> DownmixEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> DownmixEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> DownmixEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> DownmixEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
+Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset) {
+ return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset));
+}
+
+Return<void> DownmixEffect::getType(getType_cb _hidl_cb) {
+ downmix_type_t halPreset = DOWNMIX_TYPE_INVALID;
+ Result retval = mEffect->getParam(DOWNMIX_PARAM_TYPE, halPreset);
+ _hidl_cb(retval, Type(halPreset));
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/DownmixEffect.h b/audio/effect/2.0/default/DownmixEffect.h
new file mode 100644
index 0000000..125f34d
--- /dev/null
+++ b/audio/effect/2.0/default/DownmixEffect.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IDownmixEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::effect::V2_0::IDownmixEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct DownmixEffect : public IDownmixEffect {
+ explicit DownmixEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
+ Return<Result> setType(IDownmixEffect::Type preset) override;
+ Return<void> getType(getType_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~DownmixEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp
new file mode 100644
index 0000000..2d36604
--- /dev/null
+++ b/audio/effect/2.0/default/Effect.cpp
@@ -0,0 +1,766 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <memory.h>
+
+#define LOG_TAG "EffectHAL"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <android/log.h>
+#include <media/EffectsFactoryApi.h>
+#include <utils/Trace.h>
+
+#include "Conversions.h"
+#include "Effect.h"
+#include "EffectMap.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
+
+namespace {
+
+class ProcessThread : public Thread {
+ public:
+ // ProcessThread's lifespan never exceeds Effect's lifespan.
+ ProcessThread(std::atomic<bool>* stop,
+ effect_handle_t effect,
+ std::atomic<audio_buffer_t*>* inBuffer,
+ std::atomic<audio_buffer_t*>* outBuffer,
+ Effect::StatusMQ* statusMQ,
+ EventFlag* efGroup)
+ : Thread(false /*canCallJava*/),
+ mStop(stop),
+ mEffect(effect),
+ mHasProcessReverse((*mEffect)->process_reverse != NULL),
+ mInBuffer(inBuffer),
+ mOutBuffer(outBuffer),
+ mStatusMQ(statusMQ),
+ mEfGroup(efGroup) {
+ }
+ virtual ~ProcessThread() {}
+
+ private:
+ std::atomic<bool>* mStop;
+ effect_handle_t mEffect;
+ bool mHasProcessReverse;
+ std::atomic<audio_buffer_t*>* mInBuffer;
+ std::atomic<audio_buffer_t*>* mOutBuffer;
+ Effect::StatusMQ* mStatusMQ;
+ EventFlag* mEfGroup;
+
+ bool threadLoop() override;
+};
+
+bool ProcessThread::threadLoop() {
+ // This implementation doesn't return control back to the Thread until it decides to stop,
+ // as the Thread uses mutexes, and this can lead to priority inversion.
+ while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+ uint32_t efState = 0;
+ mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState);
+ if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL))
+ || (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) {
+ continue; // Nothing to do or time to quit.
+ }
+ Result retval = Result::OK;
+ if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE)
+ && !mHasProcessReverse) {
+ retval = Result::NOT_SUPPORTED;
+ }
+
+ if (retval == Result::OK) {
+ // affects both buffer pointers and their contents.
+ std::atomic_thread_fence(std::memory_order_acquire);
+ int32_t processResult;
+ audio_buffer_t* inBuffer =
+ std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
+ audio_buffer_t* outBuffer =
+ std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
+ if (inBuffer != nullptr && outBuffer != nullptr) {
+ if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
+ processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
+ } else {
+ processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
+ }
+ std::atomic_thread_fence(std::memory_order_release);
+ } else {
+ ALOGE("processing buffers were not set before calling 'process'");
+ processResult = -ENODEV;
+ }
+ switch(processResult) {
+ case 0: retval = Result::OK; break;
+ case -ENODATA: retval = Result::INVALID_STATE; break;
+ case -EINVAL: retval = Result::INVALID_ARGUMENTS; break;
+ default: retval = Result::NOT_INITIALIZED;
+ }
+ }
+ if (!mStatusMQ->write(&retval)) {
+ ALOGW("status message queue write failed");
+ }
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
+ }
+
+ return false;
+}
+
+} // namespace
+
+// static
+const char *Effect::sContextResultOfCommand = "returned status";
+const char *Effect::sContextCallToCommand = "error";
+const char *Effect::sContextCallFunction = sContextCallToCommand;
+
+Effect::Effect(effect_handle_t handle)
+ : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
+}
+
+Effect::~Effect() {
+ ATRACE_CALL();
+ close();
+ if (mProcessThread.get()) {
+ ATRACE_NAME("mProcessThread->join");
+ status_t status = mProcessThread->join();
+ ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
+ }
+ if (mEfGroup) {
+ status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+ ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
+ }
+ mInBuffer.clear();
+ mOutBuffer.clear();
+ int status = EffectRelease(mHandle);
+ ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+ EffectMap::getInstance().remove(mHandle);
+ mHandle = 0;
+}
+
+// static
+template<typename T> size_t Effect::alignedSizeIn(size_t s) {
+ return (s + sizeof(T) - 1) / sizeof(T);
+}
+
+// static
+template<typename T> std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(
+ const hidl_vec<T>& vec, uint32_t* halDataSize) {
+ // Due to bugs in HAL, they may attempt to write into the provided
+ // input buffer. The original binder buffer is r/o, thus it is needed
+ // to create a r/w version.
+ *halDataSize = vec.size() * sizeof(T);
+ std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
+ memcpy(&halData[0], &vec[0], *halDataSize);
+ return halData;
+}
+
+// static
+void Effect::effectAuxChannelsConfigFromHal(
+ const channel_config_t& halConfig, EffectAuxChannelsConfig* config) {
+ config->mainChannels = AudioChannelMask(halConfig.main_channels);
+ config->auxChannels = AudioChannelMask(halConfig.aux_channels);
+}
+
+// static
+void Effect::effectAuxChannelsConfigToHal(
+ const EffectAuxChannelsConfig& config, channel_config_t* halConfig) {
+ halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
+ halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
+}
+
+// static
+void Effect::effectBufferConfigFromHal(
+ const buffer_config_t& halConfig, EffectBufferConfig* config) {
+ config->buffer.id = 0;
+ config->buffer.frameCount = 0;
+ config->samplingRateHz = halConfig.samplingRate;
+ config->channels = AudioChannelMask(halConfig.channels);
+ config->format = AudioFormat(halConfig.format);
+ config->accessMode = EffectBufferAccess(halConfig.accessMode);
+ config->mask = EffectConfigParameters(halConfig.mask);
+}
+
+// static
+void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) {
+ // Note: setting the buffers directly is considered obsolete. They need to be set
+ // using 'setProcessBuffers'.
+ halConfig->buffer.frameCount = 0;
+ halConfig->buffer.raw = NULL;
+ halConfig->samplingRate = config.samplingRateHz;
+ halConfig->channels = static_cast<uint32_t>(config.channels);
+ // Note: The framework code does not use BP.
+ halConfig->bufferProvider.cookie = NULL;
+ halConfig->bufferProvider.getBuffer = NULL;
+ halConfig->bufferProvider.releaseBuffer = NULL;
+ halConfig->format = static_cast<uint8_t>(config.format);
+ halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
+ halConfig->mask = static_cast<uint8_t>(config.mask);
+}
+
+// static
+void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
+ effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
+ effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
+}
+
+// static
+void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
+ effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
+ effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
+}
+
+// static
+void Effect::effectOffloadParamToHal(
+ const EffectOffloadParameter& offload, effect_offload_param_t* halOffload) {
+ halOffload->isOffload = offload.isOffload;
+ halOffload->ioHandle = offload.ioHandle;
+}
+
+// static
+std::vector<uint8_t> Effect::parameterToHal(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t valueSize,
+ const void** valueData) {
+ size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
+ size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
+ std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0);
+ effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
+ halParam->psize = paramSize;
+ halParam->vsize = valueSize;
+ memcpy(halParam->data, paramData, paramSize);
+ if (valueData) {
+ if (*valueData) {
+ // Value data is provided.
+ memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
+ } else {
+ // The caller needs the pointer to the value data location.
+ *valueData = halParam->data + valueOffsetFromData;
+ }
+ }
+ return halParamBuffer;
+}
+
+Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
+ return analyzeStatus("command", commandName, context, status);
+}
+
+Result Effect::analyzeStatus(
+ const char* funcName,
+ const char* subFuncName,
+ const char* contextDescription,
+ status_t status) {
+ if (status != OK) {
+ ALOGW("Effect %p %s %s %s: %s",
+ mHandle, funcName, subFuncName, contextDescription, strerror(-status));
+ }
+ switch (status) {
+ case OK: return Result::OK;
+ case -EINVAL: return Result::INVALID_ARGUMENTS;
+ case -ENODATA: return Result::INVALID_STATE;
+ case -ENODEV: return Result::NOT_INITIALIZED;
+ case -ENOMEM: return Result::RESULT_TOO_BIG;
+ case -ENOSYS: return Result::NOT_SUPPORTED;
+ default: return Result::INVALID_STATE;
+ }
+}
+
+void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
+ uint32_t halResultSize = sizeof(effect_config_t);
+ effect_config_t halConfig{};
+ status_t status = (*mHandle)->command(
+ mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
+ EffectConfig config;
+ if (status == OK) {
+ effectConfigFromHal(halConfig, &config);
+ }
+ cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
+}
+
+Result Effect::getCurrentConfigImpl(
+ uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess) {
+ uint32_t halCmd = featureId;
+ uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
+ memset(halResult, 0, sizeof(halResult));
+ uint32_t halResultSize = 0;
+ return sendCommandReturningStatusAndData(
+ EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
+ sizeof(uint32_t), &halCmd,
+ &halResultSize, halResult,
+ sizeof(uint32_t),
+ [&]{ onSuccess(&halResult[1]); });
+}
+
+Result Effect::getParameterImpl(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t requestValueSize,
+ uint32_t replyValueSize,
+ GetParameterSuccessCallback onSuccess) {
+ // As it is unknown what method HAL uses for copying the provided parameter data,
+ // it is safer to make sure that input and output buffers do not overlap.
+ std::vector<uint8_t> halCmdBuffer =
+ parameterToHal(paramSize, paramData, requestValueSize, nullptr);
+ const void *valueData = nullptr;
+ std::vector<uint8_t> halParamBuffer =
+ parameterToHal(paramSize, paramData, replyValueSize, &valueData);
+ uint32_t halParamBufferSize = halParamBuffer.size();
+
+ return sendCommandReturningStatusAndData(
+ EFFECT_CMD_GET_PARAM, "GET_PARAM",
+ halCmdBuffer.size(), &halCmdBuffer[0],
+ &halParamBufferSize, &halParamBuffer[0],
+ sizeof(effect_param_t),
+ [&]{
+ effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
+ onSuccess(halParam->vsize, valueData);
+ });
+}
+
+Result Effect::getSupportedConfigsImpl(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ GetSupportedConfigsSuccessCallback onSuccess) {
+ uint32_t halCmd[2] = { featureId, maxConfigs };
+ uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
+ uint8_t halResult[halResultSize];
+ memset(&halResult[0], 0, halResultSize);
+ return sendCommandReturningStatusAndData(
+ EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS",
+ sizeof(halCmd), halCmd,
+ &halResultSize, &halResult[0],
+ 2 * sizeof(uint32_t),
+ [&]{
+ uint32_t *halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
+ uint32_t supportedConfigs = *(++halResult32); // skip status field
+ if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
+ onSuccess(supportedConfigs, ++halResult32);
+ });
+}
+
+Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+ status_t status;
+ // Create message queue.
+ if (mStatusMQ) {
+ ALOGE("the client attempts to call prepareForProcessing_cb twice");
+ _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
+ return Void();
+ }
+ std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
+ if (!tempStatusMQ->isValid()) {
+ ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+ _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+ return Void();
+ }
+ status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
+ if (status != OK || !mEfGroup) {
+ ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+ return Void();
+ }
+
+ // Create and launch the thread.
+ mProcessThread = new ProcessThread(
+ &mStopProcessThread,
+ mHandle,
+ &mHalInBufferPtr,
+ &mHalOutBufferPtr,
+ tempStatusMQ.get(),
+ mEfGroup);
+ status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
+ if (status != OK) {
+ ALOGW("failed to start effect processing thread: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
+ return Void();
+ }
+
+ mStatusMQ = std::move(tempStatusMQ);
+ _hidl_cb(Result::OK, *mStatusMQ->getDesc());
+ return Void();
+}
+
+Return<Result> Effect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ AudioBufferManager& manager = AudioBufferManager::getInstance();
+ sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
+ if (!manager.wrap(inBuffer, &tempInBuffer)) {
+ ALOGE("Could not map memory of the input buffer");
+ return Result::INVALID_ARGUMENTS;
+ }
+ if (!manager.wrap(outBuffer, &tempOutBuffer)) {
+ ALOGE("Could not map memory of the output buffer");
+ return Result::INVALID_ARGUMENTS;
+ }
+ mInBuffer = tempInBuffer;
+ mOutBuffer = tempOutBuffer;
+ // The processing thread only reads these pointers after waking up by an event flag,
+ // so it's OK to update the pair non-atomically.
+ mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
+ mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
+ return Result::OK;
+}
+
+Result Effect::sendCommand(int commandCode, const char* commandName) {
+ return sendCommand(commandCode, commandName, 0, NULL);
+}
+
+Result Effect::sendCommand(
+ int commandCode, const char* commandName, uint32_t size, void* data) {
+ status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
+ return analyzeCommandStatus(commandName, sContextCallToCommand, status);
+}
+
+Result Effect::sendCommandReturningData(
+ int commandCode, const char* commandName,
+ uint32_t* replySize, void* replyData) {
+ return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
+}
+
+Result Effect::sendCommandReturningData(
+ int commandCode, const char* commandName,
+ uint32_t size, void* data,
+ uint32_t* replySize, void* replyData) {
+ uint32_t expectedReplySize = *replySize;
+ status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
+ if (status == OK && *replySize != expectedReplySize) {
+ status = -ENODATA;
+ }
+ return analyzeCommandStatus(commandName, sContextCallToCommand, status);
+}
+
+Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
+ return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
+}
+
+Result Effect::sendCommandReturningStatus(
+ int commandCode, const char* commandName, uint32_t size, void* data) {
+ uint32_t replyCmdStatus;
+ uint32_t replySize = sizeof(uint32_t);
+ return sendCommandReturningStatusAndData(
+ commandCode, commandName, size, data, &replySize, &replyCmdStatus, replySize, []{});
+}
+
+Result Effect::sendCommandReturningStatusAndData(
+ int commandCode, const char* commandName,
+ uint32_t size, void* data,
+ uint32_t* replySize, void* replyData,
+ uint32_t minReplySize,
+ CommandSuccessCallback onSuccess) {
+ status_t status =
+ (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
+ Result retval;
+ if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
+ uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
+ retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
+ if (commandStatus == OK) {
+ onSuccess();
+ }
+ } else {
+ retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
+ }
+ return retval;
+}
+
+Result Effect::setConfigImpl(
+ int commandCode, const char* commandName,
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ effect_config_t halConfig;
+ effectConfigToHal(config, &halConfig);
+ if (inputBufferProvider != 0) {
+ LOG_FATAL("Using input buffer provider is not supported");
+ }
+ if (outputBufferProvider != 0) {
+ LOG_FATAL("Using output buffer provider is not supported");
+ }
+ return sendCommandReturningStatus(
+ commandCode, commandName, sizeof(effect_config_t), &halConfig);
+}
+
+
+Result Effect::setParameterImpl(
+ uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData) {
+ std::vector<uint8_t> halParamBuffer = parameterToHal(
+ paramSize, paramData, valueSize, &valueData);
+ return sendCommandReturningStatus(
+ EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(), &halParamBuffer[0]);
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> Effect::init() {
+ return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
+}
+
+Return<Result> Effect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return setConfigImpl(
+ EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> Effect::reset() {
+ return sendCommand(EFFECT_CMD_RESET, "RESET");
+}
+
+Return<Result> Effect::enable() {
+ return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
+}
+
+Return<Result> Effect::disable() {
+ return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
+}
+
+Return<Result> Effect::setDevice(AudioDevice device) {
+ uint32_t halDevice = static_cast<uint32_t>(device);
+ return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
+}
+
+Return<void> Effect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ uint32_t halDataSize;
+ std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
+ uint32_t halResultSize = halDataSize;
+ uint32_t halResult[volumes.size()];
+ Result retval = sendCommandReturningData(
+ EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
+ halDataSize, &halData[0],
+ &halResultSize, halResult);
+ hidl_vec<uint32_t> result;
+ if (retval == Result::OK) {
+ result.setToExternal(&halResult[0], halResultSize);
+ }
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+ uint32_t halDataSize;
+ std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
+ return sendCommand(
+ EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
+ halDataSize, &halData[0]);
+}
+
+Return<Result> Effect::setAudioMode(AudioMode mode) {
+ uint32_t halMode = static_cast<uint32_t>(mode);
+ return sendCommand(
+ EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
+}
+
+Return<Result> Effect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE",
+ config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> Effect::setInputDevice(AudioDevice device) {
+ uint32_t halDevice = static_cast<uint32_t>(device);
+ return sendCommand(
+ EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t), &halDevice);
+}
+
+Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
+ getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
+ return Void();
+}
+
+Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
+ return Void();
+}
+
+Return<void> Effect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ hidl_vec<EffectAuxChannelsConfig> result;
+ Result retval = getSupportedConfigsImpl(
+ EFFECT_FEATURE_AUX_CHANNELS,
+ maxConfigs,
+ sizeof(channel_config_t),
+ [&] (uint32_t supportedConfigs, void* configsData) {
+ result.resize(supportedConfigs);
+ channel_config_t *config = reinterpret_cast<channel_config_t*>(configsData);
+ for (size_t i = 0; i < result.size(); ++i) {
+ effectAuxChannelsConfigFromHal(*config++, &result[i]);
+ }
+ });
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ uint32_t halCmd = EFFECT_FEATURE_AUX_CHANNELS;
+ uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+ memset(halResult, 0, sizeof(halResult));
+ uint32_t halResultSize = 0;
+ EffectAuxChannelsConfig result;
+ Result retval = getCurrentConfigImpl(
+ EFFECT_FEATURE_AUX_CHANNELS,
+ sizeof(channel_config_t),
+ [&] (void* configData) {
+ effectAuxChannelsConfigFromHal(
+ *reinterpret_cast<channel_config_t*>(configData), &result);
+ });
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+ uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+ halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
+ effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
+ return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
+ "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
+}
+
+Return<Result> Effect::setAudioSource(AudioSource source) {
+ uint32_t halSource = static_cast<uint32_t>(source);
+ return sendCommand(
+ EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t), &halSource);
+}
+
+Return<Result> Effect::offload(const EffectOffloadParameter& param) {
+ effect_offload_param_t halParam;
+ effectOffloadParamToHal(param, &halParam);
+ return sendCommandReturningStatus(
+ EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t), &halParam);
+}
+
+Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ effect_descriptor_t halDescriptor;
+ memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
+ status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
+ EffectDescriptor descriptor;
+ if (status == OK) {
+ effectDescriptorFromHal(halDescriptor, &descriptor);
+ }
+ _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
+ return Void();
+}
+
+Return<void> Effect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ uint32_t halDataSize;
+ std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
+ uint32_t halResultSize = resultMaxSize;
+ std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
+ memset(&halResult[0], 0, halResultSize);
+
+ void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
+ void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
+ status_t status = (*mHandle)->command(
+ mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
+ hidl_vec<uint8_t> result;
+ if (status == OK && resultPtr != NULL) {
+ result.setToExternal(&halResult[0], halResultSize);
+ }
+ _hidl_cb(status, result);
+ return Void();
+}
+
+Return<Result> Effect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return setParameterImpl(parameter.size(), ¶meter[0], value.size(), &value[0]);
+}
+
+Return<void> Effect::getParameter(
+ const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+ hidl_vec<uint8_t> value;
+ Result retval = getParameterImpl(
+ parameter.size(),
+ ¶meter[0],
+ valueMaxSize,
+ [&] (uint32_t valueSize, const void* valueData) {
+ value.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)), valueSize);
+ });
+ _hidl_cb(retval, value);
+ return Void();
+}
+
+Return<void> Effect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ uint32_t configCount = 0;
+ hidl_vec<uint8_t> result;
+ Result retval = getSupportedConfigsImpl(
+ featureId,
+ maxConfigs,
+ configSize,
+ [&] (uint32_t supportedConfigs, void* configsData) {
+ configCount = supportedConfigs;
+ result.resize(configCount * configSize);
+ memcpy(&result[0], configsData, result.size());
+ });
+ _hidl_cb(retval, configCount, result);
+ return Void();
+}
+
+Return<void> Effect::getCurrentConfigForFeature(
+ uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+ hidl_vec<uint8_t> result;
+ Result retval = getCurrentConfigImpl(
+ featureId,
+ configSize,
+ [&] (void* configData) {
+ result.resize(configSize);
+ memcpy(&result[0], configData, result.size());
+ });
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+Return<Result> Effect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
+ memset(halCmd, 0, sizeof(halCmd));
+ halCmd[0] = featureId;
+ memcpy(&halCmd[1], &configData[0], configData.size());
+ return sendCommandReturningStatus(
+ EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", sizeof(halCmd), halCmd);
+}
+
+Return<Result> Effect::close() {
+ if (mIsClosed) return Result::INVALID_STATE;
+ mIsClosed = true;
+ if (mProcessThread.get()) {
+ mStopProcessThread.store(true, std::memory_order_release);
+ }
+ if (mEfGroup) {
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
+ }
+ return Result::OK;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h
new file mode 100644
index 0000000..0918cd8
--- /dev/null
+++ b/audio/effect/2.0/default/Effect.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
+
+#include <atomic>
+#include <memory>
+#include <vector>
+
+#include <android/hardware/audio/effect/2.0/IEffect.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
+
+#include <hardware/audio_effect.h>
+
+#include "AudioBufferManager.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectFeature;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Effect : public IEffect {
+ typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ;
+ using GetParameterSuccessCallback =
+ std::function<void(uint32_t valueSize, const void* valueData)>;
+
+ explicit Effect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Utility methods for extending interfaces.
+ template<typename T> Return<void> getIntegerParam(
+ uint32_t paramId, std::function<void(Result retval, T paramValue)> cb) {
+ T value;
+ Result retval = getParameterImpl(
+ sizeof(uint32_t), ¶mId,
+ sizeof(T),
+ [&] (uint32_t valueSize, const void* valueData) {
+ if (valueSize > sizeof(T)) valueSize = sizeof(T);
+ memcpy(&value, valueData, valueSize);
+ });
+ cb(retval, value);
+ return Void();
+ }
+
+ template<typename T> Result getParam(uint32_t paramId, T& paramValue) {
+ return getParameterImpl(
+ sizeof(uint32_t), ¶mId,
+ sizeof(T),
+ [&] (uint32_t valueSize, const void* valueData) {
+ if (valueSize > sizeof(T)) valueSize = sizeof(T);
+ memcpy(¶mValue, valueData, valueSize);
+ });
+ }
+
+ template<typename T> Result getParam(uint32_t paramId, uint32_t paramArg, T& paramValue) {
+ uint32_t params[2] = { paramId, paramArg };
+ return getParameterImpl(
+ sizeof(params), params,
+ sizeof(T),
+ [&] (uint32_t valueSize, const void* valueData) {
+ if (valueSize > sizeof(T)) valueSize = sizeof(T);
+ memcpy(¶mValue, valueData, valueSize);
+ });
+ }
+
+ template<typename T> Result setParam(uint32_t paramId, const T& paramValue) {
+ return setParameterImpl(sizeof(uint32_t), ¶mId, sizeof(T), ¶mValue);
+ }
+
+ template<typename T> Result setParam(uint32_t paramId, uint32_t paramArg, const T& paramValue) {
+ uint32_t params[2] = { paramId, paramArg };
+ return setParameterImpl(sizeof(params), params, sizeof(T), ¶mValue);
+ }
+
+ Result getParameterImpl(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t valueSize,
+ GetParameterSuccessCallback onSuccess) {
+ return getParameterImpl(paramSize, paramData, valueSize, valueSize, onSuccess);
+ }
+ Result getParameterImpl(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t requestValueSize,
+ uint32_t replyValueSize,
+ GetParameterSuccessCallback onSuccess);
+ Result setParameterImpl(
+ uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData);
+
+ private:
+ friend struct VirtualizerEffect; // for getParameterImpl
+ friend struct VisualizerEffect; // to allow executing commands
+
+ using CommandSuccessCallback = std::function<void()>;
+ using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>;
+ using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>;
+ using GetSupportedConfigsSuccessCallback =
+ std::function<void(uint32_t supportedConfigs, void* configsData)>;
+
+ static const char *sContextResultOfCommand;
+ static const char *sContextCallToCommand;
+ static const char *sContextCallFunction;
+
+ bool mIsClosed;
+ effect_handle_t mHandle;
+ sp<AudioBufferWrapper> mInBuffer;
+ sp<AudioBufferWrapper> mOutBuffer;
+ std::atomic<audio_buffer_t*> mHalInBufferPtr;
+ std::atomic<audio_buffer_t*> mHalOutBufferPtr;
+ std::unique_ptr<StatusMQ> mStatusMQ;
+ EventFlag* mEfGroup;
+ std::atomic<bool> mStopProcessThread;
+ sp<Thread> mProcessThread;
+
+ virtual ~Effect();
+
+ template<typename T> static size_t alignedSizeIn(size_t s);
+ template<typename T> std::unique_ptr<uint8_t[]> hidlVecToHal(
+ const hidl_vec<T>& vec, uint32_t* halDataSize);
+ static void effectAuxChannelsConfigFromHal(
+ const channel_config_t& halConfig, EffectAuxChannelsConfig* config);
+ static void effectAuxChannelsConfigToHal(
+ const EffectAuxChannelsConfig& config, channel_config_t* halConfig);
+ static void effectBufferConfigFromHal(
+ const buffer_config_t& halConfig, EffectBufferConfig* config);
+ static void effectBufferConfigToHal(
+ const EffectBufferConfig& config, buffer_config_t* halConfig);
+ static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config);
+ static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig);
+ static void effectOffloadParamToHal(
+ const EffectOffloadParameter& offload, effect_offload_param_t* halOffload);
+ static std::vector<uint8_t> parameterToHal(
+ uint32_t paramSize, const void* paramData, uint32_t valueSize, const void** valueData);
+
+ Result analyzeCommandStatus(
+ const char* commandName, const char* context, status_t status);
+ Result analyzeStatus(
+ const char* funcName,
+ const char* subFuncName,
+ const char* contextDescription,
+ status_t status);
+ void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
+ Result getCurrentConfigImpl(
+ uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess);
+ Result getSupportedConfigsImpl(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ GetSupportedConfigsSuccessCallback onSuccess);
+ Result sendCommand(int commandCode, const char* commandName);
+ Result sendCommand(int commandCode, const char* commandName, uint32_t size, void* data);
+ Result sendCommandReturningData(
+ int commandCode, const char* commandName, uint32_t* replySize, void* replyData);
+ Result sendCommandReturningData(
+ int commandCode, const char* commandName,
+ uint32_t size, void* data,
+ uint32_t* replySize, void* replyData);
+ Result sendCommandReturningStatus(int commandCode, const char* commandName);
+ Result sendCommandReturningStatus(
+ int commandCode, const char* commandName, uint32_t size, void* data);
+ Result sendCommandReturningStatusAndData(
+ int commandCode, const char* commandName,
+ uint32_t size, void* data,
+ uint32_t* replySize, void* replyData,
+ uint32_t minReplySize,
+ CommandSuccessCallback onSuccess);
+ Result setConfigImpl(
+ int commandCode, const char* commandName,
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp
new file mode 100644
index 0000000..08d92bd
--- /dev/null
+++ b/audio/effect/2.0/default/EffectsFactory.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "EffectFactoryHAL"
+#include <media/EffectsFactoryApi.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_agc.h>
+#include <system/audio_effects/effect_bassboost.h>
+#include <system/audio_effects/effect_downmix.h>
+#include <system/audio_effects/effect_environmentalreverb.h>
+#include <system/audio_effects/effect_equalizer.h>
+#include <system/audio_effects/effect_loudnessenhancer.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_presetreverb.h>
+#include <system/audio_effects/effect_virtualizer.h>
+#include <system/audio_effects/effect_visualizer.h>
+#include <android/log.h>
+
+#include "AcousticEchoCancelerEffect.h"
+#include "AutomaticGainControlEffect.h"
+#include "BassBoostEffect.h"
+#include "Conversions.h"
+#include "DownmixEffect.h"
+#include "EffectsFactory.h"
+#include "HidlUtils.h"
+#include "Effect.h"
+#include "EffectMap.h"
+#include "EnvironmentalReverbEffect.h"
+#include "EqualizerEffect.h"
+#include "LoudnessEnhancerEffect.h"
+#include "NoiseSuppressionEffect.h"
+#include "PresetReverbEffect.h"
+#include "VirtualizerEffect.h"
+#include "VisualizerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+// static
+sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(
+ const effect_descriptor_t& halDescriptor, effect_handle_t handle) {
+ const effect_uuid_t *halUuid = &halDescriptor.type;
+ if (memcmp(halUuid, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+ return new AcousticEchoCancelerEffect(handle);
+ } else if (memcmp(halUuid, FX_IID_AGC, sizeof(effect_uuid_t)) == 0) {
+ return new AutomaticGainControlEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_BASSBOOST, sizeof(effect_uuid_t)) == 0) {
+ return new BassBoostEffect(handle);
+ } else if (memcmp(halUuid, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
+ return new DownmixEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_ENVIRONMENTALREVERB, sizeof(effect_uuid_t)) == 0) {
+ return new EnvironmentalReverbEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_EQUALIZER, sizeof(effect_uuid_t)) == 0) {
+ return new EqualizerEffect(handle);
+ } else if (memcmp(halUuid, FX_IID_LOUDNESS_ENHANCER, sizeof(effect_uuid_t)) == 0) {
+ return new LoudnessEnhancerEffect(handle);
+ } else if (memcmp(halUuid, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
+ return new NoiseSuppressionEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
+ return new PresetReverbEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_VIRTUALIZER, sizeof(effect_uuid_t)) == 0) {
+ return new VirtualizerEffect(handle);
+ } else if (memcmp(halUuid, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) {
+ return new VisualizerEffect(handle);
+ }
+ return new Effect(handle);
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow.
+Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) {
+ Result retval(Result::OK);
+ hidl_vec<EffectDescriptor> result;
+ uint32_t numEffects;
+ status_t status;
+
+restart:
+ numEffects = 0;
+ status = EffectQueryNumberEffects(&numEffects);
+ if (status != OK) {
+ retval = Result::NOT_INITIALIZED;
+ ALOGE("Error querying number of effects: %s", strerror(-status));
+ goto exit;
+ }
+ result.resize(numEffects);
+ for (uint32_t i = 0; i < numEffects; ++i) {
+ effect_descriptor_t halDescriptor;
+ status = EffectQueryEffect(i, &halDescriptor);
+ if (status == OK) {
+ effectDescriptorFromHal(halDescriptor, &result[i]);
+ } else {
+ ALOGE("Error querying effect at position %d / %d: %s",
+ i, numEffects, strerror(-status));
+ switch (status) {
+ case -ENOSYS: {
+ // Effect list has changed.
+ goto restart;
+ }
+ case -ENOENT: {
+ // No more effects available.
+ result.resize(i);
+ }
+ default: {
+ result.resize(0);
+ retval = Result::NOT_INITIALIZED;
+ }
+ }
+ break;
+ }
+ }
+
+exit:
+ _hidl_cb(retval, result);
+ return Void();
+}
+
+Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) {
+ effect_uuid_t halUuid;
+ HidlUtils::uuidToHal(uid, &halUuid);
+ effect_descriptor_t halDescriptor;
+ status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
+ EffectDescriptor descriptor;
+ effectDescriptorFromHal(halDescriptor, &descriptor);
+ Result retval(Result::OK);
+ if (status != OK) {
+ ALOGE("Error querying effect descriptor for %s: %s",
+ uuidToString(halUuid).c_str(), strerror(-status));
+ if (status == -ENOENT) {
+ retval = Result::INVALID_ARGUMENTS;
+ } else {
+ retval = Result::NOT_INITIALIZED;
+ }
+ }
+ _hidl_cb(retval, descriptor);
+ return Void();
+}
+
+Return<void> EffectsFactory::createEffect(
+ const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) {
+ effect_uuid_t halUuid;
+ HidlUtils::uuidToHal(uid, &halUuid);
+ effect_handle_t handle;
+ Result retval(Result::OK);
+ status_t status = EffectCreate(&halUuid, session, ioHandle, &handle);
+ sp<IEffect> effect;
+ uint64_t effectId = EffectMap::INVALID_ID;
+ if (status == OK) {
+ effect_descriptor_t halDescriptor;
+ memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
+ status = (*handle)->get_descriptor(handle, &halDescriptor);
+ if (status == OK) {
+ effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+ effectId = EffectMap::getInstance().add(handle);
+ } else {
+ ALOGE("Error querying effect descriptor for %s: %s",
+ uuidToString(halUuid).c_str(), strerror(-status));
+ EffectRelease(handle);
+ }
+ }
+ if (status != OK) {
+ ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status));
+ if (status == -ENOENT) {
+ retval = Result::INVALID_ARGUMENTS;
+ } else {
+ retval = Result::NOT_INITIALIZED;
+ }
+ }
+ _hidl_cb(retval, effect, effectId);
+ return Void();
+}
+
+Return<void> EffectsFactory::debugDump(const hidl_handle& fd) {
+ if (fd->numFds == 1) {
+ EffectDumpEffects(fd->data[0]);
+ }
+ return Void();
+}
+
+
+IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) {
+ return new EffectsFactory();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/EffectsFactory.h b/audio/effect/2.0/default/EffectsFactory.h
new file mode 100644
index 0000000..829a534
--- /dev/null
+++ b/audio/effect/2.0/default/EffectsFactory.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H
+
+#include <system/audio_effect.h>
+
+#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EffectsFactory : public IEffectsFactory {
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow.
+ Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
+ Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override;
+ Return<void> createEffect(
+ const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) override;
+ Return<void> debugDump(const hidl_handle& fd) override;
+
+ private:
+ static sp<IEffect> dispatchEffectInstanceCreation(
+ const effect_descriptor_t& halDescriptor, effect_handle_t handle);
+};
+
+extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
new file mode 100644
index 0000000..86ff368
--- /dev/null
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "EnvReverb_HAL"
+#include <android/log.h>
+
+#include "EnvironmentalReverbEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+EnvironmentalReverbEffect::EnvironmentalReverbEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+EnvironmentalReverbEffect::~EnvironmentalReverbEffect() {}
+
+void EnvironmentalReverbEffect::propertiesFromHal(
+ const t_reverb_settings& halProperties,
+ IEnvironmentalReverbEffect::AllProperties* properties) {
+ properties->roomLevel = halProperties.roomLevel;
+ properties->roomHfLevel = halProperties.roomHFLevel;
+ properties->decayTime = halProperties.decayTime;
+ properties->decayHfRatio = halProperties.decayHFRatio;
+ properties->reflectionsLevel = halProperties.reflectionsLevel;
+ properties->reflectionsDelay = halProperties.reflectionsDelay;
+ properties->reverbLevel = halProperties.reverbLevel;
+ properties->reverbDelay = halProperties.reverbDelay;
+ properties->diffusion = halProperties.diffusion;
+ properties->density = halProperties.density;
+}
+
+void EnvironmentalReverbEffect::propertiesToHal(
+ const IEnvironmentalReverbEffect::AllProperties& properties,
+ t_reverb_settings* halProperties) {
+ halProperties->roomLevel = properties.roomLevel;
+ halProperties->roomHFLevel = properties.roomHfLevel;
+ halProperties->decayTime = properties.decayTime;
+ halProperties->decayHFRatio = properties.decayHfRatio;
+ halProperties->reflectionsLevel = properties.reflectionsLevel;
+ halProperties->reflectionsDelay = properties.reflectionsDelay;
+ halProperties->reverbLevel = properties.reverbLevel;
+ halProperties->reverbDelay = properties.reverbDelay;
+ halProperties->diffusion = properties.diffusion;
+ halProperties->density = properties.density;
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> EnvironmentalReverbEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> EnvironmentalReverbEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EnvironmentalReverbEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> EnvironmentalReverbEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> EnvironmentalReverbEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> EnvironmentalReverbEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> EnvironmentalReverbEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> EnvironmentalReverbEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EnvironmentalReverbEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> EnvironmentalReverbEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> EnvironmentalReverbEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> EnvironmentalReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> EnvironmentalReverbEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> EnvironmentalReverbEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> EnvironmentalReverbEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
+Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass) {
+ return mEffect->setParam(REVERB_PARAM_BYPASS, bypass);
+}
+
+Return<void> EnvironmentalReverbEffect::getBypass(getBypass_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_BYPASS, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setRoomLevel(int16_t roomLevel) {
+ return mEffect->setParam(REVERB_PARAM_ROOM_LEVEL, roomLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getRoomLevel(getRoomLevel_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_ROOM_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setRoomHfLevel(int16_t roomHfLevel) {
+ return mEffect->setParam(REVERB_PARAM_ROOM_HF_LEVEL, roomHfLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_ROOM_HF_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDecayTime(uint32_t decayTime) {
+ return mEffect->setParam(REVERB_PARAM_DECAY_TIME, decayTime);
+}
+
+Return<void> EnvironmentalReverbEffect::getDecayTime(getDecayTime_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_DECAY_TIME, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDecayHfRatio(int16_t decayHfRatio) {
+ return mEffect->setParam(REVERB_PARAM_DECAY_HF_RATIO, decayHfRatio);
+}
+
+Return<void> EnvironmentalReverbEffect::getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_DECAY_HF_RATIO, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReflectionsLevel(int16_t reflectionsLevel) {
+ return mEffect->setParam(REVERB_PARAM_REFLECTIONS_LEVEL, reflectionsLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReflectionsDelay(uint32_t reflectionsDelay) {
+ return mEffect->setParam(REVERB_PARAM_REFLECTIONS_DELAY, reflectionsDelay);
+}
+
+Return<void> EnvironmentalReverbEffect::getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_DELAY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReverbLevel(int16_t reverbLevel) {
+ return mEffect->setParam(REVERB_PARAM_REVERB_LEVEL, reverbLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getReverbLevel(getReverbLevel_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_REVERB_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReverbDelay(uint32_t reverbDelay) {
+ return mEffect->setParam(REVERB_PARAM_REVERB_DELAY, reverbDelay);
+}
+
+Return<void> EnvironmentalReverbEffect::getReverbDelay(getReverbDelay_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_REVERB_DELAY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDiffusion(int16_t diffusion) {
+ return mEffect->setParam(REVERB_PARAM_DIFFUSION, diffusion);
+}
+
+Return<void> EnvironmentalReverbEffect::getDiffusion(getDiffusion_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_DIFFUSION, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDensity(int16_t density) {
+ return mEffect->setParam(REVERB_PARAM_DENSITY, density);
+}
+
+Return<void> EnvironmentalReverbEffect::getDensity(getDensity_cb _hidl_cb) {
+ return mEffect->getIntegerParam(REVERB_PARAM_DENSITY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAllProperties(
+ const IEnvironmentalReverbEffect::AllProperties& properties) {
+ t_reverb_settings halProperties;
+ propertiesToHal(properties, &halProperties);
+ return mEffect->setParam(REVERB_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> EnvironmentalReverbEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+ t_reverb_settings halProperties;
+ Result retval = mEffect->getParam(REVERB_PARAM_PROPERTIES, halProperties);
+ AllProperties properties;
+ propertiesFromHal(halProperties, &properties);
+ _hidl_cb(retval, properties);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.h b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
new file mode 100644
index 0000000..794caac
--- /dev/null
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H
+
+#include <system/audio_effects/effect_environmentalreverb.h>
+
+#include <android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect {
+ explicit EnvironmentalReverbEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
+ Return<Result> setBypass(bool bypass) override;
+ Return<void> getBypass(getBypass_cb _hidl_cb) override;
+ Return<Result> setRoomLevel(int16_t roomLevel) override;
+ Return<void> getRoomLevel(getRoomLevel_cb _hidl_cb) override;
+ Return<Result> setRoomHfLevel(int16_t roomHfLevel) override;
+ Return<void> getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) override;
+ Return<Result> setDecayTime(uint32_t decayTime) override;
+ Return<void> getDecayTime(getDecayTime_cb _hidl_cb) override;
+ Return<Result> setDecayHfRatio(int16_t decayHfRatio) override;
+ Return<void> getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) override;
+ Return<Result> setReflectionsLevel(int16_t reflectionsLevel) override;
+ Return<void> getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) override;
+ Return<Result> setReflectionsDelay(uint32_t reflectionsDelay) override;
+ Return<void> getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) override;
+ Return<Result> setReverbLevel(int16_t reverbLevel) override;
+ Return<void> getReverbLevel(getReverbLevel_cb _hidl_cb) override;
+ Return<Result> setReverbDelay(uint32_t reverbDelay) override;
+ Return<void> getReverbDelay(getReverbDelay_cb _hidl_cb) override;
+ Return<Result> setDiffusion(int16_t diffusion) override;
+ Return<void> getDiffusion(getDiffusion_cb _hidl_cb) override;
+ Return<Result> setDensity(int16_t density) override;
+ Return<void> getDensity(getDensity_cb _hidl_cb) override;
+ Return<Result> setAllProperties(
+ const IEnvironmentalReverbEffect::AllProperties& properties) override;
+ Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~EnvironmentalReverbEffect();
+
+ void propertiesFromHal(
+ const t_reverb_settings& halProperties,
+ IEnvironmentalReverbEffect::AllProperties* properties);
+ void propertiesToHal(
+ const IEnvironmentalReverbEffect::AllProperties& properties,
+ t_reverb_settings* halProperties);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp
new file mode 100644
index 0000000..808d8eb
--- /dev/null
+++ b/audio/effect/2.0/default/EqualizerEffect.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <memory.h>
+
+#define LOG_TAG "Equalizer_HAL"
+#include <android/log.h>
+
+#include "EqualizerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+EqualizerEffect::EqualizerEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+EqualizerEffect::~EqualizerEffect() {}
+
+void EqualizerEffect::propertiesFromHal(
+ const t_equalizer_settings& halProperties,
+ IEqualizerEffect::AllProperties* properties) {
+ properties->curPreset = halProperties.curPreset;
+ // t_equalizer_settings incorrectly defines bandLevels as uint16_t,
+ // whereas the actual type of values used by effects is int16_t.
+ const int16_t* signedBandLevels =
+ reinterpret_cast<const int16_t*>(&halProperties.bandLevels[0]);
+ properties->bandLevels.setToExternal(
+ const_cast<int16_t*>(signedBandLevels), halProperties.numBands);
+}
+
+std::vector<uint8_t> EqualizerEffect::propertiesToHal(
+ const IEqualizerEffect::AllProperties& properties,
+ t_equalizer_settings** halProperties) {
+ size_t bandsSize = properties.bandLevels.size() * sizeof(uint16_t);
+ std::vector<uint8_t> halBuffer(sizeof(t_equalizer_settings) + bandsSize, 0);
+ *halProperties = reinterpret_cast<t_equalizer_settings*>(&halBuffer[0]);
+ (*halProperties)->curPreset = properties.curPreset;
+ (*halProperties)->numBands = properties.bandLevels.size();
+ memcpy((*halProperties)->bandLevels, &properties.bandLevels[0], bandsSize);
+ return halBuffer;
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> EqualizerEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> EqualizerEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EqualizerEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> EqualizerEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> EqualizerEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> EqualizerEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> EqualizerEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> EqualizerEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> EqualizerEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EqualizerEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> EqualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> EqualizerEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> EqualizerEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> EqualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> EqualizerEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> EqualizerEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> EqualizerEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
+Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) {
+ return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) {
+ int16_t halLevels[2] = { 0, 0 };
+ Result retval = mEffect->getParam(EQ_PARAM_LEVEL_RANGE, halLevels);
+ _hidl_cb(retval, halLevels[0], halLevels[1]);
+ return Void();
+}
+
+Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) {
+ return mEffect->setParam(EQ_PARAM_BAND_LEVEL, band, level);
+}
+
+Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) {
+ int16_t halLevel = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_BAND_LEVEL, band, halLevel);
+ _hidl_cb(retval, halLevel);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandCenterFrequency(
+ uint16_t band, getBandCenterFrequency_cb _hidl_cb) {
+ uint32_t halFreq = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_CENTER_FREQ, band, halFreq);
+ _hidl_cb(retval, halFreq);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandFrequencyRange(
+ uint16_t band, getBandFrequencyRange_cb _hidl_cb) {
+ uint32_t halFreqs[2] = { 0, 0 };
+ Result retval = mEffect->getParam(EQ_PARAM_BAND_FREQ_RANGE, band, halFreqs);
+ _hidl_cb(retval, halFreqs[0], halFreqs[1]);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) {
+ uint16_t halBand = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_GET_BAND, freq, halBand);
+ _hidl_cb(retval, halBand);
+ return Void();
+}
+
+Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb) {
+ uint16_t halPresetCount = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_GET_NUM_OF_PRESETS, halPresetCount);
+ hidl_vec<hidl_string> presetNames;
+ if (retval == Result::OK) {
+ presetNames.resize(halPresetCount);
+ for (uint16_t i = 0; i < halPresetCount; ++i) {
+ char halPresetName[EFFECT_STRING_LEN_MAX];
+ retval = mEffect->getParam(EQ_PARAM_GET_PRESET_NAME, i, halPresetName);
+ if (retval == Result::OK) {
+ presetNames[i] = halPresetName;
+ } else {
+ presetNames.resize(i);
+ }
+ }
+ }
+ _hidl_cb(retval, presetNames);
+ return Void();
+}
+
+Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset) {
+ return mEffect->setParam(EQ_PARAM_CUR_PRESET, preset);
+}
+
+Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb) {
+ return mEffect->getIntegerParam(EQ_PARAM_CUR_PRESET, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setAllProperties(
+ const IEqualizerEffect::AllProperties& properties) {
+ t_equalizer_settings *halPropertiesPtr = nullptr;
+ std::vector<uint8_t> halBuffer = propertiesToHal(properties, &halPropertiesPtr);
+ uint32_t paramId = EQ_PARAM_PROPERTIES;
+ return mEffect->setParameterImpl(
+ sizeof(paramId), ¶mId, halBuffer.size(), halPropertiesPtr);
+}
+
+Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+ uint16_t numBands = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_NUM_BANDS, numBands);
+ AllProperties properties;
+ if (retval != Result::OK) {
+ _hidl_cb(retval, properties);
+ return Void();
+ }
+ size_t valueSize = sizeof(t_equalizer_settings) + sizeof(int16_t) * numBands;
+ uint32_t paramId = EQ_PARAM_PROPERTIES;
+ retval = mEffect->getParameterImpl(
+ sizeof(paramId), ¶mId, valueSize,
+ [&] (uint32_t, const void* valueData) {
+ const t_equalizer_settings* halProperties =
+ reinterpret_cast<const t_equalizer_settings*>(valueData);
+ propertiesFromHal(*halProperties, &properties);
+ });
+ _hidl_cb(retval, properties);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h
new file mode 100644
index 0000000..9e8d75b
--- /dev/null
+++ b/audio/effect/2.0/default/EqualizerEffect.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
+
+#include <vector>
+
+#include <system/audio_effects/effect_equalizer.h>
+
+#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::IEqualizerEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EqualizerEffect : public IEqualizerEffect {
+ explicit EqualizerEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
+ Return<void> getNumBands(getNumBands_cb _hidl_cb) override;
+ Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override;
+ Return<Result> setBandLevel(uint16_t band, int16_t level) override;
+ Return<void> getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) override;
+ Return<void> getBandCenterFrequency(
+ uint16_t band, getBandCenterFrequency_cb _hidl_cb) override;
+ Return<void> getBandFrequencyRange(uint16_t band, getBandFrequencyRange_cb _hidl_cb) override;
+ Return<void> getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) override;
+ Return<void> getPresetNames(getPresetNames_cb _hidl_cb) override;
+ Return<Result> setCurrentPreset(uint16_t preset) override;
+ Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb) override;
+ Return<Result> setAllProperties(const IEqualizerEffect::AllProperties& properties) override;
+ Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~EqualizerEffect();
+
+ void propertiesFromHal(
+ const t_equalizer_settings& halProperties,
+ IEqualizerEffect::AllProperties* properties);
+ std::vector<uint8_t> propertiesToHal(
+ const IEqualizerEffect::AllProperties& properties,
+ t_equalizer_settings** halProperties);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
new file mode 100644
index 0000000..fda5eb0
--- /dev/null
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <system/audio_effects/effect_loudnessenhancer.h>
+
+#define LOG_TAG "LoudnessEnhancer_HAL"
+#include <system/audio_effects/effect_aec.h>
+#include <android/log.h>
+
+#include "LoudnessEnhancerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+LoudnessEnhancerEffect::~LoudnessEnhancerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> LoudnessEnhancerEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> LoudnessEnhancerEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> LoudnessEnhancerEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> LoudnessEnhancerEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> LoudnessEnhancerEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> LoudnessEnhancerEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> LoudnessEnhancerEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> LoudnessEnhancerEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> LoudnessEnhancerEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> LoudnessEnhancerEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> LoudnessEnhancerEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> LoudnessEnhancerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> LoudnessEnhancerEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> LoudnessEnhancerEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> LoudnessEnhancerEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
+Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) {
+ return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb);
+}
+
+Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) {
+ // AOSP Loudness Enhancer expects the size of the request to not include the
+ // size of the parameter.
+ uint32_t paramId = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
+ uint32_t targetGainMb = 0;
+ Result retval = mEffect->getParameterImpl(
+ sizeof(paramId), ¶mId,
+ 0, sizeof(targetGainMb),
+ [&] (uint32_t, const void* valueData) {
+ memcpy(&targetGainMb, valueData, sizeof(targetGainMb));
+ });
+ _hidl_cb(retval, targetGainMb);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.h b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
new file mode 100644
index 0000000..039b8d6
--- /dev/null
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
+
+#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect {
+ explicit LoudnessEnhancerEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
+ Return<Result> setTargetGain(int32_t targetGainMb) override;
+ Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~LoudnessEnhancerEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
new file mode 100644
index 0000000..7c4e06d
--- /dev/null
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "NS_Effect_HAL"
+#include <android/log.h>
+
+#include "NoiseSuppressionEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+NoiseSuppressionEffect::NoiseSuppressionEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+NoiseSuppressionEffect::~NoiseSuppressionEffect() {}
+
+void NoiseSuppressionEffect::propertiesFromHal(
+ const t_ns_settings& halProperties,
+ INoiseSuppressionEffect::AllProperties* properties) {
+ properties->level = Level(halProperties.level);
+ properties->type = Type(halProperties.type);
+}
+
+void NoiseSuppressionEffect::propertiesToHal(
+ const INoiseSuppressionEffect::AllProperties& properties,
+ t_ns_settings* halProperties) {
+ halProperties->level = static_cast<uint32_t>(properties.level);
+ halProperties->type = static_cast<uint32_t>(properties.type);
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> NoiseSuppressionEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> NoiseSuppressionEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> NoiseSuppressionEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> NoiseSuppressionEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> NoiseSuppressionEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> NoiseSuppressionEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> NoiseSuppressionEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> NoiseSuppressionEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> NoiseSuppressionEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> NoiseSuppressionEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> NoiseSuppressionEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> NoiseSuppressionEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> NoiseSuppressionEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> NoiseSuppressionEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> NoiseSuppressionEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> NoiseSuppressionEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> NoiseSuppressionEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
+Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level) {
+ return mEffect->setParam(NS_PARAM_LEVEL, static_cast<int32_t>(level));
+}
+
+Return<void> NoiseSuppressionEffect::getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) {
+ int32_t halLevel = 0;
+ Result retval = mEffect->getParam(NS_PARAM_LEVEL, halLevel);
+ _hidl_cb(retval, Level(halLevel));
+ return Void();
+}
+
+Return<Result> NoiseSuppressionEffect::setSuppressionType(INoiseSuppressionEffect::Type type) {
+ return mEffect->setParam(NS_PARAM_TYPE, static_cast<int32_t>(type));
+}
+
+Return<void> NoiseSuppressionEffect::getSuppressionType(getSuppressionType_cb _hidl_cb) {
+ int32_t halType = 0;
+ Result retval = mEffect->getParam(NS_PARAM_TYPE, halType);
+ _hidl_cb(retval, Type(halType));
+ return Void();
+}
+
+Return<Result> NoiseSuppressionEffect::setAllProperties(
+ const INoiseSuppressionEffect::AllProperties& properties) {
+ t_ns_settings halProperties;
+ propertiesToHal(properties, &halProperties);
+ return mEffect->setParam(NS_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> NoiseSuppressionEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+ t_ns_settings halProperties;
+ Result retval = mEffect->getParam(NS_PARAM_PROPERTIES, halProperties);
+ AllProperties properties;
+ propertiesFromHal(halProperties, &properties);
+ _hidl_cb(retval, properties);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.h b/audio/effect/2.0/default/NoiseSuppressionEffect.h
new file mode 100644
index 0000000..5491201
--- /dev/null
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
+
+#include <system/audio_effects/effect_ns.h>
+
+#include <android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct NoiseSuppressionEffect : public INoiseSuppressionEffect {
+ explicit NoiseSuppressionEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
+ Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level) override;
+ Return<void> getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) override;
+ Return<Result> setSuppressionType(INoiseSuppressionEffect::Type type) override;
+ Return<void> getSuppressionType(getSuppressionType_cb _hidl_cb) override;
+ Return<Result> setAllProperties(
+ const INoiseSuppressionEffect::AllProperties& properties) override;
+ Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~NoiseSuppressionEffect();
+
+ void propertiesFromHal(
+ const t_ns_settings& halProperties,
+ INoiseSuppressionEffect::AllProperties* properties);
+ void propertiesToHal(
+ const INoiseSuppressionEffect::AllProperties& properties,
+ t_ns_settings* halProperties);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
diff --git a/audio/effect/2.0/default/PresetReverbEffect.cpp b/audio/effect/2.0/default/PresetReverbEffect.cpp
new file mode 100644
index 0000000..5f17791
--- /dev/null
+++ b/audio/effect/2.0/default/PresetReverbEffect.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "PresetReverb_HAL"
+#include <system/audio_effects/effect_presetreverb.h>
+#include <android/log.h>
+
+#include "PresetReverbEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+PresetReverbEffect::PresetReverbEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+PresetReverbEffect::~PresetReverbEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> PresetReverbEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> PresetReverbEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> PresetReverbEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> PresetReverbEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> PresetReverbEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> PresetReverbEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> PresetReverbEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> PresetReverbEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> PresetReverbEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> PresetReverbEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> PresetReverbEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> PresetReverbEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> PresetReverbEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> PresetReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> PresetReverbEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> PresetReverbEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> PresetReverbEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
+Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset) {
+ return mEffect->setParam(REVERB_PARAM_PRESET, static_cast<t_reverb_presets>(preset));
+}
+
+Return<void> PresetReverbEffect::getPreset(getPreset_cb _hidl_cb) {
+ t_reverb_presets halPreset = REVERB_PRESET_NONE;
+ Result retval = mEffect->getParam(REVERB_PARAM_PRESET, halPreset);
+ _hidl_cb(retval, Preset(halPreset));
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/PresetReverbEffect.h b/audio/effect/2.0/default/PresetReverbEffect.h
new file mode 100644
index 0000000..4eb074a
--- /dev/null
+++ b/audio/effect/2.0/default/PresetReverbEffect.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IPresetReverbEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::IPresetReverbEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct PresetReverbEffect : public IPresetReverbEffect {
+ explicit PresetReverbEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
+ Return<Result> setPreset(IPresetReverbEffect::Preset preset) override;
+ Return<void> getPreset(getPreset_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~PresetReverbEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/VirtualizerEffect.cpp b/audio/effect/2.0/default/VirtualizerEffect.cpp
new file mode 100644
index 0000000..c1fe52f
--- /dev/null
+++ b/audio/effect/2.0/default/VirtualizerEffect.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <memory.h>
+
+#define LOG_TAG "Virtualizer_HAL"
+#include <system/audio_effects/effect_virtualizer.h>
+#include <android/log.h>
+
+#include "VirtualizerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+VirtualizerEffect::VirtualizerEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)) {
+}
+
+VirtualizerEffect::~VirtualizerEffect() {}
+
+void VirtualizerEffect::speakerAnglesFromHal(
+ const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles) {
+ speakerAngles.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ speakerAngles[i].mask = AudioChannelMask(*halAngles++);
+ speakerAngles[i].azimuth = *halAngles++;
+ speakerAngles[i].elevation = *halAngles++;
+ }
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> VirtualizerEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> VirtualizerEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VirtualizerEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> VirtualizerEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> VirtualizerEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> VirtualizerEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> VirtualizerEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> VirtualizerEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> VirtualizerEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VirtualizerEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> VirtualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> VirtualizerEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> VirtualizerEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> VirtualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> VirtualizerEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> VirtualizerEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> VirtualizerEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
+Return<bool> VirtualizerEffect::isStrengthSupported() {
+ bool halSupported = false;
+ mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported);
+ return halSupported;
+}
+
+Return<Result> VirtualizerEffect::setStrength(uint16_t strength) {
+ return mEffect->setParam(VIRTUALIZER_PARAM_STRENGTH, strength);
+}
+
+Return<void> VirtualizerEffect::getStrength(getStrength_cb _hidl_cb) {
+ return mEffect->getIntegerParam(VIRTUALIZER_PARAM_STRENGTH, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getVirtualSpeakerAngles(
+ AudioChannelMask mask, AudioDevice device, getVirtualSpeakerAngles_cb _hidl_cb) {
+ uint32_t channelCount = audio_channel_count_from_out_mask(
+ static_cast<audio_channel_mask_t>(mask));
+ size_t halSpeakerAnglesSize = sizeof(int32_t) * 3 * channelCount;
+ uint32_t halParam[3] = {
+ VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES,
+ static_cast<audio_channel_mask_t>(mask),
+ static_cast<audio_devices_t>(device)
+ };
+ hidl_vec<SpeakerAngle> speakerAngles;
+ Result retval = mEffect->getParameterImpl(
+ sizeof(halParam), halParam,
+ halSpeakerAnglesSize,
+ [&] (uint32_t valueSize, const void* valueData) {
+ if (valueSize > halSpeakerAnglesSize) {
+ valueSize = halSpeakerAnglesSize;
+ } else if (valueSize < halSpeakerAnglesSize) {
+ channelCount = valueSize / (sizeof(int32_t) * 3);
+ }
+ speakerAnglesFromHal(
+ reinterpret_cast<const int32_t*>(valueData), channelCount, speakerAngles);
+ });
+ _hidl_cb(retval, speakerAngles);
+ return Void();
+}
+
+Return<Result> VirtualizerEffect::forceVirtualizationMode(AudioDevice device) {
+ return mEffect->setParam(
+ VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, static_cast<audio_devices_t>(device));
+}
+
+Return<void> VirtualizerEffect::getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) {
+ uint32_t halMode = 0;
+ Result retval = mEffect->getParam(VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, halMode);
+ _hidl_cb(retval, AudioDevice(halMode));
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/VirtualizerEffect.h b/audio/effect/2.0/default/VirtualizerEffect.h
new file mode 100644
index 0000000..536775f
--- /dev/null
+++ b/audio/effect/2.0/default/VirtualizerEffect.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IVirtualizerEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::IVirtualizerEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct VirtualizerEffect : public IVirtualizerEffect {
+ explicit VirtualizerEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
+ Return<bool> isStrengthSupported() override;
+ Return<Result> setStrength(uint16_t strength) override;
+ Return<void> getStrength(getStrength_cb _hidl_cb) override;
+ Return<void> getVirtualSpeakerAngles(
+ AudioChannelMask mask,
+ AudioDevice device,
+ getVirtualSpeakerAngles_cb _hidl_cb) override;
+ Return<Result> forceVirtualizationMode(AudioDevice device) override;
+ Return<void> getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+
+ virtual ~VirtualizerEffect();
+
+ void speakerAnglesFromHal(
+ const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/VisualizerEffect.cpp b/audio/effect/2.0/default/VisualizerEffect.cpp
new file mode 100644
index 0000000..2cd3240
--- /dev/null
+++ b/audio/effect/2.0/default/VisualizerEffect.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "Visualizer_HAL"
+#include <system/audio_effects/effect_visualizer.h>
+#include <android/log.h>
+
+#include "VisualizerEffect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+VisualizerEffect::VisualizerEffect(effect_handle_t handle)
+ : mEffect(new Effect(handle)), mCaptureSize(0), mMeasurementMode(MeasurementMode::NONE) {
+}
+
+VisualizerEffect::~VisualizerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+Return<Result> VisualizerEffect::init() {
+ return mEffect->init();
+}
+
+Return<Result> VisualizerEffect::setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VisualizerEffect::reset() {
+ return mEffect->reset();
+}
+
+Return<Result> VisualizerEffect::enable() {
+ return mEffect->enable();
+}
+
+Return<Result> VisualizerEffect::disable() {
+ return mEffect->disable();
+}
+
+Return<Result> VisualizerEffect::setDevice(AudioDevice device) {
+ return mEffect->setDevice(device);
+}
+
+Return<void> VisualizerEffect::setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
+ return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::volumeChangeNotification(
+ const hidl_vec<uint32_t>& volumes) {
+ return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> VisualizerEffect::setAudioMode(AudioMode mode) {
+ return mEffect->setAudioMode(mode);
+}
+
+Return<Result> VisualizerEffect::setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+ return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VisualizerEffect::setInputDevice(AudioDevice device) {
+ return mEffect->setInputDevice(device);
+}
+
+Return<void> VisualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+ return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+ return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+ return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+ return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setAuxChannelsConfig(
+ const EffectAuxChannelsConfig& config) {
+ return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> VisualizerEffect::setAudioSource(AudioSource source) {
+ return mEffect->setAudioSource(source);
+}
+
+Return<Result> VisualizerEffect::offload(const EffectOffloadParameter& param) {
+ return mEffect->offload(param);
+}
+
+Return<void> VisualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+ return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::prepareForProcessing(
+ prepareForProcessing_cb _hidl_cb) {
+ return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+ return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> VisualizerEffect::command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) {
+ return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
+ return mEffect->setParameter(parameter, value);
+}
+
+Return<void> VisualizerEffect::getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) {
+ return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) {
+ return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) {
+ return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+ return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> VisualizerEffect::close() {
+ return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
+Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize) {
+ Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize);
+ if (retval == Result::OK) {
+ mCaptureSize = captureSize;
+ }
+ return retval;
+}
+
+Return<void> VisualizerEffect::getCaptureSize(getCaptureSize_cb _hidl_cb) {
+ return mEffect->getIntegerParam(VISUALIZER_PARAM_CAPTURE_SIZE, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setScalingMode(IVisualizerEffect::ScalingMode scalingMode) {
+ return mEffect->setParam(VISUALIZER_PARAM_SCALING_MODE, static_cast<int32_t>(scalingMode));
+}
+
+Return<void> VisualizerEffect::getScalingMode(getScalingMode_cb _hidl_cb) {
+ int32_t halMode;
+ Result retval = mEffect->getParam(VISUALIZER_PARAM_SCALING_MODE, halMode);
+ _hidl_cb(retval, ScalingMode(halMode));
+ return Void();
+}
+
+Return<Result> VisualizerEffect::setLatency(uint32_t latencyMs) {
+ return mEffect->setParam(VISUALIZER_PARAM_LATENCY, latencyMs);
+}
+
+Return<void> VisualizerEffect::getLatency(getLatency_cb _hidl_cb) {
+ return mEffect->getIntegerParam(VISUALIZER_PARAM_LATENCY, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setMeasurementMode(
+ IVisualizerEffect::MeasurementMode measurementMode) {
+ Result retval = mEffect->setParam(
+ VISUALIZER_PARAM_MEASUREMENT_MODE, static_cast<int32_t>(measurementMode));
+ if (retval == Result::OK) {
+ mMeasurementMode = measurementMode;
+ }
+ return retval;
+}
+
+Return<void> VisualizerEffect::getMeasurementMode(getMeasurementMode_cb _hidl_cb) {
+ int32_t halMode;
+ Result retval = mEffect->getParam(VISUALIZER_PARAM_MEASUREMENT_MODE, halMode);
+ _hidl_cb(retval, MeasurementMode(halMode));
+ return Void();
+}
+
+Return<void> VisualizerEffect::capture(capture_cb _hidl_cb) {
+ if (mCaptureSize == 0) {
+ _hidl_cb(Result::NOT_INITIALIZED, hidl_vec<uint8_t>());
+ return Void();
+ }
+ uint32_t halCaptureSize = mCaptureSize;
+ uint8_t halCapture[mCaptureSize];
+ Result retval = mEffect->sendCommandReturningData(
+ VISUALIZER_CMD_CAPTURE, "VISUALIZER_CAPTURE", &halCaptureSize, halCapture);
+ hidl_vec<uint8_t> capture;
+ if (retval == Result::OK) {
+ capture.setToExternal(&halCapture[0], halCaptureSize);
+ }
+ _hidl_cb(retval, capture);
+ return Void();
+}
+
+Return<void> VisualizerEffect::measure(measure_cb _hidl_cb) {
+ if (mMeasurementMode == MeasurementMode::NONE) {
+ _hidl_cb(Result::NOT_INITIALIZED, Measurement());
+ return Void();
+ }
+ int32_t halMeasurement[MEASUREMENT_COUNT];
+ uint32_t halMeasurementSize = sizeof(halMeasurement);
+ Result retval = mEffect->sendCommandReturningData(
+ VISUALIZER_CMD_MEASURE, "VISUALIZER_MEASURE", &halMeasurementSize, halMeasurement);
+ Measurement measurement = { .mode = MeasurementMode::PEAK_RMS };
+ measurement.value.peakAndRms.peakMb = 0;
+ measurement.value.peakAndRms.rmsMb = 0;
+ if (retval == Result::OK) {
+ measurement.value.peakAndRms.peakMb = halMeasurement[MEASUREMENT_IDX_PEAK];
+ measurement.value.peakAndRms.rmsMb = halMeasurement[MEASUREMENT_IDX_RMS];
+ }
+ _hidl_cb(retval, measurement);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/default/VisualizerEffect.h b/audio/effect/2.0/default/VisualizerEffect.h
new file mode 100644
index 0000000..fd40ca8
--- /dev/null
+++ b/audio/effect/2.0/default/VisualizerEffect.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
+
+#include <android/hardware/audio/effect/2.0/IVisualizerEffect.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "Effect.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
+using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
+using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::V2_0::IVisualizerEffect;
+using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct VisualizerEffect : public IVisualizerEffect {
+ explicit VisualizerEffect(effect_handle_t handle);
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
+ Return<Result> init() override;
+ Return<Result> setConfig(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> reset() override;
+ Return<Result> enable() override;
+ Return<Result> disable() override;
+ Return<Result> setDevice(AudioDevice device) override;
+ Return<void> setAndGetVolume(
+ const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override;
+ Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+ Return<Result> setAudioMode(AudioMode mode) override;
+ Return<Result> setConfigReverse(
+ const EffectConfig& config,
+ const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+ const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+ Return<Result> setInputDevice(AudioDevice device) override;
+ Return<void> getConfig(getConfig_cb _hidl_cb) override;
+ Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+ Return<void> getSupportedAuxChannelsConfigs(
+ uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+ Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+ Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+ Return<Result> setAudioSource(AudioSource source) override;
+ Return<Result> offload(const EffectOffloadParameter& param) override;
+ Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+ Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+ Return<Result> setProcessBuffers(
+ const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override;
+ Return<void> command(
+ uint32_t commandId,
+ const hidl_vec<uint8_t>& data,
+ uint32_t resultMaxSize,
+ command_cb _hidl_cb) override;
+ Return<Result> setParameter(
+ const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override;
+ Return<void> getParameter(
+ const hidl_vec<uint8_t>& parameter,
+ uint32_t valueMaxSize,
+ getParameter_cb _hidl_cb) override;
+ Return<void> getSupportedConfigsForFeature(
+ uint32_t featureId,
+ uint32_t maxConfigs,
+ uint32_t configSize,
+ getSupportedConfigsForFeature_cb _hidl_cb) override;
+ Return<void> getCurrentConfigForFeature(
+ uint32_t featureId,
+ uint32_t configSize,
+ getCurrentConfigForFeature_cb _hidl_cb) override;
+ Return<Result> setCurrentConfigForFeature(
+ uint32_t featureId, const hidl_vec<uint8_t>& configData) override;
+ Return<Result> close() override;
+
+ // Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
+ Return<Result> setCaptureSize(uint16_t captureSize) override;
+ Return<void> getCaptureSize(getCaptureSize_cb _hidl_cb) override;
+ Return<Result> setScalingMode(IVisualizerEffect::ScalingMode scalingMode) override;
+ Return<void> getScalingMode(getScalingMode_cb _hidl_cb) override;
+ Return<Result> setLatency(uint32_t latencyMs) override;
+ Return<void> getLatency(getLatency_cb _hidl_cb) override;
+ Return<Result> setMeasurementMode(IVisualizerEffect::MeasurementMode measurementMode) override;
+ Return<void> getMeasurementMode(getMeasurementMode_cb _hidl_cb) override;
+ Return<void> capture(capture_cb _hidl_cb) override;
+ Return<void> measure(measure_cb _hidl_cb) override;
+
+ private:
+ sp<Effect> mEffect;
+ uint16_t mCaptureSize;
+ MeasurementMode mMeasurementMode;
+
+ virtual ~VisualizerEffect();
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
diff --git a/audio/effect/2.0/types.hal b/audio/effect/2.0/types.hal
new file mode 100644
index 0000000..0626ec5
--- /dev/null
+++ b/audio/effect/2.0/types.hal
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2016 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.audio.effect@2.0;
+
+import android.hardware.audio.common@2.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ NOT_SUPPORTED,
+ RESULT_TOO_BIG
+};
+
+/*
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description | bits | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection | 0..2 | 0 insert: after track process
+ * | mode | | 1 auxiliary: connect to track auxiliary
+ * | | | output and use send level
+ * | | | 2 replace: replaces track process function;
+ * | | | must implement SRC, volume and mono to stereo.
+ * | | | 3 pre processing: applied below audio HAL on in
+ * | | | 4 post processing: applied below audio HAL on out
+ * | | | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion | 3..5 | 0 none
+ * | preference | | 1 first of the chain
+ * | | | 2 last of the chain
+ * | | | 3 exclusive (only effect in the insert chain)
+ * | | | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume | 6..8 | 0 none
+ * | management | | 1 implements volume control
+ * | | | 2 requires volume indication
+ * | | | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device | 9..11 | 0 none
+ * | indication | | 1 requires device updates
+ * | | | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input | 12..13 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request input.
+ * | | | buffers.
+ * | | | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output | 14..15 | 1 direct: process() function or
+ * | mode | | EFFECT_CMD_SET_CONFIG command must specify
+ * | | | a buffer descriptor
+ * | | | 2 provider: process() function uses the
+ * | | | bufferProvider indicated by the
+ * | | | EFFECT_CMD_SET_CONFIG command to request output
+ * | | | buffers.
+ * | | | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware | 16..17 | 0 No hardware acceleration
+ * | acceleration | | 1 non tunneled hw acceleration: the process()
+ * | | | function reads the samples, send them to HW
+ * | | | accelerated effect processor, reads back
+ * | | | the processed samples and returns them
+ * | | | to the output buffer.
+ * | | | 2 tunneled hw acceleration: the process()
+ * | | | function is transparent. The effect interface
+ * | | | is only used to control the effect engine.
+ * | | | This mode is relevant for global effects
+ * | | | actually applied by the audio hardware on
+ * | | | the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode | 18..19 | 0 none
+ * | indication | | 1 requires audio mode updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source | 20..21 | 0 none
+ * | indication | | 1 requires audio source updates
+ * | | | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22 | 0 The effect cannot be offloaded to an audio DSP
+ * | supported | | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process | 23 | 0 The effect implements a process function.
+ * | function | | 1 The effect does not implement a process
+ * | not | | function: enabling the effect has no impact
+ * | implemented | | on latency or CPU load.
+ * | | | Effect implementations setting this flag do not
+ * | | | have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+ // Insert mode
+ TYPE_SHIFT = 0,
+ TYPE_SIZE = 3,
+ TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+ TYPE_INSERT = 0 << TYPE_SHIFT,
+ TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+ TYPE_REPLACE = 2 << TYPE_SHIFT,
+ TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+ TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+ // Insert preference
+ INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+ INSERT_SIZE = 3,
+ INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+ INSERT_ANY = 0 << INSERT_SHIFT,
+ INSERT_FIRST = 1 << INSERT_SHIFT,
+ INSERT_LAST = 2 << INSERT_SHIFT,
+ INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+ // Volume control
+ VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+ VOLUME_SIZE = 3,
+ VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+ VOLUME_CTRL = 1 << VOLUME_SHIFT,
+ VOLUME_IND = 2 << VOLUME_SHIFT,
+ VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+ // Device indication
+ DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+ DEVICE_SIZE = 3,
+ DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+ DEVICE_IND = 1 << DEVICE_SHIFT,
+ DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+ // Sample input modes
+ INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+ INPUT_SIZE = 2,
+ INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+ INPUT_DIRECT = 1 << INPUT_SHIFT,
+ INPUT_PROVIDER = 2 << INPUT_SHIFT,
+ INPUT_BOTH = 3 << INPUT_SHIFT,
+
+ // Sample output modes
+ OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+ OUTPUT_SIZE = 2,
+ OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+ OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+ OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+ OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+ // Hardware acceleration mode
+ HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+ HW_ACC_SIZE = 2,
+ HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+ HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+ HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+ // Audio mode indication
+ AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+ AUDIO_MODE_SIZE = 2,
+ AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+ AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+ // Audio source indication
+ AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+ AUDIO_SOURCE_SIZE = 2,
+ AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+ AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+ // Effect offload indication
+ OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+ OFFLOAD_SIZE = 1,
+ OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+ OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+ // Effect has no process indication
+ NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+ NO_PROCESS_SIZE = 1,
+ NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+ NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/*
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+ Uuid type; // UUID of to the OpenSL ES interface implemented
+ // by this effect
+ Uuid uuid; // UUID for this particular implementation
+ EffectFlags flags; // effect engine capabilities/requirements flags
+ uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units
+ // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+ uint16_t memoryUsage; // data memory usage expressed in KB and includes
+ // only dynamically allocated memory
+ uint8_t[64] name; // human readable effect name
+ uint8_t[64] implementor; // human readable effect implementor name
+};
+
+/*
+ * A buffer is a chunk of audio data for processing. Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+ uint64_t id;
+ uint32_t frameCount;
+ memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+ ACCESS_WRITE,
+ ACCESS_READ,
+ ACCESS_ACCUMULATE
+};
+
+/*
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+ BUFFER = 0x0001, // buffer field
+ SMP_RATE = 0x0002, // samplingRate
+ CHANNELS = 0x0004, // channels
+ FORMAT = 0x0008, // format
+ ACC_MODE = 0x0010, // accessMode
+ ALL = BUFFER | SMP_RATE | CHANNELS | FORMAT | ACC_MODE
+};
+
+/*
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+ AudioBuffer buffer;
+ uint32_t samplingRateHz;
+ AudioChannelMask channels;
+ AudioFormat format;
+ EffectBufferAccess accessMode;
+ EffectConfigParameters mask;
+};
+
+struct EffectConfig {
+ EffectBufferConfig inputCfg;
+ EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+ AUX_CHANNELS, // supports auxiliary channels
+ // (e.g. dual mic noise suppressor)
+ CNT
+};
+
+struct EffectAuxChannelsConfig {
+ AudioChannelMask mainChannels; // channel mask for main channels
+ AudioChannelMask auxChannels; // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+ bool isOffload; // true if the playback thread the effect
+ // is attached to is offloaded
+ AudioIoHandle ioHandle; // io handle of the playback thread
+ // the effect is attached to
+};
+
+/*
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ DONE_PROCESSING = 1 << 0,
+ REQUEST_PROCESS = 1 << 1,
+ REQUEST_PROCESS_REVERSE = 1 << 2,
+ REQUEST_QUIT = 1 << 3,
+ REQUEST_PROCESS_ALL =
+ REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/2.0/vts/Android.mk b/audio/effect/2.0/vts/Android.mk
new file mode 100644
index 0000000..abdd5bf
--- /dev/null
+++ b/audio/effect/2.0/vts/Android.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..8a370cd
--- /dev/null
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalAudioEffectV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalAudioEffectV2_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.audio.effect@2.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
new file mode 100644
index 0000000..f6da213
--- /dev/null
+++ b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "AudioEffectHidlHalTest"
+#include <android-base/logging.h>
+#include <system/audio.h>
+
+#include <android/hardware/audio/effect/2.0/IEffect.h>
+#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h>
+#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h>
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using android::hardware::audio::common::V2_0::AudioDevice;
+using android::hardware::audio::common::V2_0::AudioHandleConsts;
+using android::hardware::audio::common::V2_0::AudioMode;
+using android::hardware::audio::common::V2_0::Uuid;
+using android::hardware::audio::effect::V2_0::AudioBuffer;
+using android::hardware::audio::effect::V2_0::EffectBufferConfig;
+using android::hardware::audio::effect::V2_0::EffectConfig;
+using android::hardware::audio::effect::V2_0::EffectDescriptor;
+using android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using android::hardware::audio::effect::V2_0::IEffect;
+using android::hardware::audio::effect::V2_0::IEffectsFactory;
+using android::hardware::audio::effect::V2_0::IEqualizerEffect;
+using android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect;
+using android::hardware::audio::effect::V2_0::Result;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::hidl_memory;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+using android::sp;
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
+// The main test class for Audio Effects Factory HIDL HAL.
+class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ effectsFactory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+ ASSERT_NE(effectsFactory, nullptr);
+ }
+
+ void TearDown() override { effectsFactory.clear(); }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<IEffectsFactory> effectsFactory;
+};
+
+TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+ description("Verify that EnumerateEffects returns at least one effect");
+ Result retval = Result::NOT_INITIALIZED;
+ size_t effectCount = 0;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ retval = r;
+ effectCount = result.size();
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_GT(effectCount, 0u);
+}
+
+TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+ description("Verify that an effect can be created via CreateEffect");
+ bool gotEffect = false;
+ Uuid effectUuid;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK && result.size() > 0) {
+ gotEffect = true;
+ effectUuid = result[0].uuid;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(gotEffect);
+ Result retval = Result::NOT_INITIALIZED;
+ sp<IEffect> effect;
+ ret = effectsFactory->createEffect(
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ retval = r;
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_NE(nullptr, effect.get());
+}
+
+TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+ description(
+ "Verify that effects factory can provide an effect descriptor via "
+ "GetDescriptor");
+ hidl_vec<EffectDescriptor> allDescriptors;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK) {
+ allDescriptors = result;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_GT(allDescriptors.size(), 0u);
+ for (size_t i = 0; i < allDescriptors.size(); ++i) {
+ ret = effectsFactory->getDescriptor(
+ allDescriptors[i].uuid, [&](Result r, const EffectDescriptor& result) {
+ EXPECT_EQ(r, Result::OK);
+ EXPECT_EQ(result, allDescriptors[i]);
+ });
+ }
+ EXPECT_TRUE(ret.isOk());
+}
+
+// Equalizer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java.
+static const Uuid EQUALIZER_EFFECT_TYPE = {
+ 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+ std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}};
+// Loudness Enhancer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java.
+static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = {
+ 0xfe3199be, 0xaed0, 0x413f, 0x87bb,
+ std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
+
+// The main test class for Audio Effect HIDL HAL.
+class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ effectsFactory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+ ASSERT_NE(nullptr, effectsFactory.get());
+
+ findAndCreateEffect(getEffectType());
+ ASSERT_NE(nullptr, effect.get());
+
+ Return<Result> ret = effect->init();
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, ret);
+ }
+
+ void TearDown() override {
+ effect.clear();
+ effectsFactory.clear();
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; }
+
+ void findAndCreateEffect(const Uuid& type);
+ void findEffectInstance(const Uuid& type, Uuid* uuid);
+ void getChannelCount(uint32_t* channelCount);
+
+ sp<IEffectsFactory> effectsFactory;
+ sp<IEffect> effect;
+};
+
+void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
+ Uuid effectUuid;
+ findEffectInstance(type, &effectUuid);
+ Return<void> ret = effectsFactory->createEffect(
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) {
+ bool effectFound = false;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK) {
+ for (const auto& desc : result) {
+ if (desc.type == type) {
+ effectFound = true;
+ *uuid = desc.uuid;
+ break;
+ }
+ }
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(effectFound);
+}
+
+void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) {
+ Result retval;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ASSERT_TRUE(audio_channel_mask_is_valid(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
+ *channelCount = audio_channel_count_from_out_mask(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
+}
+
+TEST_F(AudioEffectHidlTest, Close) {
+ description("Verify that an effect can be closed");
+ Return<Result> ret = effect->close();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, GetDescriptor) {
+ description(
+ "Verify that an effect can return its own descriptor via GetDescriptor");
+ Result retval = Result::NOT_INITIALIZED;
+ Uuid actualType;
+ Return<void> ret =
+ effect->getDescriptor([&](Result r, const EffectDescriptor& desc) {
+ retval = r;
+ if (r == Result::OK) {
+ actualType = desc.type;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(getEffectType(), actualType);
+}
+
+TEST_F(AudioEffectHidlTest, GetSetConfig) {
+ description(
+ "Verify that it is possible to manipulate effect config via Get / "
+ "SetConfig");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+// Not generated automatically because AudioBuffer contains
+// instances of hidl_memory which can't be compared properly
+// in general case due to presence of handles.
+//
+// However, in this particular case, handles must not present
+// thus comparison is possible.
+//
+// operator== must be defined in the same namespace as the structures.
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) {
+ return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount &&
+ lhs.data.handle() == nullptr && rhs.data.handle() == nullptr;
+}
+
+inline bool operator==(const EffectBufferConfig& lhs,
+ const EffectBufferConfig& rhs) {
+ return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz &&
+ lhs.channels == rhs.channels && lhs.format == rhs.format &&
+ lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask;
+}
+
+inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) {
+ return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg;
+}
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+TEST_F(AudioEffectHidlTest, Reset) {
+ description("Verify that Reset preserves effect configuration");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig originalConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ originalConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->reset();
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+ EffectConfig configAfterReset;
+ ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ configAfterReset = conf;
+ }
+ });
+ EXPECT_EQ(originalConfig, configAfterReset);
+}
+
+TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+ description("Verify Disable -> Enable -> Disable sequence for an effect");
+ Return<Result> ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, ret);
+ ret = effect->enable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetDevice) {
+ description("Verify that SetDevice works for an output chain effect");
+ Return<Result> ret = effect->setDevice(AudioDevice::OUT_SPEAKER);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+ description("Verify that SetAndGetVolume method works for an effect");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->setAndGetVolume(
+ volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+ description("Verify that effect accepts VolumeChangeNotification");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Return<Result> ret = effect->volumeChangeNotification(volumes);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAudioMode) {
+ description("Verify that SetAudioMode works for an effect");
+ Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, Offload) {
+ description("Verify that calling Offload methods works for an effect");
+ EffectOffloadParameter offloadParam;
+ offloadParam.isOffload = false;
+ offloadParam.ioHandle =
+ static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE);
+ Return<Result> ret = effect->offload(offloadParam);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+ description("Verify that PrepareForProcessing method works for an effect");
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->prepareForProcessing(
+ [&](Result r, const MQDescriptorSync<Result>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+ description("Verify that SetProcessBuffers works for an effect");
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ ASSERT_NE(nullptr, ashmem.get());
+ bool success = false;
+ AudioBuffer buffer;
+ Return<void> ret =
+ ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) {
+ success = s;
+ if (s) {
+ buffer.data = memory;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(success);
+ Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+// Testing getConfigReverse, getAuxChannelsConfig,
+// getSupportedAuxChannelsConfigs, setAudioSource, setConfigReverse,
+// setInputDevice doesn't make sense, because normally they are not supported by
+// the Equalizer, but it wouldn't be a problem if some vendor implementation
+// supports them, thus we can't test these methods neither for success, nor for
+// failure.
+
+// command, getParameter, getSupportedConfigsForFeature,
+// getCurrentConfigForFeature, setCurrentConfigForFeature, setParameter are
+// opaque channels between vendor apps and HALs, and can't be meaningfully
+// tested with effects that don't support them.
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ equalizer = IEqualizerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, equalizer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; }
+ void getNumBands(uint16_t* numBands);
+ void getLevelRange(int16_t* minLevel, int16_t* maxLevel);
+ void getBandFrequencyRange(uint16_t band, uint32_t* minFreq,
+ uint32_t* centerFreq, uint32_t* maxFreq);
+ void getPresetCount(size_t* count);
+
+ sp<IEqualizerEffect> equalizer;
+};
+
+void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ *numBands = b;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel,
+ int16_t* maxLevel) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret =
+ equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minLevel = min;
+ *maxLevel = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band,
+ uint32_t* minFreq,
+ uint32_t* centerFreq,
+ uint32_t* maxFreq) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getBandFrequencyRange(
+ band, [&](Result r, uint32_t min, uint32_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minFreq = min;
+ *maxFreq = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) {
+ retval = r;
+ if (retval == Result::OK) {
+ *centerFreq = center;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getPresetNames(
+ [&](Result r, const hidl_vec<hidl_string>& names) {
+ retval = r;
+ if (retval == Result::OK) {
+ *count = names.size();
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+ description("Verify that Equalizer effect reports at least one band");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ EXPECT_GT(numBands, 0);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+ description("Verify that Equalizer effect reports adequate band level range");
+ int16_t minLevel = 0x7fff, maxLevel = 0;
+ getLevelRange(&minLevel, &maxLevel);
+ EXPECT_GT(maxLevel, minLevel);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+ description(
+ "Verify that manipulating band levels works for Equalizer effect");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ int16_t levels[3]{0x7fff, 0, 0};
+ getLevelRange(&levels[0], &levels[2]);
+ ASSERT_GT(levels[2], levels[0]);
+ levels[1] = (levels[2] + levels[0]) / 2;
+ for (uint16_t i = 0; i < numBands; ++i) {
+ for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) {
+ Return<Result> ret = equalizer->setBandLevel(i, levels[j]);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ int16_t actualLevel;
+ Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualLevel = l;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(levels[j], actualLevel);
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+ description(
+ "Verify that Equalizer effect reports adequate band frequency range");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff,
+ maxFreq = 0xffffffff;
+ getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq);
+ // Note: NXP legacy implementation reports "1" as upper bound for last band,
+ // so this check fails.
+ EXPECT_GE(maxFreq, centerFreq);
+ EXPECT_GE(centerFreq, minFreq);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+ description(
+ "Verify that Equalizer effect supports GetBandForFrequency correctly");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t freqs[3]{0, 0, 0};
+ getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]);
+ // NXP legacy implementation reports "1" as upper bound for last band, some
+ // of the checks fail.
+ for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) {
+ if (j == 0) {
+ freqs[j]++;
+ } // Min frequency is an open interval.
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualBand = numBands + 1;
+ Return<void> ret =
+ equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualBand = b;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j];
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+ description("Verify that Equalizer effect reports at least one preset");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ EXPECT_GT(presetCount, 0u);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+ description(
+ "Verify that manipulating the current preset for Equalizer effect");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ ASSERT_GT(presetCount, 0u);
+ for (uint16_t i = 0; i < presetCount; ++i) {
+ Return<Result> ret = equalizer->setCurrentPreset(i);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualPreset = 0xffff;
+ Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualPreset = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualPreset);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+ description(
+ "Verify that setting band levels and presets works via Get / "
+ "SetAllProperties for Equalizer effect");
+ using AllProperties =
+ android::hardware::audio::effect::V2_0::IEqualizerEffect::AllProperties;
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ AllProperties props;
+ props.bandLevels.resize(numBands);
+ for (size_t i = 0; i < numBands; ++i) {
+ props.bandLevels[i] = 0;
+ }
+
+ AllProperties actualProps;
+ Result retval = Result::NOT_INITIALIZED;
+
+ // Verify setting of the band levels via properties.
+ props.curPreset = -1;
+ Return<Result> ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Return<void> ret2 =
+ equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.bandLevels, actualProps.bandLevels);
+
+ // Verify setting of the current preset via properties.
+ props.curPreset = 0; // Assuming there is at least one preset.
+ ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.curPreset, actualProps.curPreset);
+}
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ enhancer = ILoudnessEnhancerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, enhancer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; }
+
+ sp<ILoudnessEnhancerEffect> enhancer;
+};
+
+TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+ description(
+ "Verify that manipulating the target gain works for Loudness Enhancer "
+ "effect");
+ const int32_t gain = 100;
+ Return<Result> ret = enhancer->setTargetGain(gain);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ int32_t actualGain = 0;
+ Result retval;
+ Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualGain = g;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(gain, actualGain);
+}
diff --git a/audio/effect/Android.mk b/audio/effect/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/audio/effect/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/automotive/Android.bp b/automotive/Android.bp
new file mode 100644
index 0000000..9b24ded
--- /dev/null
+++ b/automotive/Android.bp
@@ -0,0 +1,7 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "evs/1.0",
+ "evs/1.0/default",
+ "vehicle/2.0",
+ "vehicle/2.1",
+]
diff --git a/automotive/evs/1.0/Android.bp b/automotive/evs/1.0/Android.bp
new file mode 100644
index 0000000..042becd
--- /dev/null
+++ b/automotive/evs/1.0/Android.bp
@@ -0,0 +1,83 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.automotive.evs@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IEvsCamera.hal",
+ "IEvsCameraStream.hal",
+ "IEvsDisplay.hal",
+ "IEvsEnumerator.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.evs@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0",
+ srcs: [
+ ":android.hardware.automotive.evs@1.0_hal",
+ ],
+ out: [
+ "android/hardware/automotive/evs/1.0/types.cpp",
+ "android/hardware/automotive/evs/1.0/EvsCameraAll.cpp",
+ "android/hardware/automotive/evs/1.0/EvsCameraStreamAll.cpp",
+ "android/hardware/automotive/evs/1.0/EvsDisplayAll.cpp",
+ "android/hardware/automotive/evs/1.0/EvsEnumeratorAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.evs@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0",
+ srcs: [
+ ":android.hardware.automotive.evs@1.0_hal",
+ ],
+ out: [
+ "android/hardware/automotive/evs/1.0/types.h",
+ "android/hardware/automotive/evs/1.0/IEvsCamera.h",
+ "android/hardware/automotive/evs/1.0/IHwEvsCamera.h",
+ "android/hardware/automotive/evs/1.0/BnHwEvsCamera.h",
+ "android/hardware/automotive/evs/1.0/BpHwEvsCamera.h",
+ "android/hardware/automotive/evs/1.0/BsEvsCamera.h",
+ "android/hardware/automotive/evs/1.0/IEvsCameraStream.h",
+ "android/hardware/automotive/evs/1.0/IHwEvsCameraStream.h",
+ "android/hardware/automotive/evs/1.0/BnHwEvsCameraStream.h",
+ "android/hardware/automotive/evs/1.0/BpHwEvsCameraStream.h",
+ "android/hardware/automotive/evs/1.0/BsEvsCameraStream.h",
+ "android/hardware/automotive/evs/1.0/IEvsDisplay.h",
+ "android/hardware/automotive/evs/1.0/IHwEvsDisplay.h",
+ "android/hardware/automotive/evs/1.0/BnHwEvsDisplay.h",
+ "android/hardware/automotive/evs/1.0/BpHwEvsDisplay.h",
+ "android/hardware/automotive/evs/1.0/BsEvsDisplay.h",
+ "android/hardware/automotive/evs/1.0/IEvsEnumerator.h",
+ "android/hardware/automotive/evs/1.0/IHwEvsEnumerator.h",
+ "android/hardware/automotive/evs/1.0/BnHwEvsEnumerator.h",
+ "android/hardware/automotive/evs/1.0/BpHwEvsEnumerator.h",
+ "android/hardware/automotive/evs/1.0/BsEvsEnumerator.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.automotive.evs@1.0",
+ generated_sources: ["android.hardware.automotive.evs@1.0_genc++"],
+ generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
new file mode 100644
index 0000000..1b55d1f
--- /dev/null
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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.automotive.evs@1.0;
+
+import types;
+import IEvsCameraStream;
+
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+interface IEvsCamera {
+
+ /**
+ * Returns the ID of this camera.
+ *
+ * Returns the string id of this camera. This must be the same value as reported in
+ * the camera_id field of the CameraDesc structure by EvsEnumerator::getCamerList().
+ */
+ getId() generates (string cameraId);
+
+ /**
+ * Specifies the depth of the buffer chain the camera is asked to support.
+ *
+ * Up to this many frames may be held concurrently by the client of IEvsCamera.
+ * If this many frames have been delivered to the receiver without being returned
+ * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+ * It is legal for this call to come at any time, even while streams are already running,
+ * in which case buffers should be added or removed from the chain as appropriate.
+ * If no call is made to this entry point, the IEvsCamera must support at least one
+ * frame by default. More is acceptable.
+ * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the
+ * requested number of concurrent frames.
+ */
+ setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result);
+
+ /**
+ * Request delivery of EVS camera frames from this camera.
+ *
+ * The IEvsCameraStream must begin receiving periodic calls with new image
+ * frames until stopVideoStream() is called.
+ */
+ startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
+
+ /**
+ * Return a frame that was delivered by to the IEvsCameraStream.
+ *
+ * When done consuming a frame delivered to the IEvsCameraStream
+ * interface, it must be returned to the IEvsCamera for reuse.
+ * A small, finite number of buffers are available (possibly as small
+ * as one), and if the supply is exhausted, no further frames may be
+ * delivered until a buffer is returned.
+ */
+ oneway doneWithFrame(BufferDesc buffer);
+
+ /**
+ * Stop the delivery of EVS camera frames.
+ *
+ * Because delivery is asynchronous, frames may continue to arrive for
+ * some time after this call returns. Each must be returned until the
+ * closure of the stream is signaled to the IEvsCameraStream.
+ * This function cannot fail and is simply ignored if the stream isn't running.
+ */
+ stopVideoStream();
+
+ /**
+ * Request driver specific information from the HAL implementation.
+ *
+ * The values allowed for opaqueIdentifier are driver specific,
+ * but no value passed in may crash the driver. The driver should
+ * return 0 for any unrecognized opaqueIdentifier.
+ */
+ getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value);
+
+ /**
+ * Send a driver specific value to the HAL implementation.
+ *
+ * This extension is provided to facilitate car specific
+ * extensions, but no HAL implementation may require this call
+ * in order to function in a default state.
+ * INVALID_ARG is returned if the opaqueValue is not meaningful to
+ * the driver implementation.
+ */
+ setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result);
+};
diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal
new file mode 100644
index 0000000..4e743b2
--- /dev/null
+++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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.automotive.evs@1.0;
+
+
+/**
+ * Implemented on client side to receive asynchronous video frame deliveries.
+ */
+interface IEvsCameraStream {
+
+ /**
+ * Receives calls from the HAL each time a video frame is ready for inspection.
+ * Buffer handles received by this method must be returned via calls to
+ * IEvsCamera::doneWithFrame(). When the video stream is stopped via a call
+ * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+ * some time as the pipeline drains. Each frame must still be returned.
+ * When the last frame in the stream has been delivered, a NULL bufferHandle
+ * must be delivered, signifying the end of the stream. No further frame
+ * deliveries may happen thereafter.
+ */
+ oneway deliverFrame(BufferDesc buffer);
+};
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
new file mode 100644
index 0000000..bbad428
--- /dev/null
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.automotive.evs@1.0;
+
+import types;
+
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+interface IEvsDisplay {
+
+ /**
+ * Returns basic information about the EVS display provided by the system.
+ *
+ * See the description of the DisplayDesc structure below for details.
+ */
+ getDisplayInfo() generates (DisplayDesc info);
+
+
+ /**
+ * Clients may set the display state to express their desired state.
+ *
+ * The HAL implementation must gracefully accept a request for any state while in
+ * any other state, although the response may be to defer or ignore the request. The display
+ * is defined to start in the NOT_VISIBLE state upon initialization. The client is
+ * then expected to request the VISIBLE_ON_NEXT_FRAME state, and then begin providing
+ * video. When the display is no longer required, the client is expected to request
+ * the NOT_VISIBLE state after passing the last video frame.
+ * Returns INVALID_ARG if the requested state is not a recognized value.
+ */
+ setDisplayState(DisplayState state) generates (EvsResult result);
+
+
+ /**
+ * This call requests the current state of the display
+ *
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state. Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to spontaneously
+ * change display states.
+ */
+ getDisplayState() generates (DisplayState state);
+
+
+ /**
+ * This call returns a handle to a frame buffer associated with the display.
+ *
+ * The returned buffer may be locked and written to by software and/or GL. This buffer
+ * must be returned via a call to returnTargetBufferForDisplay() even if the
+ * display is no longer visible.
+ */
+ getTargetBuffer() generates (BufferDesc buffer);
+
+
+ /**
+ * This call tells the display that the buffer is ready for display.
+ *
+ * The buffer is no longer valid for use by the client after this call.
+ * There is no maximum time the caller may hold onto the buffer before making this
+ * call. The buffer may be returned at any time and in any DisplayState, but all
+ * buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+ */
+ returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result);
+};
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
new file mode 100644
index 0000000..334430b
--- /dev/null
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.automotive.evs@1.0;
+
+import types;
+import IEvsCamera;
+import IEvsDisplay;
+
+
+/**
+ * Provides the mechanism for EVS camera discovery
+ */
+interface IEvsEnumerator {
+
+ /**
+ * Returns a list of all EVS cameras available to the system
+ */
+ getCameraList() generates (vec<CameraDesc> cameras);
+
+
+ /**
+ * Get the IEvsCamera associated with a cameraId from a CameraDesc
+ *
+ * Given a camera's unique cameraId from ca CameraDesc, returns
+ * the ICamera interface assocaited with the specified camera.
+ * When done using the camera, it must be returned by calling
+ * closeCamera on the ICamera interface.
+ */
+ openCamera(string cameraId) generates (IEvsCamera carCamera);
+
+ /**
+ * Return the specified IEvsCamera interface as no longer in use
+ *
+ * When the IEvsCamera object is no longer required, it must be released.
+ * NOTE: Video streaming must be cleanly stopped before making this call.
+ */
+ closeCamera(IEvsCamera carCamera);
+
+
+ /**
+ * Get exclusive access to IEvsDisplay for the system
+ *
+ * There can be at most one EVS display object for the system and this function
+ * requests access to it. If the EVS display is not available or is already in use,
+ * a null pointer is returned.
+ */
+ openDisplay() generates (IEvsDisplay display);
+
+ /**
+ * Return the specified IEvsDisplay interface as no longer in use
+ *
+ * When the IEvsDisplay object is no longer required, it must be released.
+ * NOTE: All buffer must have been returned to the display before making this call.
+ */
+ closeDisplay(IEvsDisplay display);
+
+ /**
+ * This call requests the current state of the display
+ *
+ * If there is no open display, this returns DisplayState::NOT_OPEN. otherwise, it returns
+ * the actual state of the active display. This call is replicated on the IEvsEnumerator
+ * interface in order to allow secondary clients to monitor the state of the EVS display
+ * without acquiring exclusive ownership of the display.
+ */
+ getDisplayState() generates (DisplayState state);
+};
+
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
new file mode 100644
index 0000000..8b214e3
--- /dev/null
+++ b/automotive/evs/1.0/default/Android.bp
@@ -0,0 +1,26 @@
+cc_binary {
+ name: "android.hardware.automotive.evs@1.0-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "EvsCamera.cpp",
+ "EvsEnumerator.cpp",
+ "EvsDisplay.cpp"
+ ],
+ init_rc: ["android.hardware.automotive.evs@1.0-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.evs@1.0",
+ "libui",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
new file mode 100644
index 0000000..c4436ee
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
+
+#include "EvsCamera.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+
+// These are the special camera names for which we'll initialize custom test data
+const char EvsCamera::kCameraName_Backup[] = "backup";
+const char EvsCamera::kCameraName_RightTurn[] = "Right Turn";
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
+
+
+// TODO(b/31632518): Need to get notification when our client dies so we can close the camera.
+// As it stands, if the client dies suddenly, the buffer may be stranded.
+
+EvsCamera::EvsCamera(const char *id) :
+ mFramesAllowed(0),
+ mFramesInUse(0),
+ mStreamState(STOPPED) {
+
+ ALOGD("EvsCamera instantiated");
+
+ mDescription.cameraId = id;
+
+ // Set up dummy data for testing
+ if (mDescription.cameraId == kCameraName_Backup) {
+ mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE);
+ mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
+ mDescription.defaultHorResolution = 320; // 1/2 NTSC/VGA
+ mDescription.defaultVerResolution = 240; // 1/2 NTSC/VGA
+ } else if (mDescription.cameraId == kCameraName_RightTurn) {
+ // Nothing but the name and the usage hint
+ mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN);
+ } else {
+ // Leave empty for a minimalist camera description without even a hint
+ }
+
+
+ // Set our buffer properties
+ mWidth = (mDescription.defaultHorResolution) ? mDescription.defaultHorResolution : 640;
+ mHeight = (mDescription.defaultVerResolution) ? mDescription.defaultVerResolution : 480;
+
+ mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+}
+
+
+EvsCamera::~EvsCamera() {
+ ALOGD("EvsCamera being destroyed");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Make sure our output stream is cleaned up
+ // (It really should be already)
+ stopVideoStream();
+
+ // Drop all the graphics buffers we've been using
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ for (auto&& rec : mBuffers) {
+ if (rec.inUse) {
+ ALOGE("Error - releasing buffer despite remote ownership");
+ }
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+ }
+
+ ALOGD("EvsCamera destroyed");
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+Return<void> EvsCamera::getId(getId_cb id_cb) {
+ ALOGD("getId");
+
+ id_cb(mDescription.cameraId);
+
+ return Void();
+}
+
+
+Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+ ALOGD("setMaxFramesInFlight");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // We cannot function without at least one video buffer to send data
+ if (bufferCount < 1) {
+ ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
+ return EvsResult::INVALID_ARG;
+ }
+
+ // Update our internal state
+ if (setAvailableFrames_Locked(bufferCount)) {
+ return EvsResult::OK;
+ } else {
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+}
+
+
+Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream) {
+ ALOGD("startVideoStream");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != STOPPED) {
+ ALOGE("ignoring startVideoStream call when a stream is already running.");
+ return EvsResult::STREAM_ALREADY_RUNNING;
+ }
+
+ // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+ if (mFramesAllowed < 1) {
+ if (!setAvailableFrames_Locked(1)) {
+ ALOGE("Failed to start stream because we couldn't get a graphics buffer");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+ }
+
+ // Record the user's callback for use when we have a frame ready
+ mStream = stream;
+
+ // Start the frame generation thread
+ mStreamState = RUNNING;
+ mCaptureThread = std::thread([this](){ generateFrames(); });
+
+ return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::doneWithFrame(const BufferDesc& buffer) {
+ ALOGD("doneWithFrame");
+ { // lock context
+ std::lock_guard <std::mutex> lock(mAccessLock);
+
+ if (buffer.memHandle == nullptr) {
+ ALOGE("ignoring doneWithFrame called with null handle");
+ } else if (buffer.bufferId >= mBuffers.size()) {
+ ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
+ buffer.bufferId, mBuffers.size()-1);
+ } else if (!mBuffers[buffer.bufferId].inUse) {
+ ALOGE("ignoring doneWithFrame called on frame %d which is already free",
+ buffer.bufferId);
+ } else {
+ // Mark the frame as available
+ mBuffers[buffer.bufferId].inUse = false;
+ mFramesInUse--;
+
+ // If this frame's index is high in the array, try to move it down
+ // to improve locality after mFramesAllowed has been reduced.
+ if (buffer.bufferId >= mFramesAllowed) {
+ // Find an empty slot lower in the array (which should always exist in this case)
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ rec.handle = mBuffers[buffer.bufferId].handle;
+ mBuffers[buffer.bufferId].handle = nullptr;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return Void();
+}
+
+
+Return<void> EvsCamera::stopVideoStream() {
+ ALOGD("stopVideoStream");
+ std::unique_lock <std::mutex> lock(mAccessLock);
+
+ if (mStreamState == RUNNING) {
+ // Tell the GenerateFrames loop we want it to stop
+ mStreamState = STOPPING;
+
+ // Block outside the mutex until the "stop" flag has been acknowledged
+ // We won't send any more frames, but the client might still get some already in flight
+ ALOGD("Waiting for stream thread to end...");
+ lock.unlock();
+ mCaptureThread.join();
+ lock.lock();
+
+ mStreamState = STOPPED;
+ ALOGD("Stream marked STOPPED.");
+ }
+
+ return Void();
+}
+
+
+Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
+ ALOGD("getExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // For any single digit value, return the index itself as a test value
+ if (opaqueIdentifier <= 9) {
+ return opaqueIdentifier;
+ }
+
+ // Return zero by default as required by the spec
+ return 0;
+}
+
+
+Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) {
+ ALOGD("setExtendedInfo");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // We don't store any device specific information in this implementation
+ return EvsResult::INVALID_ARG;
+}
+
+
+bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
+ if (bufferCount < 1) {
+ ALOGE("Ignoring request to set buffer count to zero");
+ return false;
+ }
+ if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
+ ALOGE("Rejecting buffer request in excess of internal limit");
+ return false;
+ }
+
+ // Is an increase required?
+ if (mFramesAllowed < bufferCount) {
+ // An increase is required
+ unsigned needed = bufferCount - mFramesAllowed;
+ ALOGI("Allocating %d buffers for camera frames", needed);
+
+ unsigned added = increaseAvailableFrames_Locked(needed);
+ if (added != needed) {
+ // If we didn't add all the frames we needed, then roll back to the previous state
+ ALOGE("Rolling back to previous frame queue size");
+ decreaseAvailableFrames_Locked(added);
+ return false;
+ }
+ } else if (mFramesAllowed > bufferCount) {
+ // A decrease is required
+ unsigned framesToRelease = mFramesAllowed - bufferCount;
+ ALOGI("Returning %d camera frame buffers", framesToRelease);
+
+ unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
+ if (released != framesToRelease) {
+ // This shouldn't happen with a properly behaving client because the client
+ // should only make this call after returning sufficient outstanding buffers
+ // to allow a clean resize.
+ ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
+ }
+ }
+
+ return true;
+}
+
+
+unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned added = 0;
+
+ while (added < numToAdd) {
+ buffer_handle_t memHandle = nullptr;
+ status_t result = alloc.allocate(mWidth, mHeight,
+ mFormat, 1,
+ mUsage, mUsage,
+ &memHandle, &mStride, 0, "EvsCamera");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
+ break;
+ }
+ if (!memHandle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ break;
+ }
+
+ // Find a place to store the new buffer
+ bool stored = false;
+ for (auto&& rec : mBuffers) {
+ if (rec.handle == nullptr) {
+ // Use this existing entry
+ rec.handle = memHandle;
+ rec.inUse = false;
+ stored = true;
+ break;
+ }
+ }
+ if (!stored) {
+ // Add a BufferRecord wrapping this handle to our set of available buffers
+ mBuffers.emplace_back(memHandle);
+ }
+
+ mFramesAllowed++;
+ added++;
+ }
+
+ return added;
+}
+
+
+unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
+ // Acquire the graphics buffer allocator
+ GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+ unsigned removed = 0;
+
+ for (auto&& rec : mBuffers) {
+ // Is this record not in use, but holding a buffer that we can free?
+ if ((rec.inUse == false) && (rec.handle != nullptr)) {
+ // Release buffer and update the record so we can recognize it as "empty"
+ alloc.free(rec.handle);
+ rec.handle = nullptr;
+
+ mFramesAllowed--;
+ removed++;
+
+ if (removed == numToRemove) {
+ break;
+ }
+ }
+ }
+
+ return removed;
+}
+
+
+// This is the asynchronous frame generation thread that runs in parallel with the
+// main serving thread. There is one for each active camera instance.
+void EvsCamera::generateFrames() {
+ ALOGD("Frame generation loop started");
+
+ unsigned idx;
+
+ while (true) {
+ bool timeForFrame = false;
+ // Lock scope
+ {
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ if (mStreamState != RUNNING) {
+ // Break out of our main thread loop
+ break;
+ }
+
+ // Are we allowed to issue another buffer?
+ if (mFramesInUse >= mFramesAllowed) {
+ // Can't do anything right now -- skip this frame
+ ALOGW("Skipped a frame because too many are in flight\n");
+ } else {
+ // Identify an available buffer to fill
+ for (idx = 0; idx < mBuffers.size(); idx++) {
+ if (!mBuffers[idx].inUse) {
+ if (mBuffers[idx].handle != nullptr) {
+ // Found an available record, so stop looking
+ break;
+ }
+ }
+ }
+ if (idx >= mBuffers.size()) {
+ // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
+ ALOGE("Failed to find an available buffer slot\n");
+ } else {
+ // We're going to make the frame busy
+ mBuffers[idx].inUse = true;
+ mFramesInUse++;
+ timeForFrame = true;
+ }
+ }
+ }
+
+ if (timeForFrame) {
+ // Assemble the buffer description we'll transmit below
+ BufferDesc buff = {};
+ buff.width = mWidth;
+ buff.height = mHeight;
+ buff.stride = mStride;
+ buff.format = mFormat;
+ buff.usage = mUsage;
+ buff.bufferId = idx;
+ buff.memHandle = mBuffers[idx].handle;
+
+ // Write test data into the image buffer
+ fillTestFrame(buff);
+
+ // Issue the (asynchronous) callback to the client -- can't be holding the lock
+ auto result = mStream->deliverFrame(buff);
+ if (result.isOk()) {
+ ALOGD("Delivered %p as id %d", buff.memHandle.getNativeHandle(), buff.bufferId);
+ } else {
+ // This can happen if the client dies and is likely unrecoverable.
+ // To avoid consuming resources generating failing calls, we stop sending
+ // frames. Note, however, that the stream remains in the "STREAMING" state
+ // until cleaned up on the main thread.
+ ALOGE("Frame delivery call failed in the transport layer.");
+
+ // Since we didn't actually deliver it, mark the frame as available
+ std::lock_guard<std::mutex> lock(mAccessLock);
+ mBuffers[idx].inUse = false;
+ mFramesInUse--;
+
+ break;
+ }
+ }
+
+ // We arbitrarily choose to generate frames at 10 fps (1/10 * uSecPerSec)
+ usleep(100000);
+ }
+
+ // If we've been asked to stop, send one last NULL frame to signal the actual end of stream
+ BufferDesc nullBuff = {};
+ auto result = mStream->deliverFrame(nullBuff);
+ if (!result.isOk()) {
+ ALOGE("Error delivering end of stream marker");
+ }
+
+ return;
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc& buff) {
+ // Lock our output buffer for writing
+ uint32_t *pixels = nullptr;
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(buff.memHandle,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+ android::Rect(buff.width, buff.height),
+ (void **) &pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Camera failed to gain access to image buffer for writing");
+ }
+
+ // Fill in the test pixels
+ for (unsigned row = 0; row < buff.height; row++) {
+ for (unsigned col = 0; col < buff.width; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ static uint32_t sFrameTicker = 0;
+ expectedPixel = (sFrameTicker) & 0xFF;
+ sFrameTicker++;
+ }
+ pixels[col] = expectedPixel;
+ }
+ // Point to the next row
+ // NOTE: stride retrieved from gralloc is in units of pixels
+ pixels = pixels + buff.stride;
+ }
+
+ // Release our output buffer
+ mapper.unlock(buff.memHandle);
+}
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.0/default/EvsCamera.h b/automotive/evs/1.0/default/EvsCamera.h
new file mode 100644
index 0000000..ee91ca4
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsCamera.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
+
+#include <android/hardware/automotive/evs/1.0/types.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+
+class EvsCamera : public IEvsCamera {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+ Return<void> getId(getId_cb id_cb) override;
+
+ Return <EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+
+ Return <EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override;
+
+ Return<void> doneWithFrame(const BufferDesc& buffer) override;
+
+ Return<void> stopVideoStream() override;
+
+ Return <int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+
+ Return <EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+ // Implementation details
+ EvsCamera(const char* id);
+
+ virtual ~EvsCamera() override;
+
+ const CameraDesc& getDesc() { return mDescription; };
+
+ static const char kCameraName_Backup[];
+ static const char kCameraName_RightTurn[];
+
+private:
+ // These three functions are expected to be called while mAccessLock is held
+ bool setAvailableFrames_Locked(unsigned bufferCount);
+
+ unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
+
+ unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
+
+ void generateFrames();
+
+ void fillTestFrame(const BufferDesc& buff);
+
+ CameraDesc mDescription = {}; // The properties of this camera
+
+ std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+ uint32_t mWidth = 0; // Horizontal pixel count in the buffers
+ uint32_t mHeight = 0; // Vertical pixel count in the buffers
+ uint32_t mFormat = 0; // Values from android_pixel_format_t [TODO: YUV? Leave opaque?]
+ uint32_t mUsage = 0; // Values from from Gralloc.h
+ uint32_t mStride = 0; // Bytes per line in the buffers
+
+ sp <IEvsCameraStream> mStream = nullptr; // The callback used to deliver each frame
+
+ struct BufferRecord {
+ buffer_handle_t handle;
+ bool inUse;
+
+ explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+ };
+
+ std::vector <BufferRecord> mBuffers; // Graphics buffers to transfer images
+ unsigned mFramesAllowed; // How many buffers are we currently using
+ unsigned mFramesInUse; // How many buffers are currently outstanding
+
+ enum StreamStateValues {
+ STOPPED,
+ RUNNING,
+ STOPPING,
+ };
+ StreamStateValues mStreamState;
+
+ // Syncrhonization necessary to deconflict mCaptureThread from the main service thread
+ std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
diff --git a/automotive/evs/1.0/default/EvsDisplay.cpp b/automotive/evs/1.0/default/EvsDisplay.cpp
new file mode 100644
index 0000000..a1a76d0
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsDisplay.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
+
+#include "EvsDisplay.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+
+// TODO(b/31632518): Need to get notification when our client dies so we can close the camera.
+// As it stands, if the client dies suddently, the buffer may be stranded.
+// As possible work around would be to give the client a HIDL object to exclusively hold
+// and use it's destructor to perform some work in the server side.
+
+
+EvsDisplay::EvsDisplay() {
+ ALOGD("EvsDisplay instantiated");
+
+ // Set up our self description
+ // NOTE: These are arbitrary values chosen for testing
+ mInfo.displayId = "Mock Display";
+ mInfo.vendorFlags = 3870;
+ mInfo.defaultHorResolution = 320;
+ mInfo.defaultVerResolution = 240;
+}
+
+
+EvsDisplay::~EvsDisplay() {
+ ALOGD("EvsDisplay being destroyed");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Report if we're going away while a buffer is outstanding
+ if (mFrameBusy) {
+ ALOGE("EvsDisplay going down while client is holding a buffer");
+ }
+
+ // Make sure we release our frame buffer
+ if (mBuffer.memHandle) {
+ // Drop the graphics buffer we've been using
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.free(mBuffer.memHandle);
+ mBuffer.memHandle = nullptr;
+ }
+ ALOGD("EvsDisplay destroyed");
+}
+
+
+/**
+ * Returns basic information about the EVS display provided by the system.
+ * See the description of the DisplayDesc structure below for details.
+ */
+Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) {
+ ALOGD("getDisplayInfo");
+
+ // Send back our self description
+ _hidl_cb(mInfo);
+ return Void();
+}
+
+
+/**
+ * Clients may set the display state to express their desired state.
+ * The HAL implementation must gracefully accept a request for any state
+ * while in any other state, although the response may be to ignore the request.
+ * The display is defined to start in the NOT_VISIBLE state upon initialization.
+ * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
+ * then begin providing video. When the display is no longer required, the client
+ * is expected to request the NOT_VISIBLE state after passing the last video frame.
+ */
+Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
+ ALOGD("setDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Ensure we recognize the requested state so we don't go off the rails
+ if (state < DisplayState::NUM_STATES) {
+ // Record the requested state
+ mRequestedState = state;
+ return EvsResult::OK;
+ }
+ else {
+ // Turn off the display if asked for an unrecognized state
+ mRequestedState = DisplayState::NOT_VISIBLE;
+ return EvsResult::INVALID_ARG;
+ }
+}
+
+
+/**
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state. Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to
+ * spontaneously change display states.
+ */
+Return<DisplayState> EvsDisplay::getDisplayState() {
+ ALOGD("getDisplayState");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // At the moment, we treat the requested state as immediately active
+ DisplayState currentState = mRequestedState;
+
+ return currentState;
+}
+
+
+/**
+ * This call returns a handle to a frame buffer associated with the display.
+ * This buffer may be locked and written to by software and/or GL. This buffer
+ * must be returned via a call to returnTargetBufferForDisplay() even if the
+ * display is no longer visible.
+ */
+// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
+Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) {
+ ALOGD("getTargetBuffer");
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // If we don't already have a buffer, allocate one now
+ if (!mBuffer.memHandle) {
+ // Assemble the buffer description we'll use for our render target
+ mBuffer.width = mInfo.defaultHorResolution;
+ mBuffer.height = mInfo.defaultVerResolution;
+ mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;
+ mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+ mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition
+
+ buffer_handle_t handle = nullptr;
+ GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ status_t result = alloc.allocate(mBuffer.width, mBuffer.height,
+ mBuffer.format, 1, mBuffer.usage,
+ mBuffer.usage, &handle,
+ &mBuffer.stride,
+ 0, "EvsDisplay");
+ if (result != NO_ERROR) {
+ ALOGE("Error %d allocating %d x %d graphics buffer",
+ result, mBuffer.width, mBuffer.height);
+ BufferDesc nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+ if (!handle) {
+ ALOGE("We didn't get a buffer handle back from the allocator");
+ BufferDesc nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ }
+
+ mBuffer.memHandle = handle;
+ mFrameBusy = false;
+ ALOGD("Allocated new buffer %p with stride %u",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
+ }
+
+ // Do we have a frame available?
+ if (mFrameBusy) {
+ // This means either we have a 2nd client trying to compete for buffers
+ // (an unsupported mode of operation) or else the client hasn't returned
+ // a previously issued buffer yet (they're behaving badly).
+ // NOTE: We have to make the callback even if we have nothing to provide
+ ALOGE("getTargetBuffer called while no buffers available.");
+ BufferDesc nullBuff = {};
+ _hidl_cb(nullBuff);
+ return Void();
+ } else {
+ // Mark our buffer as busy
+ mFrameBusy = true;
+
+ // Send the buffer to the client
+ ALOGD("Providing display buffer handle %p as id %d",
+ mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
+ _hidl_cb(mBuffer);
+ return Void();
+ }
+}
+
+
+/**
+ * This call tells the display that the buffer is ready for display.
+ * The buffer is no longer valid for use by the client after this call.
+ */
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) {
+ ALOGD("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle());
+ std::lock_guard<std::mutex> lock(mAccessLock);
+
+ // Nobody should call us with a null handle
+ if (!buffer.memHandle.getNativeHandle()) {
+ ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (buffer.bufferId != mBuffer.bufferId) {
+ ALOGE ("Got an unrecognized frame returned.\n");
+ return EvsResult::INVALID_ARG;
+ }
+ if (!mFrameBusy) {
+ ALOGE ("A frame was returned with no outstanding frames.\n");
+ return EvsResult::BUFFER_NOT_AVAILABLE;
+ }
+
+ mFrameBusy = false;
+
+ // If we were waiting for a new frame, this is it!
+ if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
+ mRequestedState = DisplayState::VISIBLE;
+ }
+
+ // Validate we're in an expected state
+ if (mRequestedState != DisplayState::VISIBLE) {
+ // We shouldn't get frames back when we're not visible.
+ ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
+ } else {
+ // This is where the buffer would be made visible.
+ // For now we simply validate it has the data we expect in it by reading it back
+
+ // Lock our display buffer for reading
+ uint32_t* pixels = nullptr;
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+ mapper.lock(mBuffer.memHandle,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+ android::Rect(mBuffer.width, mBuffer.height),
+ (void **)&pixels);
+
+ // If we failed to lock the pixel buffer, we're about to crash, but log it first
+ if (!pixels) {
+ ALOGE("Display failed to gain access to image buffer for reading");
+ }
+
+ // Check the test pixels
+ bool frameLooksGood = true;
+ for (unsigned row = 0; row < mInfo.defaultVerResolution; row++) {
+ for (unsigned col = 0; col < mInfo.defaultHorResolution; col++) {
+ // Index into the row to check the pixel at this column.
+ // We expect 0xFF in the LSB channel, a vertical gradient in the
+ // second channel, a horitzontal gradient in the third channel, and
+ // 0xFF in the MSB.
+ // The exception is the very first 32 bits which is used for the
+ // time varying frame signature to avoid getting fooled by a static image.
+ uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
+ ((row & 0xFF) << 8) | // vertical gradient
+ ((col & 0xFF) << 16); // horizontal gradient
+ if ((row | col) == 0) {
+ // we'll check the "uniqueness" of the frame signature below
+ continue;
+ }
+ // Walk across this row (we'll step rows below)
+ uint32_t receivedPixel = pixels[col];
+ if (receivedPixel != expectedPixel) {
+ ALOGE("Pixel check mismatch in frame buffer");
+ frameLooksGood = false;
+ break;
+ }
+ }
+
+ if (!frameLooksGood) {
+ break;
+ }
+
+ // Point to the next row (NOTE: gralloc reports stride in units of pixels)
+ pixels = pixels + mBuffer.stride;
+ }
+
+ // Ensure we don't see the same buffer twice without it being rewritten
+ static uint32_t prevSignature = ~0;
+ uint32_t signature = pixels[0] & 0xFF;
+ if (prevSignature == signature) {
+ frameLooksGood = false;
+ ALOGE("Duplicate, likely stale frame buffer detected");
+ }
+
+
+ // Release our output buffer
+ mapper.unlock(mBuffer.memHandle);
+
+ if (!frameLooksGood) {
+ return EvsResult::UNDERLYING_SERVICE_ERROR;
+ }
+ }
+
+ return EvsResult::OK;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.0/default/EvsDisplay.h b/automotive/evs/1.0/default/EvsDisplay.h
new file mode 100644
index 0000000..fcf4a06
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsDisplay.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+class EvsDisplay : public IEvsDisplay {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
+ Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override;
+ Return<EvsResult> setDisplayState(DisplayState state) override;
+ Return<DisplayState> getDisplayState() override;
+ Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override;
+ Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc& buffer) override;
+
+ // Implementation details
+ EvsDisplay();
+ virtual ~EvsDisplay() override;
+
+private:
+ DisplayDesc mInfo = {};
+ BufferDesc mBuffer = {}; // A graphics buffer into which we'll store images
+
+ bool mFrameBusy = false; // A flag telling us our buffer is in use
+ DisplayState mRequestedState = DisplayState::NOT_VISIBLE;
+
+ std::mutex mAccessLock;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
diff --git a/automotive/evs/1.0/default/EvsEnumerator.cpp b/automotive/evs/1.0/default/EvsEnumerator.cpp
new file mode 100644
index 0000000..e54f699
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsEnumerator.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
+
+#include "EvsEnumerator.h"
+#include "EvsCamera.h"
+#include "EvsDisplay.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+
+// TODO(b/31632518): Need to get notification when our client dies so we can close the camera.
+// As it stands, if the client dies suddenly, the camera will be stuck "open".
+// NOTE: Display should already be safe by virtue of holding only a weak pointer.
+
+
+EvsEnumerator::EvsEnumerator() {
+ ALOGD("EvsEnumerator created");
+
+ // Add sample camera data to our list of cameras
+ // NOTE: The id strings trigger special initialization inside the EvsCamera constructor
+ mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_Backup), false );
+ mCameraList.emplace_back( new EvsCamera("LaneView"), false );
+ mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_RightTurn), false );
+}
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
+ ALOGD("getCameraList");
+
+ const unsigned numCameras = mCameraList.size();
+
+ // Build up a packed array of CameraDesc for return
+ // NOTE: Only has to live until the callback returns
+ std::vector<CameraDesc> descriptions;
+ descriptions.reserve(numCameras);
+ for (const auto& cam : mCameraList) {
+ descriptions.push_back( cam.pCamera->getDesc() );
+ }
+
+ // Encapsulate our camera descriptions in the HIDL vec type
+ hidl_vec<CameraDesc> hidlCameras(descriptions);
+
+ // Send back the results
+ ALOGD("reporting %zu cameras available", hidlCameras.size());
+ _hidl_cb(hidlCameras);
+
+ // HIDL convention says we return Void if we sent our result back via callback
+ return Void();
+}
+
+Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
+ ALOGD("openCamera");
+
+ // Find the named camera
+ CameraRecord *pRecord = nullptr;
+ for (auto &&cam : mCameraList) {
+ if (cam.pCamera->getDesc().cameraId == cameraId) {
+ // Found a match!
+ pRecord = &cam;
+ break;
+ }
+ }
+
+ if (!pRecord) {
+ ALOGE("Requested camera %s not found", cameraId.c_str());
+ return nullptr;
+ } else if (pRecord->inUse) {
+ ALOGE("Cannot open camera %s which is already in use", cameraId.c_str());
+ return nullptr;
+ } else {
+ pRecord->inUse = true;
+ return(pRecord->pCamera);
+ }
+}
+
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& camera) {
+ ALOGD("closeCamera");
+
+ if (camera == nullptr) {
+ ALOGE("Ignoring call to closeCamera with null camera pointer");
+ } else {
+ // Find this camera in our list
+ auto it = std::find_if(mCameraList.begin(),
+ mCameraList.end(),
+ [camera](const CameraRecord& rec) {
+ return (rec.pCamera == camera);
+ });
+ if (it == mCameraList.end()) {
+ ALOGE("Ignoring close on unrecognized camera");
+ } else {
+ // Make sure the camera has stopped streaming
+ camera->stopVideoStream();
+
+ it->inUse = false;
+ }
+ }
+
+ return Void();
+}
+
+Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
+ ALOGD("openDisplay");
+
+ // If we already have a display active, then this request must be denied
+ sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ ALOGW("Rejecting openDisplay request the display is already in use.");
+ return nullptr;
+ } else {
+ // Create a new display interface and return it
+ pActiveDisplay = new EvsDisplay();
+ mActiveDisplay = pActiveDisplay;
+ ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+ return pActiveDisplay;
+ }
+}
+
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) {
+ ALOGD("closeDisplay");
+
+ // Do we still have a display object we think should be active?
+ sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
+
+ if (pActiveDisplay == nullptr) {
+ ALOGE("Ignoring closeDisplay when there is no active display.");
+ } else if (display != pActiveDisplay) {
+ ALOGE("Ignoring closeDisplay on a display we didn't issue");
+ ALOGI("Got %p while active display is %p.", display.get(), pActiveDisplay.get());
+ } else {
+ // Drop the active display
+ mActiveDisplay = nullptr;
+ }
+
+ return Void();
+}
+
+Return<DisplayState> EvsEnumerator::getDisplayState() {
+ ALOGD("getDisplayState");
+
+ // Do we still have a display object we think should be active?
+ sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote();
+ if (pActiveDisplay != nullptr) {
+ return pActiveDisplay->getDisplayState();
+ } else {
+ return DisplayState::NOT_OPEN;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.0/default/EvsEnumerator.h b/automotive/evs/1.0/default/EvsEnumerator.h
new file mode 100644
index 0000000..3d6e264
--- /dev/null
+++ b/automotive/evs/1.0/default/EvsEnumerator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
+
+#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.0/IEvsCamera.h>
+
+#include <list>
+
+#include "EvsCamera.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_0 {
+namespace implementation {
+
+class EvsEnumerator : public IEvsEnumerator {
+public:
+ // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+ Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+ Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override;
+ Return<void> closeCamera(const ::android::sp<IEvsCamera>& carCamera) override;
+ Return<sp<IEvsDisplay>> openDisplay() override;
+ Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override;
+ Return<DisplayState> getDisplayState() override;
+
+ // Implementation details
+ EvsEnumerator();
+
+private:
+ struct CameraRecord {
+ sp<EvsCamera> pCamera;
+ bool inUse;
+ CameraRecord(EvsCamera* p, bool b) : pCamera(p), inUse(b) {}
+ };
+ std::list<CameraRecord> mCameraList;
+
+ wp<IEvsDisplay> mActiveDisplay; // Weak pointer -> object destructs if client dies
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
diff --git a/automotive/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h
new file mode 100644
index 0000000..d20a37f
--- /dev/null
+++ b/automotive/evs/1.0/default/ServiceNames.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+const static char kEnumeratorServiceName[] = "EvsEnumeratorHw-Mock";
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
new file mode 100644
index 0000000..8957ecf
--- /dev/null
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -0,0 +1,4 @@
+service evs-hal-1-0 /vendor/bin/hw/android.hardware.automotive.evs@1.0-service
+ class hal
+ user cameraserver
+ group camera
diff --git a/automotive/evs/1.0/default/service.cpp b/automotive/evs/1.0/default/service.cpp
new file mode 100644
index 0000000..1b64e44
--- /dev/null
+++ b/automotive/evs/1.0/default/service.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.evs@1.0-service"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Log.h>
+
+#include "ServiceNames.h"
+#include "EvsEnumerator.h"
+#include "EvsDisplay.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::evs::V1_0::implementation;
+using namespace android;
+
+
+int main() {
+ ALOGI("EVS Hardware Enumerator service is starting");
+ android::sp<IEvsEnumerator> service = new EvsEnumerator();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ status_t status = service->registerAsService(kEnumeratorServiceName);
+ if (status == OK) {
+ ALOGD("%s is ready.", kEnumeratorServiceName);
+ joinRpcThreadpool();
+ } else {
+ ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status);
+ }
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("EVS Hardware Enumerator is shutting down");
+ return 1;
+}
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
new file mode 100644
index 0000000..661c2a9
--- /dev/null
+++ b/automotive/evs/1.0/types.hal
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 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.automotive.evs@1.0;
+
+
+/*
+ * Bit flags indicating suggested uses for a given EVS camera
+ *
+ * The values in the UsageHint bit field provide a generic expression of how a
+ * given camera is intended to be used. The values for these flags support
+ * existing use cases, and are used by the default EVS application to select
+ * appropriate cameras for display based on observed vehicle state (such as
+ * turn signal activation or selection of reverse gear). When implementing
+ * their own specialized EVS Applications, OEMs are free to use these flags
+ * and/or the opaque vendor_flags to drive their own vehicle specific logic.
+ */
+enum UsageHint : uint32_t {
+ USAGE_HINT_REVERSE = 0x00000001,
+ USAGE_HINT_LEFT_TURN = 0x00000002,
+ USAGE_HINT_RIGHT_TURN = 0x00000004,
+};
+
+
+/*
+ * Structure describing the basic properties of an EVS camera
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system. Attention should be given to the field
+ * of view, direction of view, and location parameters as these may
+ * be used to (if available) to project overlay graphics into the
+ * scene by an EVS application.
+ * Any of these values for which the HAL does not have reasonable values
+ * should be set to ZERO.
+ */
+struct CameraDesc {
+ string cameraId;
+ bitfield<UsageHint> hints; // Mask of usage hints
+ uint32_t vendorFlags; // Opaque value from driver
+ uint32_t defaultHorResolution; // Units of pixels
+ uint32_t defaultVerResolution; // Units of pixels
+};
+
+
+/*
+ * Structure describing the basic properties of an EVS display
+ *
+ * The HAL is responsible for filling out this structure to describe
+ * the EVS display. As an implementation detail, this may be a physical
+ * display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+struct DisplayDesc {
+ string displayId;
+ uint32_t vendorFlags; // Opaque value from driver
+ uint32_t defaultHorResolution; // Units of pixels
+ uint32_t defaultVerResolution; // Units of pixels
+};
+
+
+/*
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR().
+ * See also related types from android.hardware.graphics.common
+ * TODO: b/34722508 Review details of interaction of this structure with gralloc and OpenGL.
+ * Specifically consider if format and/or usage should become enumerated types.
+ */
+struct BufferDesc {
+ uint32_t width; // Units of pixels
+ uint32_t height; // Units of pixels
+ uint32_t stride; // Units of bytes
+ uint32_t format; // May contain values from android_pixel_format_t
+ uint32_t usage; // May contain values from from Gralloc.h
+ uint32_t bufferId; // Opaque value from driver
+ handle memHandle; // gralloc memory buffer handle
+};
+
+
+/*
+ * States for control of the EVS display
+ *
+ * The DisplayInfo structure describes the basic properties of an EVS display. Any EVS
+ * implementation is required to have one. The HAL is responsible for filling out this
+ * structure to describe the EVS display. As an implementation detail, this may be a
+ * physical display or a virtual display that is overlaid or mixed with another
+ * presentation device.
+ */
+enum DisplayState : uint32_t {
+ NOT_OPEN = 0, // Display has not been requested by any application
+ NOT_VISIBLE, // Display is inhibited
+ VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame
+ VISIBLE, // Display is currently active
+ NUM_STATES // Must be last
+};
+
+
+/* Error codes used in EVS HAL interface. */
+enum EvsResult : uint32_t {
+ OK = 0,
+ INVALID_ARG,
+ STREAM_ALREADY_RUNNING,
+ BUFFER_NOT_AVAILABLE,
+ UNDERLYING_SERVICE_ERROR,
+};
\ No newline at end of file
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
new file mode 100644
index 0000000..e08d3ca
--- /dev/null
+++ b/automotive/vehicle/2.0/Android.bp
@@ -0,0 +1,69 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.automotive.vehicle@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IVehicle.hal",
+ "IVehicleCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.vehicle@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.0",
+ srcs: [
+ ":android.hardware.automotive.vehicle@2.0_hal",
+ ],
+ out: [
+ "android/hardware/automotive/vehicle/2.0/types.cpp",
+ "android/hardware/automotive/vehicle/2.0/VehicleAll.cpp",
+ "android/hardware/automotive/vehicle/2.0/VehicleCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.vehicle@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.0",
+ srcs: [
+ ":android.hardware.automotive.vehicle@2.0_hal",
+ ],
+ out: [
+ "android/hardware/automotive/vehicle/2.0/types.h",
+ "android/hardware/automotive/vehicle/2.0/IVehicle.h",
+ "android/hardware/automotive/vehicle/2.0/IHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.0/BnHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.0/BpHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.0/BsVehicle.h",
+ "android/hardware/automotive/vehicle/2.0/IVehicleCallback.h",
+ "android/hardware/automotive/vehicle/2.0/IHwVehicleCallback.h",
+ "android/hardware/automotive/vehicle/2.0/BnHwVehicleCallback.h",
+ "android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h",
+ "android/hardware/automotive/vehicle/2.0/BsVehicleCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.automotive.vehicle@2.0",
+ generated_sources: ["android.hardware.automotive.vehicle@2.0_genc++"],
+ generated_headers: ["android.hardware.automotive.vehicle@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.automotive.vehicle@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/automotive/vehicle/2.0/Android.mk b/automotive/vehicle/2.0/Android.mk
new file mode 100644
index 0000000..d093017
--- /dev/null
+++ b/automotive/vehicle/2.0/Android.mk
@@ -0,0 +1,1950 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.automotive.vehicle@2.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (StatusCode)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.StatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SubscribeFlags)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.SubscribeFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SubscribeOptions)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeOptions.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.SubscribeOptions
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerBootupReason)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerBootupReason.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerBootupReason
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerSetState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerSetState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerSetState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateConfigFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateConfigFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateConfigFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateShutdownParam)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateShutdownParam.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateShutdownParam
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleArea)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleArea.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleArea
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaConfig)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaDoor)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaDoor.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaDoor
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaMirror)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaMirror.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaMirror
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaSeat)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaSeat.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaSeat
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaWindow)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaWindow.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaWindow
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaZone)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaZone.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaZone
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioContextFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioContextFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioContextFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioExtFocusFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioExtFocusFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioExtFocusFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusRequest)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusRequest.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusRequest
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioHwVariantConfigFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioHwVariantConfigFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioHwVariantConfigFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioRoutingPolicyIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioRoutingPolicyIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioRoutingPolicyIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioStream)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStream.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioStream
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioStreamFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStreamFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioStreamFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeCapabilityFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeCapabilityFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeCapabilityFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeLimitIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeLimitIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeLimitIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleDisplay)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDisplay.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleDisplay
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleDrivingStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDrivingStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleDrivingStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleGear)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleGear.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleGear
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleHvacFanDirection)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHvacFanDirection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleHvacFanDirection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleHwKeyInputAction)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHwKeyInputAction.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleHwKeyInputAction
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleIgnitionState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleIgnitionState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleIgnitionState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleInstrumentClusterType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleInstrumentClusterType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleInstrumentClusterType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropConfig)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropValue)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropValue.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropValue
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleProperty)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleProperty.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleProperty
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyAccess)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyAccess.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyAccess
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyChangeMode)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyChangeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyChangeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyGroup)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyGroup
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyOperation)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyOperation.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyOperation
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleRadioConstants)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleRadioConstants.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleRadioConstants
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleTurnSignal)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleTurnSignal.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleTurnSignal
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleUnit)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleUnit.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleUnit
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Wheel)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.Wheel
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicle.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicle.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::IVehicle
+
+$(GEN): $(LOCAL_PATH)/IVehicle.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicleCallback.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicleCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::IVehicleCallback
+
+$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.automotive.vehicle@2.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (StatusCode)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.StatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SubscribeFlags)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.SubscribeFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SubscribeOptions)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeOptions.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.SubscribeOptions
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerBootupReason)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerBootupReason.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerBootupReason
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerSetState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerSetState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerSetState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateConfigFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateConfigFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateConfigFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleApPowerStateShutdownParam)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateShutdownParam.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateShutdownParam
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleArea)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleArea.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleArea
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaConfig)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaDoor)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaDoor.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaDoor
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaMirror)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaMirror.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaMirror
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaSeat)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaSeat.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaSeat
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaWindow)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaWindow.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaWindow
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAreaZone)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaZone.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAreaZone
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioContextFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioContextFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioContextFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioExtFocusFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioExtFocusFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioExtFocusFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusRequest)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusRequest.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusRequest
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioFocusState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioHwVariantConfigFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioHwVariantConfigFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioHwVariantConfigFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioRoutingPolicyIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioRoutingPolicyIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioRoutingPolicyIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioStream)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStream.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioStream
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioStreamFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStreamFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioStreamFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeCapabilityFlag)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeCapabilityFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeCapabilityFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeLimitIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeLimitIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeLimitIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleAudioVolumeState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleDisplay)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDisplay.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleDisplay
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleDrivingStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDrivingStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleDrivingStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleGear)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleGear.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleGear
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleHvacFanDirection)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHvacFanDirection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleHvacFanDirection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleHwKeyInputAction)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHwKeyInputAction.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleHwKeyInputAction
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleIgnitionState)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleIgnitionState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleIgnitionState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleInstrumentClusterType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleInstrumentClusterType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleInstrumentClusterType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropConfig)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropValue)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropValue.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropValue
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleProperty)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleProperty.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleProperty
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyAccess)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyAccess.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyAccess
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyChangeMode)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyChangeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyChangeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyGroup)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyGroup
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyOperation)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyOperation.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyOperation
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehiclePropertyType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehiclePropertyType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleRadioConstants)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleRadioConstants.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleRadioConstants
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleTurnSignal)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleTurnSignal.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleTurnSignal
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleUnit)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleUnit.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.VehicleUnit
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Wheel)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::types.Wheel
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicle.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicle.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::IVehicle
+
+$(GEN): $(LOCAL_PATH)/IVehicle.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicleCallback.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicleCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicleCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.0::IVehicleCallback
+
+$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/automotive/vehicle/2.0/IVehicle.hal b/automotive/vehicle/2.0/IVehicle.hal
new file mode 100644
index 0000000..5de416f
--- /dev/null
+++ b/automotive/vehicle/2.0/IVehicle.hal
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.automotive.vehicle@2.0;
+
+import IVehicleCallback;
+
+interface IVehicle {
+ /**
+ * Returns a list of all property configurations supported by this vehicle
+ * HAL.
+ */
+ getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);
+
+ /*
+ * Returns a list of property configurations for given properties.
+ *
+ * If requested VehicleProperty wasn't found it must return
+ * StatusCode::INVALID_ARG, otherwise a list of vehicle property
+ * configurations with StatusCode::OK
+ */
+ getPropConfigs(vec<int32_t> props)
+ generates (StatusCode status, vec<VehiclePropConfig> propConfigs);
+
+ /**
+ * Get a vehicle property value.
+ *
+ * For VehiclePropertyChangeMode::STATIC properties, this method must always
+ * return the same value always.
+ * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
+ * latest available value.
+ *
+ * Some properties like AUDIO_VOLUME requires to pass additional data in
+ * GET request in VehiclePropValue object.
+ *
+ * If there is no data available yet, which can happen during initial stage,
+ * this call must return immediately with an error code of
+ * StatusCode::TRY_AGAIN.
+ */
+ get(VehiclePropValue requestedPropValue)
+ generates (StatusCode status, VehiclePropValue propValue);
+
+ /**
+ * Set a vehicle property value.
+ *
+ * Timestamp of data must be ignored for set operation.
+ *
+ * Setting some properties require having initial state available. If initial
+ * data is not available yet this call must return StatusCode::TRY_AGAIN.
+ * For a property with separate power control this call must return
+ * StatusCode::NOT_AVAILABLE error if property is not powered on.
+ */
+ set(VehiclePropValue propValue) generates (StatusCode status);
+
+ /**
+ * Subscribes to property events.
+ *
+ * Clients must be able to subscribe to multiple properties at a time
+ * depending on data provided in options argument.
+ *
+ * @param listener This client must be called on appropriate event.
+ * @param options List of options to subscribe. SubscribeOption contains
+ * information such as property Id, area Id, sample rate, etc.
+ */
+ subscribe(IVehicleCallback callback, vec<SubscribeOptions> options)
+ generates (StatusCode status);
+
+ /**
+ * Unsubscribes from property events.
+ *
+ * If this client wasn't subscribed to the given property, this method
+ * must return StatusCode::INVALID_ARG.
+ */
+ unsubscribe(IVehicleCallback callback, int32_t propId)
+ generates (StatusCode status);
+
+ /**
+ * Print out debugging state for the vehicle hal.
+ *
+ * The text must be in ASCII encoding only.
+ *
+ * Performance requirements:
+ *
+ * The HAL must return from this call in less than 10ms. This call must avoid
+ * deadlocks, as it may be called at any point of operation. Any synchronization
+ * primitives used (such as mutex locks or semaphores) must be acquired
+ * with a timeout.
+ *
+ */
+ debugDump() generates (string s);
+};
diff --git a/automotive/vehicle/2.0/IVehicleCallback.hal b/automotive/vehicle/2.0/IVehicleCallback.hal
new file mode 100644
index 0000000..167e5e1
--- /dev/null
+++ b/automotive/vehicle/2.0/IVehicleCallback.hal
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.automotive.vehicle@2.0;
+
+interface IVehicleCallback {
+
+ /*
+ * Event callback happens whenever a variable that the API user has
+ * subscribed to needs to be reported. This may be based purely on
+ * threshold and frequency (a regular subscription, see subscribe call's
+ * arguments) or when the IVehicle#set method was called and the actual
+ * change needs to be reported.
+ *
+ * These callbacks are chunked.
+ *
+ * @param values that has been updated.
+ */
+ oneway onPropertyEvent(vec<VehiclePropValue> propValues);
+
+ /*
+ * This method gets called if the client was subscribed to a property using
+ * SubscribeFlags::SET_CALL flag and IVehicle#set(...) method was called.
+ *
+ * These events must be delivered to subscriber immediately without any
+ * batching.
+ *
+ * @param value Value that was set by a client.
+ */
+ oneway onPropertySet(VehiclePropValue propValue);
+
+ /*
+ * Set property value is usually asynchronous operation. Thus even if
+ * client received StatusCode::OK from the IVehicle::set(...) this
+ * doesn't guarantee that the value was successfully propagated to the
+ * vehicle network. If such rare event occurs this method must be called.
+ *
+ * @param errorCode - any value from StatusCode enum.
+ * @param property - a property where error has happened.
+ * @param areaId - bitmask that specifies in which areas the problem has
+ * occurred, must be 0 for global properties
+ */
+ oneway onPropertySetError(StatusCode errorCode,
+ int32_t propId,
+ int32_t areaId);
+};
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
new file mode 100644
index 0000000..4a010e9
--- /dev/null
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -0,0 +1,172 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+vhal_v2_0 = android.hardware.automotive.vehicle@2.0
+
+###############################################################################
+# Vehicle reference implementation lib
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(vhal_v2_0)-manager-lib
+LOCAL_SRC_FILES := \
+ common/src/AccessControlConfigParser.cpp \
+ common/src/SubscriptionManager.cpp \
+ common/src/VehicleHalManager.cpp \
+ common/src/VehicleObjectPool.cpp \
+ common/src/VehicleUtils.cpp \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/common/include/vhal_v2_0
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/common/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libutils \
+ $(vhal_v2_0) \
+
+include $(BUILD_STATIC_LIBRARY)
+
+###############################################################################
+# Vehicle HAL Protobuf library
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-proto-files-under, impl/vhal_v2_0/proto)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_MODULE := $(vhal_v2_0)-libproto-native
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STRIP_MODULE := keep_symbols
+
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(generated_sources_dir)/proto/$(LOCAL_PATH)/impl/vhal_v2_0/proto
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+###############################################################################
+# Vehicle default VehicleHAL implementation
+###############################################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib
+LOCAL_SRC_FILES:= \
+ impl/vhal_v2_0/DefaultVehicleHal.cpp \
+ impl/vhal_v2_0/PipeComm.cpp \
+ impl/vhal_v2_0/SocketComm.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/impl/vhal_v2_0
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/impl
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-manager-lib \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libprotobuf-cpp-lite \
+ libutils \
+ $(vhal_v2_0) \
+
+LOCAL_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-libproto-native \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+###############################################################################
+# Vehicle reference implementation unit tests
+###############################################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= $(vhal_v2_0)-manager-unit-tests
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-manager-lib \
+
+LOCAL_SRC_FILES:= \
+ tests/AccessControlConfigParser_test.cpp \
+ tests/RecurrentTimer_test.cpp \
+ tests/SubscriptionManager_test.cpp \
+ tests/VehicleHalManager_test.cpp \
+ tests/VehicleObjectPool_test.cpp \
+ tests/VehiclePropConfigIndex_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libutils \
+ $(vhal_v2_0) \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_NATIVE_TEST)
+
+
+###############################################################################
+# Vehicle HAL service
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(vhal_v2_0)-service
+LOCAL_INIT_RC := $(vhal_v2_0)-service.rc
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+ VehicleService.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libprotobuf-cpp-lite \
+ libutils \
+ $(vhal_v2_0) \
+
+LOCAL_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-manager-lib \
+ $(vhal_v2_0)-default-impl-lib \
+ $(vhal_v2_0)-libproto-native \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
+include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
new file mode 100644
index 0000000..95057cc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-service"
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <iostream>
+
+#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/DefaultVehicleHal.h>
+
+using namespace android;
+using namespace android::hardware;
+using namespace android::hardware::automotive::vehicle::V2_0;
+
+int main(int /* argc */, char* /* argv */ []) {
+ auto hal = std::make_unique<impl::DefaultVehicleHal>();
+ auto service = std::make_unique<VehicleHalManager>(hal.get());
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ ALOGI("Registering as service...");
+ service->registerAsService();
+
+ ALOGI("Ready");
+ joinRpcThreadpool();
+}
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
new file mode 100644
index 0000000..30e249e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -0,0 +1,4 @@
+service vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h
new file mode 100644
index 0000000..8ef6f5a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
+#define android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <list>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+struct PropertyAcl {
+ int32_t propId;
+ unsigned uid;
+ VehiclePropertyAccess access;
+};
+
+using PropertyAclMap = std::unordered_multimap<int32_t, PropertyAcl>;
+
+/**
+ * Parser for per-property access control in vehicle HAL.
+ *
+ * It supports the following format:
+ * Set ALIAS_NAME UID
+ * {S,V}:0x0305 {ALIAS_NAME,UID} {R,W,RW}
+ *
+ * ALIAS_NAME is just an alias for UID
+ * S - for system properties (VehiclePropertyGroup::SYSTEM)
+ * V - for vendor properties (VehiclePropertyGroup::VENDOR)
+ *
+ * Example:
+ *
+ * Set AID_AUDIO 1004
+ * Set AID_MY_APP 10022
+ *
+ * S:0x0305 AID_AUDIO RW
+ * S:0x0305 10021 R
+ * V:0x0101 AID_MY_APP R
+ */
+class AccessControlConfigParser {
+public:
+ /**
+ * Creates an instance of AccessControlConfigParser
+ *
+ * @param properties - properties supported by HAL implementation
+ */
+ AccessControlConfigParser(const std::vector<int32_t>& properties);
+
+ /**
+ * Parses config content from given stream and writes results to
+ * propertyAclMap.
+ */
+ bool parseFromStream(std::istream* stream, PropertyAclMap* propertyAclMap);
+
+private:
+ bool processTokens(std::list<std::string>* tokens,
+ PropertyAclMap* propertyAclMap);
+
+ bool parsePropertyGroup(char group,
+ VehiclePropertyGroup* outPropertyGroup) const;
+
+ bool parsePropertyId(const std::string& strPropId,
+ VehiclePropertyGroup propertyGroup,
+ int32_t* outVehicleProperty) const;
+
+ bool parseUid(const std::string& strUid, unsigned* outUid) const;
+
+ bool parseAccess(const std::string& strAccess,
+ VehiclePropertyAccess* outAccess) const;
+
+
+ std::string readNextToken(std::list<std::string>* tokens) const;
+
+ static bool parseInt(const char* strValue, int* outIntValue);
+ static void split(const std::string& line,
+ std::list<std::string>* outTokens);
+
+private:
+ std::unordered_map<std::string, unsigned> mUidMap {}; // Contains UID
+ // aliases.
+
+ // Map property ids w/o TYPE and AREA to VehicleProperty.
+ std::unordered_map<int32_t, int32_t> mStrippedToVehiclePropertyMap;
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h
new file mode 100644
index 0000000..b63429f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
+#define android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
+
+#include <queue>
+#include <atomic>
+#include <thread>
+#include <condition_variable>
+#include <iostream>
+
+namespace android {
+
+template<typename T>
+class ConcurrentQueue {
+public:
+ void waitForItems() {
+ std::unique_lock<std::mutex> g(mLock);
+ while (mQueue.empty() && mIsActive) {
+ mCond.wait(g);
+ }
+ }
+
+ std::vector<T> flush() {
+ std::vector<T> items;
+
+ MuxGuard g(mLock);
+ if (mQueue.empty() || !mIsActive) {
+ return items;
+ }
+ while (!mQueue.empty()) {
+ items.push_back(std::move(mQueue.front()));
+ mQueue.pop();
+ }
+ return items;
+ }
+
+ void push(T&& item) {
+ {
+ MuxGuard g(mLock);
+ if (!mIsActive) {
+ return;
+ }
+ mQueue.push(std::move(item));
+ }
+ mCond.notify_one();
+ }
+
+ /* Deactivates the queue, thus no one can push items to it, also
+ * notifies all waiting thread.
+ */
+ void deactivate() {
+ {
+ MuxGuard g(mLock);
+ mIsActive = false;
+ }
+ mCond.notify_all(); // To unblock all waiting consumers.
+ }
+
+ ConcurrentQueue() = default;
+
+ ConcurrentQueue(const ConcurrentQueue &) = delete;
+ ConcurrentQueue &operator=(const ConcurrentQueue &) = delete;
+private:
+ using MuxGuard = std::lock_guard<std::mutex>;
+
+ bool mIsActive = true;
+ mutable std::mutex mLock;
+ std::condition_variable mCond;
+ std::queue<T> mQueue;
+};
+
+template<typename T>
+class BatchingConsumer {
+private:
+ enum class State {
+ INIT = 0,
+ RUNNING = 1,
+ STOP_REQUESTED = 2,
+ STOPPED = 3,
+ };
+
+public:
+ BatchingConsumer() : mState(State::INIT) {}
+
+ BatchingConsumer(const BatchingConsumer &) = delete;
+ BatchingConsumer &operator=(const BatchingConsumer &) = delete;
+
+ using OnBatchReceivedFunc = std::function<void(const std::vector<T>& vec)>;
+
+ void run(ConcurrentQueue<T>* queue,
+ std::chrono::nanoseconds batchInterval,
+ const OnBatchReceivedFunc& func) {
+ mQueue = queue;
+ mBatchInterval = batchInterval;
+
+ mWorkerThread = std::thread(
+ &BatchingConsumer<T>::runInternal, this, func);
+ }
+
+ void requestStop() {
+ mState = State::STOP_REQUESTED;
+ }
+
+ void waitStopped() {
+ if (mWorkerThread.joinable()) {
+ mWorkerThread.join();
+ }
+ }
+
+private:
+ void runInternal(const OnBatchReceivedFunc& onBatchReceived) {
+ if (mState.exchange(State::RUNNING) == State::INIT) {
+ while (State::RUNNING == mState) {
+ mQueue->waitForItems();
+ if (State::STOP_REQUESTED == mState) break;
+
+ std::this_thread::sleep_for(mBatchInterval);
+ if (State::STOP_REQUESTED == mState) break;
+
+ std::vector<T> items = mQueue->flush();
+
+ if (items.size() > 0) {
+ onBatchReceived(items);
+ }
+ }
+ }
+
+ mState = State::STOPPED;
+ }
+
+private:
+ std::thread mWorkerThread;
+
+ std::atomic<State> mState;
+ std::chrono::nanoseconds mBatchInterval;
+ ConcurrentQueue<T>* mQueue;
+};
+
+} // namespace android
+
+#endif //android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
new file mode 100644
index 0000000..be25adc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <set>
+#include <thread>
+#include <unordered_map>
+
+/**
+ * This class allows to specify multiple time intervals to receive
+ * notifications. A single thread is used internally.
+ */
+class RecurrentTimer {
+private:
+ using Nanos = std::chrono::nanoseconds;
+ using Clock = std::chrono::steady_clock;
+ using TimePoint = std::chrono::time_point<Clock, Nanos>;
+public:
+ using Action = std::function<void(const std::vector<int32_t>& cookies)>;
+
+ RecurrentTimer(const Action& action) : mAction(action) {
+ mTimerThread = std::thread(&RecurrentTimer::loop, this, action);
+ }
+
+ virtual ~RecurrentTimer() {
+ stop();
+ }
+
+ /**
+ * Registers recurrent event for a given interval. Registred events are distinguished by
+ * cookies thus calling this method multiple times with the same cookie will override the
+ * interval provided before.
+ */
+ void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
+ TimePoint now = Clock::now();
+ // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
+ // during every second wake-up both intervals will be triggered.
+ TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
+
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
+ }
+ mCond.notify_one();
+ }
+
+ void unregisterRecurrentEvent(int32_t cookie) {
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap.erase(cookie);
+ }
+ mCond.notify_one();
+ }
+
+
+private:
+
+ struct RecurrentEvent {
+ Nanos interval;
+ int32_t cookie;
+ TimePoint absoluteTime; // Absolute time of the next event.
+
+ void updateNextEventTime(TimePoint now) {
+ // We want to move time to next event by adding some number of intervals (usually 1)
+ // to previous absoluteTime.
+ int intervalMultiplier = (now - absoluteTime) / interval;
+ if (intervalMultiplier <= 0) intervalMultiplier = 1;
+ absoluteTime += intervalMultiplier * interval;
+ }
+ };
+
+ void loop(const Action& action) {
+ static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+
+ std::vector<int32_t> cookies;
+
+ while (!mStopRequested) {
+ auto now = Clock::now();
+ auto nextEventTime = kInvalidTime;
+ cookies.clear();
+
+ {
+ std::unique_lock<std::mutex> g(mLock);
+
+ for (auto&& it : mCookieToEventsMap) {
+ RecurrentEvent& event = it.second;
+ if (event.absoluteTime <= now) {
+ event.updateNextEventTime(now);
+ cookies.push_back(event.cookie);
+ }
+
+ if (nextEventTime > event.absoluteTime) {
+ nextEventTime = event.absoluteTime;
+ }
+ }
+ }
+
+ if (cookies.size() != 0) {
+ action(cookies);
+ }
+
+ std::unique_lock<std::mutex> g(mLock);
+ mCond.wait_until(g, nextEventTime); // nextEventTime can be nanoseconds::max()
+ }
+ }
+
+ void stop() {
+ mStopRequested = true;
+ {
+ std::lock_guard<std::mutex> g(mLock);
+ mCookieToEventsMap.clear();
+ }
+ mCond.notify_one();
+ if (mTimerThread.joinable()) {
+ mTimerThread.join();
+ }
+ }
+private:
+ mutable std::mutex mLock;
+ std::thread mTimerThread;
+ std::condition_variable mCond;
+ std::atomic_bool mStopRequested { false };
+ Action mAction;
+ std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
+};
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
new file mode 100644
index 0000000..a808c66
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
+#define android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
+
+#include <memory>
+#include <map>
+#include <set>
+#include <list>
+
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+#include "ConcurrentQueue.h"
+#include "VehicleObjectPool.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+class HalClient : public android::RefBase {
+public:
+ HalClient(const sp<IVehicleCallback> &callback,
+ int32_t pid,
+ int32_t uid)
+ : mCallback(callback), mPid(pid), mUid(uid) {}
+
+ virtual ~HalClient() {}
+public:
+ sp<IVehicleCallback> getCallback() const {
+ return mCallback;
+ }
+
+ void addOrUpdateSubscription(const SubscribeOptions &opts);
+ bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+ std::vector<int32_t> getSubscribedProperties() const;
+
+private:
+ const sp<IVehicleCallback> mCallback;
+ const int32_t mPid;
+ const int32_t mUid;
+
+ std::map<int32_t, SubscribeOptions> mSubscriptions;
+};
+
+class HalClientVector : private SortedVector<sp<HalClient>> , public RefBase {
+public:
+ virtual ~HalClientVector() {}
+
+ inline void addOrUpdate(const sp<HalClient> &client) {
+ SortedVector::add(client);
+ }
+
+ using SortedVector::remove;
+ using SortedVector::size;
+ using SortedVector::indexOf;
+ using SortedVector::itemAt;
+ using SortedVector::isEmpty;
+};
+
+struct HalClientValues {
+ sp<HalClient> client;
+ std::list<VehiclePropValue *> values;
+};
+
+class SubscriptionManager {
+public:
+ using OnPropertyUnsubscribed = std::function<void(int32_t)>;
+
+ /**
+ * Constructs SubscriptionManager
+ *
+ * @param onPropertyUnsubscribed - this callback function will be called when there are no
+ * more client subscribed to particular property.
+ */
+ SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
+ : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
+ mCallbackDeathRecipient(new DeathRecipient(
+ std::bind(&SubscriptionManager::onCallbackDead, this, std::placeholders::_1)))
+ {}
+
+ ~SubscriptionManager() = default;
+
+ /**
+ * Updates subscription. Returns the vector of properties subscription that
+ * needs to be updated in VehicleHAL.
+ */
+ StatusCode addOrUpdateSubscription(const sp<IVehicleCallback>& callback,
+ const hidl_vec<SubscribeOptions>& optionList,
+ std::list<SubscribeOptions>* outUpdatedOptions);
+
+ /**
+ * Returns a list of IVehicleCallback -> list of VehiclePropValue ready for
+ * dispatching to its clients.
+ */
+ std::list<HalClientValues> distributeValuesToClients(
+ const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
+ SubscribeFlags flags) const;
+
+ std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
+ int32_t area,
+ SubscribeFlags flags) const;
+ /**
+ * If there are no clients subscribed to given properties than callback function provided
+ * in the constructor will be called.
+ */
+ void unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId);
+private:
+ std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
+ int32_t area,
+ SubscribeFlags flags) const;
+
+ bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
+
+ void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
+
+ sp<HalClientVector> getClientsForPropertyLocked(int32_t propId) const;
+
+ sp<HalClient> getOrCreateHalClientLocked(const sp<IVehicleCallback> &callback);
+
+ void onCallbackDead(uint64_t cookie);
+
+private:
+ using OnClientDead = std::function<void(uint64_t)>;
+
+ class DeathRecipient : public hidl_death_recipient {
+ public:
+ DeathRecipient(const OnClientDead& onClientDead)
+ : mOnClientDead(onClientDead) {}
+ ~DeathRecipient() = default;
+
+ DeathRecipient(const DeathRecipient& ) = delete;
+ DeathRecipient& operator=(const DeathRecipient&) = delete;
+
+ void serviceDied(uint64_t cookie,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+ mOnClientDead(cookie);
+ }
+ private:
+ OnClientDead mOnClientDead;
+ };
+
+private:
+ using MuxGuard = std::lock_guard<std::mutex>;
+
+ mutable std::mutex mLock;
+
+ std::map<sp<IVehicleCallback>, sp<HalClient>> mClients;
+ std::map<int32_t, sp<HalClientVector>> mPropToClients;
+ std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions;
+
+ OnPropertyUnsubscribed mOnPropertyUnsubscribed;
+ sp<DeathRecipient> mCallbackDeathRecipient;
+};
+
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
new file mode 100644
index 0000000..8203a1e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHal_H
+#define android_hardware_automotive_vehicle_V2_0_VehicleHal_H
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include "VehicleObjectPool.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ * This is a low-level vehicle hal interface that should be implemented by
+ * Vendor.
+ */
+class VehicleHal {
+public:
+ using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+
+ using HalEventFunction = std::function<void(VehiclePropValuePtr)>;
+ using HalErrorFunction = std::function<void(
+ StatusCode errorCode, int32_t property, int32_t areaId)>;
+
+ virtual ~VehicleHal() {}
+
+ virtual std::vector<VehiclePropConfig> listProperties() = 0;
+ virtual VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+ StatusCode* outStatus) = 0;
+
+ virtual StatusCode set(const VehiclePropValue& propValue) = 0;
+
+ /**
+ * Subscribe to HAL property events. This method might be called multiple
+ * times for the same vehicle property to update subscribed areas or sample
+ * rate.
+ *
+ * @param property to subscribe
+ * @param areas a bitwise vehicle areas or 0 for all supported areas
+ * @param sampleRate sample rate in Hz for properties that support sample
+ * rate, e.g. for properties with
+ * VehiclePropertyChangeMode::CONTINUOUS
+ */
+ virtual StatusCode subscribe(int32_t property,
+ int32_t areas,
+ float sampleRate) = 0;
+
+ /**
+ * Unsubscribe from HAL events for given property
+ *
+ * @param property vehicle property to unsubscribe
+ */
+ virtual StatusCode unsubscribe(int32_t property) = 0;
+
+ /**
+ * Override this method if you need to do one-time initialization.
+ */
+ virtual void onCreate() {}
+
+ void init(
+ VehiclePropValuePool* valueObjectPool,
+ const HalEventFunction& onHalEvent,
+ const HalErrorFunction& onHalError) {
+ mValuePool = valueObjectPool;
+ mOnHalEvent = onHalEvent;
+ mOnHalPropertySetError = onHalError;
+
+ onCreate();
+ }
+
+ VehiclePropValuePool* getValuePool() {
+ return mValuePool;
+ }
+protected:
+ /* Propagates property change events to vehicle HAL clients. */
+ void doHalEvent(VehiclePropValuePtr v) {
+ mOnHalEvent(std::move(v));
+ }
+
+ /* Propagates error during set operation to the vehicle HAL clients. */
+ void doHalPropertySetError(StatusCode errorCode,
+ int32_t propId,
+ int32_t areaId) {
+ mOnHalPropertySetError(errorCode, propId, areaId);
+ }
+
+private:
+ HalEventFunction mOnHalEvent;
+ HalErrorFunction mOnHalPropertySetError;
+ VehiclePropValuePool* mValuePool;
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif //android_hardware_automotive_vehicle_V2_0_VehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
new file mode 100644
index 0000000..b8ab309
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include "AccessControlConfigParser.h"
+#include "ConcurrentQueue.h"
+#include "SubscriptionManager.h"
+#include "VehicleHal.h"
+#include "VehicleObjectPool.h"
+#include "VehiclePropConfigIndex.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+struct Caller {
+ pid_t pid;
+ uid_t uid;
+};
+
+/**
+ * This class is a thick proxy between IVehicle HIDL interface and vendor's implementation.
+ *
+ * It has some boilerplate code like batching and caching property values, checking permissions,
+ * etc. Vendors must implement VehicleHal class.
+ */
+class VehicleHalManager : public IVehicle {
+public:
+ VehicleHalManager(VehicleHal* vehicleHal)
+ : mHal(vehicleHal),
+ mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
+ this, std::placeholders::_1)) {
+ init();
+ }
+
+ virtual ~VehicleHalManager();
+
+ void init();
+
+ // ---------------------------------------------------------------------------------------------
+ // Methods derived from IVehicle
+ Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override;
+ Return<void> getPropConfigs(const hidl_vec<int32_t>& properties,
+ getPropConfigs_cb _hidl_cb) override;
+ Return<void> get(const VehiclePropValue& requestedPropValue,
+ get_cb _hidl_cb) override;
+ Return<StatusCode> set(const VehiclePropValue& value) override;
+ Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
+ const hidl_vec<SubscribeOptions>& options) override;
+ Return<StatusCode> unsubscribe(const sp<IVehicleCallback>& callback,
+ int32_t propId) override;
+ Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override;
+
+private:
+ using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
+ // Returns true if needs to call again shortly.
+ using RetriableAction = std::function<bool()>;
+
+ // ---------------------------------------------------------------------------------------------
+ // Events received from VehicleHal
+ void onHalEvent(VehiclePropValuePtr v);
+ void onHalPropertySetError(StatusCode errorCode, int32_t property,
+ int32_t areaId);
+
+ // ---------------------------------------------------------------------------------------------
+ // This method will be called from BatchingConsumer thread
+ void onBatchHalEvent(const std::vector<VehiclePropValuePtr >& values);
+
+ void handlePropertySetEvent(const VehiclePropValue& value);
+
+ const VehiclePropConfig* getPropConfigOrNull(int32_t prop) const;
+
+ bool checkWritePermission(const VehiclePropConfig &config,
+ const Caller& callee) const;
+ bool checkReadPermission(const VehiclePropConfig &config,
+ const Caller& caller) const;
+ bool checkAcl(uid_t callerUid,
+ int32_t propertyId,
+ VehiclePropertyAccess requiredAccess) const;
+
+ void onAllClientsUnsubscribed(int32_t propertyId);
+
+ static bool isSubscribable(const VehiclePropConfig& config,
+ SubscribeFlags flags);
+ static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
+ static float checkSampleRate(const VehiclePropConfig& config,
+ float sampleRate);
+ static void readAndParseAclConfig(const char* filename,
+ AccessControlConfigParser* parser,
+ PropertyAclMap* outAclMap);
+
+ static Caller getCaller();
+
+private:
+ VehicleHal* mHal;
+ std::unique_ptr<VehiclePropConfigIndex> mConfigIndex;
+ SubscriptionManager mSubscriptionManager;
+
+ hidl_vec<VehiclePropValue> mHidlVecOfVehiclePropValuePool;
+
+ ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
+ BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer;
+ VehiclePropValuePool mValueObjectPool;
+ PropertyAclMap mPropertyAclMap;
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
new file mode 100644
index 0000000..05c649b
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
+
+#include <deque>
+#include <map>
+#include <mutex>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+// Handy metric mostly for unit tests and debug.
+#define INC_METRIC_IF_DEBUG(val) PoolStats::instance()->val++;
+struct PoolStats {
+ std::atomic<uint32_t> Obtained {0};
+ std::atomic<uint32_t> Created {0};
+ std::atomic<uint32_t> Recycled {0};
+
+ static PoolStats* instance() {
+ static PoolStats inst;
+ return &inst;
+ }
+};
+
+template<typename T>
+struct Deleter {
+ using OnDeleteFunc = std::function<void(T*)>;
+
+ Deleter(const OnDeleteFunc& f) : mOnDelete(f) {};
+
+ Deleter() = default;
+ Deleter(const Deleter&) = default;
+
+ void operator()(T* o) {
+ mOnDelete(o);
+ }
+private:
+ OnDeleteFunc mOnDelete;
+};
+
+/**
+ * This is std::unique_ptr<> with custom delete operation that typically moves
+ * the pointer it holds back to ObjectPool.
+ */
+template <typename T>
+using recyclable_ptr = typename std::unique_ptr<T, Deleter<T>>;
+
+/**
+ * Generic abstract object pool class. Users of this class must implement
+ * #createObject method.
+ *
+ * This class is thread-safe. Concurrent calls to #obtain(...) method from
+ * multiple threads is OK, also client can obtain an object in one thread and
+ * then move ownership to another thread.
+ *
+ */
+template<typename T>
+class ObjectPool {
+public:
+ ObjectPool() = default;
+ virtual ~ObjectPool() = default;
+
+ virtual recyclable_ptr<T> obtain() {
+ std::lock_guard<std::mutex> g(mLock);
+ INC_METRIC_IF_DEBUG(Obtained)
+ if (mObjects.empty()) {
+ INC_METRIC_IF_DEBUG(Created)
+ return wrap(createObject());
+ }
+
+ auto o = wrap(mObjects.front().release());
+ mObjects.pop_front();
+
+ return o;
+ }
+
+ ObjectPool& operator =(const ObjectPool &) = delete;
+ ObjectPool(const ObjectPool &) = delete;
+
+protected:
+ virtual T* createObject() = 0;
+
+ virtual void recycle(T* o) {
+ INC_METRIC_IF_DEBUG(Recycled)
+ std::lock_guard<std::mutex> g(mLock);
+ mObjects.push_back(std::unique_ptr<T> { o } );
+ }
+
+private:
+ const Deleter<T>& getDeleter() {
+ if (!mDeleter.get()) {
+ Deleter<T> *d = new Deleter<T>(std::bind(
+ &ObjectPool::recycle, this, std::placeholders::_1));
+ mDeleter.reset(d);
+ }
+ return *mDeleter.get();
+ }
+
+ recyclable_ptr<T> wrap(T* raw) {
+ return recyclable_ptr<T> { raw, getDeleter() };
+ }
+
+private:
+ mutable std::mutex mLock;
+ std::deque<std::unique_ptr<T>> mObjects;
+ std::unique_ptr<Deleter<T>> mDeleter;
+};
+
+/**
+ * This class provides a pool of recycable VehiclePropertyValue objects.
+ *
+ * It has only one overloaded public method - obtain(...), users must call this
+ * method when new object is needed with given VehiclePropertyType and vector
+ * size (for vector properties). This method returns a recycable smart pointer
+ * to VehiclePropertyValue, essentially this is a std::unique_ptr with custom
+ * delete function, so recycable object has only one owner and developers can
+ * safely pass it around. Once this object goes out of scope, it will be
+ * returned the the object pool.
+ *
+ * Some objects are not recycable: strings and vector data types with
+ * vector length > maxRecyclableVectorSize (provided in the constructor). These
+ * objects will be deleted immediately once the go out of scope. There's no
+ * synchornization penalty for these objects since we do not store them in the
+ * pool.
+ *
+ * This class is thread-safe. Users can obtain an object in one thread and pass
+ * it to another.
+ *
+ * Sample usage:
+ *
+ * VehiclePropValuePool pool;
+ * auto v = pool.obtain(VehiclePropertyType::INT32);
+ * v->propId = VehicleProperty::HVAC_FAN_SPEED;
+ * v->areaId = VehicleAreaZone::ROW_1_LEFT;
+ * v->timestamp = elapsedRealtimeNano();
+ * v->value->int32Values[0] = 42;
+ *
+ *
+ */
+class VehiclePropValuePool {
+public:
+ using RecyclableType = recyclable_ptr<VehiclePropValue>;
+
+ /**
+ * Creates VehiclePropValuePool
+ *
+ * @param maxRecyclableVectorSize - vector value types (e.g.
+ * VehiclePropertyType::INT32_VEC) with size equal or less to this value
+ * will be stored in the pool. If users tries to obtain value with vector
+ * size greater than maxRecyclableVectorSize user will receive appropriate
+ * object, but once it goes out of scope it will be deleted immediately, not
+ * returning back to the object pool.
+ *
+ */
+ VehiclePropValuePool(size_t maxRecyclableVectorSize = 4) :
+ mMaxRecyclableVectorSize(maxRecyclableVectorSize) {};
+
+ RecyclableType obtain(VehiclePropertyType type);
+
+ RecyclableType obtain(VehiclePropertyType type, size_t vecSize);
+ RecyclableType obtain(const VehiclePropValue& src);
+ RecyclableType obtainBoolean(bool value);
+ RecyclableType obtainInt32(int32_t value);
+ RecyclableType obtainInt64(int64_t value);
+ RecyclableType obtainFloat(float value);
+ RecyclableType obtainString(const char* cstr);
+ RecyclableType obtainComplex();
+
+ VehiclePropValuePool(VehiclePropValuePool& ) = delete;
+ VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete;
+private:
+ bool isDisposable(VehiclePropertyType type, size_t vecSize) const {
+ return vecSize > mMaxRecyclableVectorSize ||
+ VehiclePropertyType::STRING == type ||
+ VehiclePropertyType::COMPLEX == type;
+ }
+
+ RecyclableType obtainDisposable(VehiclePropertyType valueType,
+ size_t vectorSize) const;
+ RecyclableType obtainRecylable(VehiclePropertyType type,
+ size_t vecSize);
+
+ class InternalPool: public ObjectPool<VehiclePropValue> {
+ public:
+ InternalPool(VehiclePropertyType type, size_t vectorSize)
+ : mPropType(type), mVectorSize(vectorSize) {}
+
+ RecyclableType obtain() {
+ return ObjectPool<VehiclePropValue>::obtain();
+ }
+ protected:
+ VehiclePropValue* createObject() override;
+ void recycle(VehiclePropValue* o) override;
+ private:
+ bool check(VehiclePropValue::RawValue* v);
+
+ template <typename VecType>
+ bool check(hidl_vec<VecType>* vec, bool expected) {
+ return vec->size() == (expected ? mVectorSize : 0);
+ }
+ private:
+ VehiclePropertyType mPropType;
+ size_t mVectorSize;
+ };
+
+private:
+ const Deleter<VehiclePropValue> mDisposableDeleter {
+ [] (VehiclePropValue* v) {
+ delete v;
+ }
+ };
+
+private:
+ mutable std::mutex mLock;
+ const size_t mMaxRecyclableVectorSize;
+ std::map<int32_t, std::unique_ptr<InternalPool>> mValueTypePools;
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h
new file mode 100644
index 0000000..0528f68
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
+#define android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
+
+#include <utils/KeyedVector.h>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/*
+ * This is thread-safe immutable class to hold vehicle property configuration
+ * data.
+ */
+class VehiclePropConfigIndex {
+public:
+ VehiclePropConfigIndex(
+ const std::vector<VehiclePropConfig>& properties)
+ : mConfigs(properties), mPropToConfig(mConfigs)
+ {}
+
+ bool hasConfig(int32_t property) const {
+ return mPropToConfig.indexOfKey(property) >= 0;
+ }
+
+ const VehiclePropConfig& getConfig(int32_t property) const {
+ return *mPropToConfig.valueFor(property);
+ }
+
+ const std::vector<VehiclePropConfig>& getAllConfigs() const {
+ return mConfigs;
+ }
+
+private:
+ typedef KeyedVector<int32_t, const VehiclePropConfig*> PropConfigMap;
+ class ImmutablePropConfigMap : private PropConfigMap {
+ public:
+ ImmutablePropConfigMap(const std::vector<VehiclePropConfig>& configs) {
+ setCapacity(configs.size());
+ for (auto& config : configs) {
+ add(config.prop, &config);
+ }
+ }
+ public:
+ using PropConfigMap::valueFor;
+ using PropConfigMap::indexOfKey;
+ };
+
+private:
+ const std::vector<VehiclePropConfig> mConfigs;
+ const ImmutablePropConfigMap mPropToConfig; // mConfigs must be declared
+ // first.
+};
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
new file mode 100644
index 0000000..ce0b163
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_
+
+#include <memory>
+
+#include <hidl/HidlSupport.h>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/** Represents all supported areas for a property. Can be used is */
+constexpr int32_t kAllSupportedAreas = 0;
+
+/** Returns underlying (integer) value for given enum. */
+template<typename ENUM>
+inline constexpr typename std::underlying_type<ENUM>::type toInt(
+ ENUM const value) {
+ return static_cast<typename std::underlying_type<ENUM>::type>(value);
+}
+
+inline constexpr VehiclePropertyType getPropType(int32_t prop) {
+ return static_cast<VehiclePropertyType>(
+ prop & toInt(VehiclePropertyType::MASK));
+}
+
+inline constexpr VehiclePropertyGroup getPropGroup(int32_t prop) {
+ return static_cast<VehiclePropertyGroup>(
+ prop & toInt(VehiclePropertyGroup::MASK));
+}
+
+inline constexpr VehicleArea getPropArea(int32_t prop) {
+ return static_cast<VehicleArea>(prop & toInt(VehicleArea::MASK));
+}
+
+inline constexpr bool isGlobalProp(int32_t prop) {
+ return getPropArea(prop) == VehicleArea::GLOBAL;
+}
+
+inline constexpr bool isSystemProperty(int32_t prop) {
+ return VehiclePropertyGroup::SYSTEM == getPropGroup(prop);
+}
+
+std::unique_ptr<VehiclePropValue> createVehiclePropValue(
+ VehiclePropertyType type, size_t vecSize);
+
+size_t getVehicleRawValueVectorSize(
+ const VehiclePropValue::RawValue& value, VehiclePropertyType type);
+
+void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
+ const VehiclePropValue::RawValue& src);
+
+template<typename T>
+void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& src);
+
+void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src);
+
+void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src);
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_
diff --git a/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp b/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp
new file mode 100644
index 0000000..6a3f8e5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-impl"
+
+#include "AccessControlConfigParser.h"
+#include "VehicleUtils.h"
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+AccessControlConfigParser::AccessControlConfigParser(
+ const std::vector<int32_t>& properties) {
+ // Property Id in the config file doesn't include information about
+ // type and area. So we want to create a map from these kind of
+ // *stripped* properties to the whole VehicleProperty.
+ // We also want to filter out ACL to the properties that supported
+ // by concrete Vehicle HAL implementation.
+ for (auto prop : properties) {
+ auto strippedProp = prop
+ & ~toInt(VehiclePropertyType::MASK)
+ & ~toInt(VehicleArea::MASK);
+ mStrippedToVehiclePropertyMap.emplace(strippedProp, prop);
+ }
+}
+
+bool AccessControlConfigParser::parseFromStream(
+ std::istream* stream, PropertyAclMap* propertyAclMap) {
+ std::list<std::string> tokens;
+ std::string line;
+ int lineNo = 0;
+ bool warnings = false;
+ for (;std::getline(*stream, line); lineNo++) {
+ split(line, &tokens);
+ if (!processTokens(&tokens, propertyAclMap)) {
+ warnings = true;
+ ALOGW("Failed to parse line %d : %s", lineNo, line.c_str());
+ }
+ }
+ return !warnings;
+}
+
+
+bool AccessControlConfigParser::processTokens(std::list<std::string>* tokens,
+ PropertyAclMap* propertyAclMap) {
+ std::string token = readNextToken(tokens);
+ if (token.empty() || token[0] == '#') { // Ignore comment.
+ return true;
+ }
+
+ if (token == "Set") {
+ std::string alias = readNextToken(tokens);
+ std::string strUid = readNextToken(tokens);
+ if (alias.empty() || strUid.empty()) {
+ ALOGW("Expected alias and UID must be specified");
+ return false;
+ }
+ int uid;
+ if (!parseInt(strUid.c_str(), &uid)) {
+ ALOGW("Invalid UID: %d", uid);
+ }
+ mUidMap.emplace(std::move(alias), uid);
+ } else if (token.size() > 2 && token[1] == ':') {
+ VehiclePropertyGroup propGroup;
+ if (!parsePropertyGroup(token[0], &propGroup)) {
+ return false;
+ }
+ std::string strUid = readNextToken(tokens);
+ std::string strAccess = readNextToken(tokens);
+ if (strUid.empty() || strAccess.empty()) {
+ ALOGW("Expected UID and access for property: %s",
+ token.c_str());
+ }
+
+
+ PropertyAcl acl;
+ if (parsePropertyId(token.substr(2), propGroup, &acl.propId)
+ && parseUid(strUid, &acl.uid)
+ && parseAccess(strAccess, &acl.access)) {
+ propertyAclMap->emplace(acl.propId, std::move(acl));
+ } else {
+ return false;
+ }
+ } else {
+ ALOGW("Unexpected token: %s", token.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool AccessControlConfigParser::parsePropertyGroup(
+ char group, VehiclePropertyGroup* outPropertyGroup) const {
+ switch (group) {
+ case 'S': // Fall through.
+ case 's':
+ *outPropertyGroup = VehiclePropertyGroup::SYSTEM;
+ break;
+ case 'V': // Fall through.
+ case 'v':
+ *outPropertyGroup = VehiclePropertyGroup::VENDOR;
+ break;
+ default:
+ ALOGW("Unexpected group: %c", group);
+ return false;
+ }
+ return true;
+}
+
+bool AccessControlConfigParser::parsePropertyId(
+ const std::string& strPropId,
+ VehiclePropertyGroup propertyGroup,
+ int32_t* outVehicleProperty) const {
+ int32_t propId;
+ if (!parseInt(strPropId.c_str(), &propId)) {
+ ALOGW("Failed to convert property id to integer: %s",
+ strPropId.c_str());
+ return false;
+ }
+ propId |= static_cast<int>(propertyGroup);
+ auto it = mStrippedToVehiclePropertyMap.find(propId);
+ if (it == mStrippedToVehiclePropertyMap.end()) {
+ ALOGW("Property Id not found or not supported: 0x%x", propId);
+ return false;
+ }
+ *outVehicleProperty = it->second;
+ return true;
+}
+
+bool AccessControlConfigParser::parseInt(const char* strValue,
+ int* outIntValue) {
+ char* end;
+ long num = std::strtol(strValue, &end, 0 /* auto detect base */);
+ bool success = *end == 0 && errno != ERANGE;
+ if (success) {
+ *outIntValue = static_cast<int>(num);
+ }
+
+ return success;
+}
+
+bool AccessControlConfigParser::parseUid(const std::string& strUid,
+ unsigned* outUid) const {
+ auto element = mUidMap.find(strUid);
+ if (element != mUidMap.end()) {
+ *outUid = element->second;
+ } else {
+ int val;
+ if (!parseInt(strUid.c_str(), &val)) {
+ ALOGW("Failed to convert UID '%s' to integer", strUid.c_str());
+ return false;
+ }
+ *outUid = static_cast<unsigned>(val);
+ }
+ return true;
+}
+
+bool AccessControlConfigParser::parseAccess(
+ const std::string& strAccess, VehiclePropertyAccess* outAccess) const {
+ if (strAccess.size() == 0 || strAccess.size() > 2) {
+ ALOGW("Unknown access mode '%s'", strAccess.c_str());
+ return false;
+ }
+ int32_t access = static_cast<int32_t>(VehiclePropertyAccess::NONE);
+ for (char c : strAccess) {
+ if (c == 'R' || c == 'r') {
+ access |= VehiclePropertyAccess::READ;
+ } else if (c == 'W' || c == 'w') {
+ access |= VehiclePropertyAccess::WRITE;
+ } else {
+ ALOGW("Unknown access mode: %c", c);
+ return false;
+ }
+ }
+ *outAccess = static_cast<VehiclePropertyAccess>(access);
+ return true;
+}
+
+void AccessControlConfigParser::split(const std::string& line,
+ std::list<std::string>* outTokens) {
+ outTokens->clear();
+ std::istringstream iss(line);
+
+ while (!iss.eof()) {
+ std::string token;
+ iss >> token;
+ outTokens->push_back(std::move(token));
+ }
+}
+
+std::string AccessControlConfigParser::readNextToken(
+ std::list<std::string>* tokens) const {
+ if (tokens->empty()) {
+ return "";
+ }
+
+ std::string token = tokens->front();
+ tokens->pop_front();
+ return token;
+}
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
new file mode 100644
index 0000000..4493a41
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-impl"
+
+#include "SubscriptionManager.h"
+
+#include <cmath>
+#include <inttypes.h>
+
+#include <android/log.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
+ const SubscribeOptions &newOpts,
+ SubscribeOptions *outResult) {
+
+ int32_t updatedAreas = oldOpts.vehicleAreas;
+ if (updatedAreas != kAllSupportedAreas) {
+ updatedAreas = newOpts.vehicleAreas != kAllSupportedAreas
+ ? updatedAreas | newOpts.vehicleAreas
+ : kAllSupportedAreas;
+ }
+
+ float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
+ SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
+
+ bool updated = updatedRate > oldOpts.sampleRate
+ || updatedAreas != oldOpts.vehicleAreas
+ || updatedFlags != oldOpts.flags;
+ if (updated) {
+ *outResult = oldOpts;
+ outResult->vehicleAreas = updatedAreas;
+ outResult->sampleRate = updatedRate;
+ outResult->flags = updatedFlags;
+ }
+
+ return updated;
+}
+
+void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts) {
+ ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
+
+ auto it = mSubscriptions.find(opts.propId);
+ if (it == mSubscriptions.end()) {
+ mSubscriptions.emplace(opts.propId, opts);
+ } else {
+ const SubscribeOptions& oldOpts = it->second;
+ SubscribeOptions updatedOptions;
+ if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) {
+ mSubscriptions.erase(it);
+ mSubscriptions.emplace(opts.propId, updatedOptions);
+ }
+ }
+}
+
+bool HalClient::isSubscribed(int32_t propId,
+ int32_t areaId,
+ SubscribeFlags flags) {
+ auto it = mSubscriptions.find(propId);
+ if (it == mSubscriptions.end()) {
+ return false;
+ }
+ const SubscribeOptions& opts = it->second;
+ bool res = (opts.flags & flags)
+ && (opts.vehicleAreas == 0 || areaId == 0 || opts.vehicleAreas & areaId);
+ return res;
+}
+
+std::vector<int32_t> HalClient::getSubscribedProperties() const {
+ std::vector<int32_t> props;
+ for (const auto& subscription : mSubscriptions) {
+ ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId);
+ props.push_back(subscription.first);
+ }
+ return props;
+}
+
+StatusCode SubscriptionManager::addOrUpdateSubscription(
+ const sp<IVehicleCallback> &callback,
+ const hidl_vec<SubscribeOptions> &optionList,
+ std::list<SubscribeOptions>* outUpdatedSubscriptions) {
+ outUpdatedSubscriptions->clear();
+
+ MuxGuard g(mLock);
+
+ ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
+
+ const sp<HalClient>& client = getOrCreateHalClientLocked(callback);
+ if (client.get() == nullptr) {
+ return StatusCode::INTERNAL_ERROR;
+ }
+
+ for (size_t i = 0; i < optionList.size(); i++) {
+ const SubscribeOptions& opts = optionList[i];
+ ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
+ client->addOrUpdateSubscription(opts);
+
+ addClientToPropMapLocked(opts.propId, client);
+
+ if (SubscribeFlags::HAL_EVENT & opts.flags) {
+ SubscribeOptions updated;
+ if (updateHalEventSubscriptionLocked(opts, &updated)) {
+ outUpdatedSubscriptions->push_back(updated);
+ }
+ }
+ }
+
+ return StatusCode::OK;
+}
+
+std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
+ const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
+ SubscribeFlags flags) const {
+ std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap;
+
+ {
+ MuxGuard g(mLock);
+ for (const auto& propValue: propValues) {
+ VehiclePropValue* v = propValue.get();
+ auto clients = getSubscribedClientsLocked(
+ v->prop, v->areaId, flags);
+ for (const auto& client : clients) {
+ clientValuesMap[client].push_back(v);
+ }
+ }
+ }
+
+ std::list<HalClientValues> clientValues;
+ for (const auto& entry : clientValuesMap) {
+ clientValues.push_back(HalClientValues {
+ .client = entry.first,
+ .values = entry.second
+ });
+ }
+
+ return clientValues;
+}
+
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(
+ int32_t propId, int32_t area, SubscribeFlags flags) const {
+ MuxGuard g(mLock);
+ return getSubscribedClientsLocked(propId, area, flags);
+}
+
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
+ int32_t propId, int32_t area, SubscribeFlags flags) const {
+ std::list<sp<HalClient>> subscribedClients;
+
+ sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
+ if (propClients.get() != nullptr) {
+ for (size_t i = 0; i < propClients->size(); i++) {
+ const auto& client = propClients->itemAt(i);
+ if (client->isSubscribed(propId, area, flags)) {
+ subscribedClients.push_back(client);
+ }
+ }
+ }
+
+ return subscribedClients;
+}
+
+bool SubscriptionManager::updateHalEventSubscriptionLocked(
+ const SubscribeOptions &opts, SubscribeOptions *outUpdated) {
+ bool updated = false;
+ auto it = mHalEventSubscribeOptions.find(opts.propId);
+ if (it == mHalEventSubscribeOptions.end()) {
+ *outUpdated = opts;
+ mHalEventSubscribeOptions.emplace(opts.propId, opts);
+ updated = true;
+ } else {
+ const SubscribeOptions& oldOpts = it->second;
+
+ if (mergeSubscribeOptions(oldOpts, opts, outUpdated)) {
+ mHalEventSubscribeOptions.erase(opts.propId);
+ mHalEventSubscribeOptions.emplace(opts.propId, *outUpdated);
+ updated = true;
+ }
+ }
+
+ return updated;
+}
+
+void SubscriptionManager::addClientToPropMapLocked(
+ int32_t propId, const sp<HalClient> &client) {
+ auto it = mPropToClients.find(propId);
+ sp<HalClientVector> propClients;
+ if (it == mPropToClients.end()) {
+ propClients = new HalClientVector();
+ mPropToClients.insert(std::make_pair(propId, propClients));
+ } else {
+ propClients = it->second;
+ }
+ propClients->addOrUpdate(client);
+}
+
+sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
+ int32_t propId) const {
+ auto it = mPropToClients.find(propId);
+ return it == mPropToClients.end() ? nullptr : it->second;
+}
+
+sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked(
+ const sp<IVehicleCallback>& callback) {
+ auto it = mClients.find(callback);
+ if (it == mClients.end()) {
+ uint64_t cookie = reinterpret_cast<uint64_t>(callback.get());
+ ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
+ auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
+ if (!res.isOk()) { // Client is already dead?
+ ALOGW("%s failed to link to death, client %p, err: %s",
+ __func__, callback.get(), res.description().c_str());
+ return nullptr;
+ }
+ IPCThreadState* self = IPCThreadState::self();
+ pid_t pid = self->getCallingPid();
+ uid_t uid = self->getCallingUid();
+ sp<HalClient> client = new HalClient(callback, pid, uid);
+ mClients.emplace(callback, client);
+ return client;
+ } else {
+ return it->second;
+ }
+}
+
+void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
+ int32_t propId) {
+ MuxGuard g(mLock);
+ auto propertyClients = getClientsForPropertyLocked(propId);
+ auto clientIter = mClients.find(callback);
+ if (clientIter == mClients.end()) {
+ ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId);
+ } else {
+ auto client = clientIter->second;
+
+ if (propertyClients != nullptr) {
+ propertyClients->remove(client);
+
+ if (propertyClients->isEmpty()) {
+ mPropToClients.erase(propId);
+ }
+ }
+
+ bool isClientSubscribedToOtherProps = false;
+ for (const auto& propClient : mPropToClients) {
+ if (propClient.second->indexOf(client) >= 0) {
+ isClientSubscribedToOtherProps = true;
+ break;
+ }
+ }
+
+ if (!isClientSubscribedToOtherProps) {
+ auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
+ if (!res.isOk()) {
+ ALOGW("%s failed to unlink to death, client: %p, err: %s",
+ __func__, client->getCallback().get(), res.description().c_str());
+ }
+ mClients.erase(clientIter);
+ }
+ }
+
+ if (propertyClients == nullptr || propertyClients->isEmpty()) {
+ mHalEventSubscribeOptions.erase(propId);
+ mOnPropertyUnsubscribed(propId);
+ }
+}
+
+void SubscriptionManager::onCallbackDead(uint64_t cookie) {
+ ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie);
+ IVehicleCallback* callback = reinterpret_cast<IVehicleCallback*>(cookie);
+
+ std::vector<int32_t> props;
+ {
+ MuxGuard g(mLock);
+ const auto& it = mClients.find(callback);
+ if (it == mClients.end()) {
+ return; // Nothing to do here, client wasn't subscribed to any properties.
+ }
+ const auto& halClient = it->second;
+ props = halClient->getSubscribedProperties();
+ }
+
+ for (int32_t propId : props) {
+ unsubscribe(callback, propId);
+ }
+}
+
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
new file mode 100644
index 0000000..8906f6e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-impl"
+
+#include "VehicleHalManager.h"
+
+#include <fstream>
+
+#include <android/log.h>
+#include <private/android_filesystem_config.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+using namespace std::placeholders;
+
+constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
+
+const VehiclePropValue kEmptyValue{};
+
+/**
+ * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
+ * to store in reusable object pool.
+ */
+constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
+
+Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
+ ALOGI("getAllPropConfigs called");
+ hidl_vec<VehiclePropConfig> hidlConfigs;
+ auto& halConfig = mConfigIndex->getAllConfigs();
+
+ hidlConfigs.setToExternal(
+ const_cast<VehiclePropConfig *>(halConfig.data()),
+ halConfig.size());
+
+ _hidl_cb(hidlConfigs);
+
+ return Void();
+}
+
+Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
+ getPropConfigs_cb _hidl_cb) {
+ std::vector<VehiclePropConfig> configs;
+ for (size_t i = 0; i < properties.size(); i++) {
+ auto prop = properties[i];
+ if (mConfigIndex->hasConfig(prop)) {
+ configs.push_back(mConfigIndex->getConfig(prop));
+ } else {
+ ALOGW("Requested config for undefined property: 0x%x", prop);
+ _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>());
+ }
+ }
+
+ _hidl_cb(StatusCode::OK, configs);
+
+ return Void();
+}
+
+Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
+ const auto* config = getPropConfigOrNull(requestedPropValue.prop);
+ if (config == nullptr) {
+ ALOGE("Failed to get value: config not found, property: 0x%x",
+ requestedPropValue.prop);
+ _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
+ return Void();
+ }
+
+ if (!checkReadPermission(*config, getCaller())) {
+ _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
+ return Void();
+ }
+
+ StatusCode status;
+ auto value = mHal->get(requestedPropValue, &status);
+ _hidl_cb(status, value.get() ? *value : kEmptyValue);
+
+
+ return Void();
+}
+
+Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
+ auto prop = value.prop;
+ const auto* config = getPropConfigOrNull(prop);
+ if (config == nullptr) {
+ ALOGE("Failed to set value: config not found, property: 0x%x", prop);
+ return StatusCode::INVALID_ARG;
+ }
+
+ if (!checkWritePermission(*config, getCaller())) {
+ return StatusCode::ACCESS_DENIED;
+ }
+
+ handlePropertySetEvent(value);
+
+ auto status = mHal->set(value);
+
+ return Return<StatusCode>(status);
+}
+
+Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
+ const hidl_vec<SubscribeOptions> &options) {
+ hidl_vec<SubscribeOptions> verifiedOptions(options);
+ auto caller = getCaller();
+ for (size_t i = 0; i < verifiedOptions.size(); i++) {
+ SubscribeOptions& ops = verifiedOptions[i];
+ auto prop = ops.propId;
+
+ const auto* config = getPropConfigOrNull(prop);
+ if (config == nullptr) {
+ ALOGE("Failed to subscribe: config not found, property: 0x%x",
+ prop);
+ return StatusCode::INVALID_ARG;
+ }
+
+ if (ops.flags == SubscribeFlags::UNDEFINED) {
+ ALOGE("Failed to subscribe: undefined flag in options provided");
+ return StatusCode::INVALID_ARG;
+ }
+
+ if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) {
+ return StatusCode::ACCESS_DENIED;
+ }
+
+ if (!isSubscribable(*config, ops.flags)) {
+ ALOGE("Failed to subscribe: property 0x%x is not subscribable",
+ prop);
+ return StatusCode::INVALID_ARG;
+ }
+
+ int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas;
+ if (areas != 0 && ((areas & config->supportedAreas) != areas)) {
+ ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are "
+ "out of supported range of 0x%x", prop, ops.vehicleAreas,
+ config->supportedAreas);
+ return StatusCode::INVALID_ARG;
+ }
+
+ ops.vehicleAreas = areas;
+ ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
+ }
+
+ std::list<SubscribeOptions> updatedOptions;
+ auto res = mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions,
+ &updatedOptions);
+ if (StatusCode::OK != res) {
+ ALOGW("%s failed to subscribe, error code: %d", __func__, res);
+ return res;
+ }
+
+ for (auto opt : updatedOptions) {
+ mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
+ }
+
+ return StatusCode::OK;
+}
+
+Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
+ int32_t propId) {
+ mSubscriptionManager.unsubscribe(callback, propId);
+ return StatusCode::OK;
+}
+
+Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) {
+ _hidl_cb("");
+ return Void();
+}
+
+void VehicleHalManager::init() {
+ ALOGI("VehicleHalManager::init");
+
+ mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
+
+
+ mBatchingConsumer.run(&mEventQueue,
+ kHalEventBatchingTimeWindow,
+ std::bind(&VehicleHalManager::onBatchHalEvent,
+ this, _1));
+
+ mHal->init(&mValueObjectPool,
+ std::bind(&VehicleHalManager::onHalEvent, this, _1),
+ std::bind(&VehicleHalManager::onHalPropertySetError, this,
+ _1, _2, _3));
+
+ // Initialize index with vehicle configurations received from VehicleHal.
+ auto supportedPropConfigs = mHal->listProperties();
+ mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
+
+ std::vector<int32_t> supportedProperties(
+ supportedPropConfigs.size());
+ for (const auto& config : supportedPropConfigs) {
+ supportedProperties.push_back(config.prop);
+ }
+
+ AccessControlConfigParser aclParser(supportedProperties);
+ const char* configs[] = { "/system/etc/vehicle_access.conf",
+ "/vendor/etc/vehicle_access.conf" };
+ for (const char* filename : configs) {
+ readAndParseAclConfig(filename, &aclParser, &mPropertyAclMap);
+ }
+}
+
+VehicleHalManager::~VehicleHalManager() {
+ mBatchingConsumer.requestStop();
+ mEventQueue.deactivate();
+ // We have to wait until consumer thread is fully stopped because it may
+ // be in a state of running callback (onBatchHalEvent).
+ mBatchingConsumer.waitStopped();
+ ALOGI("VehicleHalManager::dtor");
+}
+
+void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
+ mEventQueue.push(std::move(v));
+}
+
+void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
+ int32_t property,
+ int32_t areaId) {
+ const auto& clients = mSubscriptionManager.getSubscribedClients(
+ property, 0, SubscribeFlags::HAL_EVENT);
+
+ for (auto client : clients) {
+ client->getCallback()->onPropertySetError(errorCode, property, areaId);
+ }
+}
+
+void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
+ const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
+ values, SubscribeFlags::HAL_EVENT);
+
+ for (const HalClientValues& cv : clientValues) {
+ auto vecSize = cv.values.size();
+ hidl_vec<VehiclePropValue> vec;
+ if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
+ vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
+ } else {
+ vec.resize(vecSize);
+ }
+
+ int i = 0;
+ for (VehiclePropValue* pValue : cv.values) {
+ shallowCopy(&(vec)[i++], *pValue);
+ }
+ auto status = cv.client->getCallback()->onPropertyEvent(vec);
+ if (!status.isOk()) {
+ ALOGE("Failed to notify client %s, err: %s",
+ toString(cv.client->getCallback()).c_str(),
+ status.description().c_str());
+ }
+ }
+}
+
+bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) {
+ return (mode & VehiclePropertyChangeMode::ON_SET)
+ || (mode & VehiclePropertyChangeMode::ON_CHANGE);
+}
+
+float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config,
+ float sampleRate) {
+ if (isSampleRateFixed(config.changeMode)) {
+ if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) {
+ ALOGW("Sample rate is greater than zero for on change type. "
+ "Ignoring it.");
+ }
+ return 0.0;
+ } else {
+ if (sampleRate > config.maxSampleRate) {
+ ALOGW("Sample rate %f is higher than max %f. Setting sampling rate "
+ "to max.", sampleRate, config.maxSampleRate);
+ return config.maxSampleRate;
+ }
+ if (sampleRate < config.minSampleRate) {
+ ALOGW("Sample rate %f is lower than min %f. Setting sampling rate "
+ "to min.", sampleRate, config.minSampleRate);
+ return config.minSampleRate;
+ }
+ }
+ return sampleRate; // Provided sample rate was good, no changes.
+}
+
+bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
+ SubscribeFlags flags) {
+ bool isReadable = config.access & VehiclePropertyAccess::READ;
+
+ if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) {
+ ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
+ return false;
+ }
+ if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
+ ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
+ return false;
+ }
+
+ //TODO: extend to support event notification for set from android
+ if (config.changeMode == VehiclePropertyChangeMode::POLL) {
+ ALOGW("Cannot subscribe, property 0x%x is poll only", config.prop);
+ return false;
+ }
+ return true;
+}
+
+bool VehicleHalManager::checkAcl(uid_t callerUid, int32_t propertyId,
+ VehiclePropertyAccess requiredAccess) const {
+ if (callerUid == AID_SYSTEM && isSystemProperty(propertyId)) {
+ return true;
+ }
+
+ auto range = mPropertyAclMap.equal_range(propertyId);
+ for (auto it = range.first; it != range.second; ++it) {
+ auto& acl = it->second;
+ if (acl.uid == callerUid && (acl.access & requiredAccess)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config,
+ const Caller& caller) const {
+ if (!(config.access & VehiclePropertyAccess::WRITE)) {
+ ALOGW("Property 0%x has no write access", config.prop);
+ return false;
+ }
+ return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::WRITE);
+}
+
+bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config,
+ const Caller& caller) const {
+ if (!(config.access & VehiclePropertyAccess::READ)) {
+ ALOGW("Property 0%x has no read access", config.prop);
+ return false;
+ }
+
+ return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::READ);
+}
+
+void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
+ auto clients = mSubscriptionManager.getSubscribedClients(
+ value.prop, value.areaId, SubscribeFlags::SET_CALL);
+ for (auto client : clients) {
+ client->getCallback()->onPropertySet(value);
+ }
+}
+
+const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
+ int32_t prop) const {
+ return mConfigIndex->hasConfig(prop)
+ ? &mConfigIndex->getConfig(prop) : nullptr;
+}
+
+Caller VehicleHalManager::getCaller() {
+ Caller caller;
+ IPCThreadState* self = IPCThreadState::self();
+ caller.pid = self->getCallingPid();
+ caller.uid = self->getCallingUid();
+
+ return caller;
+}
+
+void VehicleHalManager::readAndParseAclConfig(const char* filename,
+ AccessControlConfigParser* parser,
+ PropertyAclMap* outAclMap) {
+ std::ifstream file(filename);
+ if (file.is_open()) {
+ ALOGI("Parsing file: %s", filename);
+ parser->parseFromStream(&file, outAclMap);
+ file.close();
+ }
+}
+
+void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
+ mHal->unsubscribe(propertyId);
+}
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
new file mode 100644
index 0000000..ac1245a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-impl"
+
+#include "VehicleObjectPool.h"
+
+#include <log/log.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+ VehiclePropertyType type, size_t vecSize) {
+ return isDisposable(type, vecSize)
+ ? obtainDisposable(type, vecSize)
+ : obtainRecylable(type, vecSize);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+ const VehiclePropValue& src) {
+ if (src.prop == toInt(VehicleProperty::INVALID)) {
+ ALOGE("Unable to obtain an object from pool for unknown property");
+ return RecyclableType();
+ }
+ VehiclePropertyType type = getPropType(src.prop);
+ size_t vecSize = getVehicleRawValueVectorSize(src.value, type);;
+ auto dest = obtain(type, vecSize);
+
+ dest->prop = src.prop;
+ dest->areaId = src.areaId;
+ dest->timestamp = src.timestamp;
+ copyVehicleRawValue(&dest->value, src.value);
+
+ return dest;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt32(
+ int32_t value) {
+ auto val = obtain(VehiclePropertyType::INT32);
+ val->value.int32Values[0] = value;
+ return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt64(
+ int64_t value) {
+ auto val = obtain(VehiclePropertyType::INT64);
+ val->value.int64Values[0] = value;
+ return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainFloat(
+ float value) {
+ auto val = obtain(VehiclePropertyType::FLOAT);
+ val->value.floatValues[0] = value;
+ return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainString(
+ const char* cstr) {
+ auto val = obtain(VehiclePropertyType::STRING);
+ val->value.stringValue = cstr;
+ return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainComplex() {
+ return obtain(VehiclePropertyType::COMPLEX);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecylable(
+ VehiclePropertyType type, size_t vecSize) {
+ // VehiclePropertyType is not overlapping with vectorSize.
+ int32_t key = static_cast<int32_t>(type)
+ | static_cast<int32_t>(vecSize);
+
+ std::lock_guard<std::mutex> g(mLock);
+ auto it = mValueTypePools.find(key);
+
+ if (it == mValueTypePools.end()) {
+ auto newPool(std::make_unique<InternalPool>(type, vecSize));
+ it = mValueTypePools.emplace(key, std::move(newPool)).first;
+ }
+ return it->second->obtain();
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainBoolean(
+ bool value) {
+ return obtainInt32(value);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainDisposable(
+ VehiclePropertyType valueType, size_t vectorSize) const {
+ return RecyclableType {
+ createVehiclePropValue(valueType, vectorSize).release(),
+ mDisposableDeleter
+ };
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+ VehiclePropertyType type) {
+ return obtain(type, 1);
+}
+
+
+void VehiclePropValuePool::InternalPool::recycle(VehiclePropValue* o) {
+ if (o == nullptr) {
+ ALOGE("Attempt to recycle nullptr");
+ return;
+ }
+
+ if (!check(&o->value)) {
+ ALOGE("Discarding value for prop 0x%x because it contains "
+ "data that is not consistent with this pool. "
+ "Expected type: %d, vector size: %zu",
+ o->prop, mPropType, mVectorSize);
+ delete o;
+ } else {
+ ObjectPool<VehiclePropValue>::recycle(o);
+ }
+}
+
+bool VehiclePropValuePool::InternalPool::check(VehiclePropValue::RawValue* v) {
+ return check(&v->int32Values,
+ (VehiclePropertyType::INT32 == mPropType
+ || VehiclePropertyType::INT32_VEC == mPropType
+ || VehiclePropertyType::BOOLEAN == mPropType))
+ && check(&v->floatValues,
+ (VehiclePropertyType::FLOAT == mPropType
+ || VehiclePropertyType::FLOAT_VEC == mPropType))
+ && check(&v->int64Values,
+ VehiclePropertyType::INT64 == mPropType)
+ && check(&v->bytes,
+ VehiclePropertyType::BYTES == mPropType)
+ && v->stringValue.size() == 0;
+}
+
+VehiclePropValue* VehiclePropValuePool::InternalPool::createObject() {
+ return createVehiclePropValue(mPropType, mVectorSize).release();
+}
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
new file mode 100644
index 0000000..311cdef
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.0-impl"
+
+#include "VehicleUtils.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+//namespace utils {
+
+std::unique_ptr<VehiclePropValue> createVehiclePropValue(
+ VehiclePropertyType type, size_t vecSize) {
+ auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+ switch (type) {
+ case VehiclePropertyType::INT32: // fall through
+ case VehiclePropertyType::INT32_VEC: // fall through
+ case VehiclePropertyType::BOOLEAN:
+ val->value.int32Values.resize(vecSize);
+ break;
+ case VehiclePropertyType::FLOAT: // fall through
+ case VehiclePropertyType::FLOAT_VEC:
+ val->value.floatValues.resize(vecSize);
+ break;
+ case VehiclePropertyType::INT64:
+ val->value.int64Values.resize(vecSize);
+ break;
+ case VehiclePropertyType::BYTES:
+ val->value.bytes.resize(vecSize);
+ break;
+ case VehiclePropertyType::STRING:
+ case VehiclePropertyType::COMPLEX:
+ break; // Valid, but nothing to do.
+ default:
+ ALOGE("createVehiclePropValue: unknown type: %d", type);
+ val.reset(nullptr);
+ }
+ return val;
+}
+
+size_t getVehicleRawValueVectorSize(
+ const VehiclePropValue::RawValue& value, VehiclePropertyType type) {
+ switch (type) {
+ case VehiclePropertyType::INT32: // fall through
+ case VehiclePropertyType::INT32_VEC: // fall through
+ case VehiclePropertyType::BOOLEAN:
+ return value.int32Values.size();
+ case VehiclePropertyType::FLOAT: // fall through
+ case VehiclePropertyType::FLOAT_VEC:
+ return value.floatValues.size();
+ case VehiclePropertyType::INT64:
+ return value.int64Values.size();
+ case VehiclePropertyType::BYTES:
+ return value.bytes.size();
+ default:
+ return 0;
+ }
+}
+
+template<typename T>
+inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+ for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
+ (*dest)[i] = src[i];
+ }
+}
+
+void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
+ const VehiclePropValue::RawValue& src) {
+ dest->int32Values = src.int32Values;
+ dest->floatValues = src.floatValues;
+ dest->int64Values = src.int64Values;
+ dest->bytes = src.bytes;
+ dest->stringValue = src.stringValue;
+}
+
+template<typename T>
+void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+ if (src.size() > 0) {
+ dest->setToExternal(const_cast<T*>(&src[0]), src.size());
+ } else if (dest->size() > 0) {
+ dest->resize(0);
+ }
+}
+
+void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src) {
+ if (!src.empty()) {
+ dest->setToExternal(src.c_str(), src.size());
+ } else if (dest->size() > 0) {
+ dest->setToExternal(0, 0);
+ }
+}
+
+void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) {
+ dest->prop = src.prop;
+ dest->areaId = src.areaId;
+ dest->timestamp = src.timestamp;
+ shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values);
+ shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values);
+ shallowCopyHidlVec(&dest->value.floatValues, src.value.floatValues);
+ shallowCopyHidlVec(&dest->value.bytes, src.value.bytes);
+ shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue);
+}
+
+
+//} // namespace utils
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
new file mode 100644
index 0000000..6832ad3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * This is the communications base class. It defines the interface used in DefaultVehicleHal to
+ * send and receive data to and from the emulator.
+ */
+class CommBase {
+public:
+ virtual ~CommBase() = default;
+
+ /**
+ * Closes a connection if it is open.
+ */
+ virtual void stop() {}
+
+ /**
+ * Creates a connection to the other side.
+ *
+ * @return int Returns fd or socket number if connection is successful.
+ * Otherwise, returns -1 if no connection is availble.
+ */
+ virtual int connect() { return 0; }
+
+ /**
+ * Opens the communications channel.
+ *
+ * @return int Returns 0 if channel is opened, else -errno if failed.
+ */
+ virtual int open() = 0;
+
+ /**
+ * Blocking call to read data from the connection.
+ *
+ * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be
+ * an empty vector if the connection was closed or some other error occurred.
+ */
+ virtual std::vector<uint8_t> read() = 0;
+
+ /**
+ * Transmits a string of data to the emulator.
+ *
+ * @param data Serialized protobuf data to transmit.
+ *
+ * @return int Number of bytes transmitted, or -1 if failed.
+ */
+ virtual int write(const std::vector<uint8_t>& data) = 0;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
new file mode 100644
index 0000000..545de39
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <vhal_v2_0/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+const int32_t kHvacPowerProperties[] = {
+ toInt(VehicleProperty::HVAC_FAN_SPEED),
+ toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+};
+
+const VehiclePropConfig kVehicleProperties[] = {
+ {
+ .prop = toInt(VehicleProperty::INFO_MAKE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::CURRENT_GEAR),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ // TODO(bryaneyler): Ideally, this is generated dynamically from
+ // kHvacPowerProperties.
+ .configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_DEFROSTER),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas =
+ VehicleAreaWindow::FRONT_WINDSHIELD
+ | VehicleAreaWindow::REAR_WINDSHIELD
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_AC_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_AUTO_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1),
+ .minInt32Value = 1,
+ .maxInt32Value = 7
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas =
+ VehicleAreaZone::ROW_1_LEFT
+ | VehicleAreaZone::ROW_1_RIGHT,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ },
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minFloatValue = 16,
+ .maxFloatValue = 32,
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+ .access = VehiclePropertyAccess::READ,
+ // TODO(bryaneyler): Support ON_CHANGE as well.
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 1.0f,
+ .maxSampleRate = 2.0f,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::NIGHT_MODE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::DRIVING_STATUS),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::GEAR_SELECTION),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .minInt32Value = 0,
+ .maxInt32Value = 10
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::IGNITION_STATE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+
+ {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+ .maxSampleRate = 10, // 10 Hz, every 100 ms
+ }
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
new file mode 100644
index 0000000..03a65f3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "DefaultVehicleHal_v2_0"
+#include <android/log.h>
+
+#include <algorithm>
+#include <android-base/properties.h>
+#include <cstdio>
+
+#include "DefaultVehicleHal.h"
+#include "PipeComm.h"
+#include "SocketComm.h"
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg,
+ emulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = listProperties();
+ emulator::VehiclePropGet getProp = rxMsg.prop(0);
+
+ respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
+ respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+
+ for (auto& config : configs) {
+ // Find the config we are looking for
+ if (config.prop == getProp.prop()) {
+ emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ populateProtoVehicleConfig(protoCfg, config);
+ respMsg.set_status(emulator::RESULT_OK);
+ break;
+ }
+ }
+}
+
+void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */,
+ emulator::EmulatorMessage& respMsg) {
+ std::vector<VehiclePropConfig> configs = listProperties();
+
+ respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
+ respMsg.set_status(emulator::RESULT_OK);
+
+ for (auto& config : configs) {
+ emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+ populateProtoVehicleConfig(protoCfg, config);
+ }
+}
+
+void DefaultVehicleHal::doGetProperty(emulator::EmulatorMessage& rxMsg,
+ emulator::EmulatorMessage& respMsg) {
+ int32_t areaId = 0;
+ emulator::VehiclePropGet getProp = rxMsg.prop(0);
+ int32_t propId = getProp.prop();
+ emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+ VehiclePropValue* val;
+
+ respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+
+ if (getProp.has_area_id()) {
+ areaId = getProp.area_id();
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ val = getVehiclePropValueLocked(propId, areaId);
+ if (val != nullptr) {
+ emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ populateProtoVehiclePropValue(protoVal, val);
+ status = emulator::RESULT_OK;
+ }
+ }
+
+ respMsg.set_status(status);
+}
+
+void DefaultVehicleHal::doGetPropertyAll(emulator::EmulatorMessage& /* rxMsg */,
+ emulator::EmulatorMessage& respMsg) {
+ respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
+ respMsg.set_status(emulator::RESULT_OK);
+
+ {
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ for (auto& prop : mProps) {
+ emulator::VehiclePropValue* protoVal = respMsg.add_value();
+ populateProtoVehiclePropValue(protoVal, prop.second->get());
+ }
+ }
+}
+
+void DefaultVehicleHal::doSetProperty(emulator::EmulatorMessage& rxMsg,
+ emulator::EmulatorMessage& respMsg) {
+ emulator::VehiclePropValue protoVal = rxMsg.value(0);
+ VehiclePropValue val;
+
+ respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+
+ val.prop = protoVal.prop();
+ val.areaId = protoVal.area_id();
+ val.timestamp = elapsedRealtimeNano();
+
+ // Copy value data if it is set. This automatically handles complex data types if needed.
+ if (protoVal.has_string_value()) {
+ val.value.stringValue = protoVal.string_value().c_str();
+ }
+
+ if (protoVal.has_bytes_value()) {
+ std::vector<uint8_t> tmp(protoVal.bytes_value().begin(), protoVal.bytes_value().end());
+ val.value.bytes = tmp;
+ }
+
+ if (protoVal.int32_values_size() > 0) {
+ std::vector<int32_t> int32Values = std::vector<int32_t>(protoVal.int32_values_size());
+ for (int i=0; i<protoVal.int32_values_size(); i++) {
+ int32Values[i] = protoVal.int32_values(i);
+ }
+ val.value.int32Values = int32Values;
+ }
+
+ if (protoVal.int64_values_size() > 0) {
+ std::vector<int64_t> int64Values = std::vector<int64_t>(protoVal.int64_values_size());
+ for (int i=0; i<protoVal.int64_values_size(); i++) {
+ int64Values[i] = protoVal.int64_values(i);
+ }
+ val.value.int64Values = int64Values;
+ }
+
+ if (protoVal.float_values_size() > 0) {
+ std::vector<float> floatValues = std::vector<float>(protoVal.float_values_size());
+ for (int i=0; i<protoVal.float_values_size(); i++) {
+ floatValues[i] = protoVal.float_values(i);
+ }
+ val.value.floatValues = floatValues;
+ }
+
+ if (updateProperty(val) == StatusCode::OK) {
+ // Send property up to VehicleHalManager via callback
+ auto& pool = *getValuePool();
+ VehiclePropValuePtr v = pool.obtain(val);
+
+ doHalEvent(std::move(v));
+ respMsg.set_status(emulator::RESULT_OK);
+ } else {
+ respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+ }
+}
+
+// This function should only be called while mPropsMutex is locked.
+VehiclePropValue* DefaultVehicleHal::getVehiclePropValueLocked(int32_t propId, int32_t areaId) {
+ if (getPropArea(propId) == VehicleArea::GLOBAL) {
+ // In VehicleHal, global properties have areaId = -1. We use 0.
+ areaId = 0;
+ }
+
+ auto prop = mProps.find(std::make_pair(propId, areaId));
+ if (prop != mProps.end()) {
+ return prop->second->get();
+ }
+ ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
+ return nullptr;
+}
+
+void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) {
+ emulator::EmulatorMessage rxMsg;
+ emulator::EmulatorMessage respMsg;
+
+ if (rxMsg.ParseFromArray(msg.data(), msg.size())) {
+ switch (rxMsg.msg_type()) {
+ case emulator::GET_CONFIG_CMD:
+ doGetConfig(rxMsg, respMsg);
+ break;
+ case emulator::GET_CONFIG_ALL_CMD:
+ doGetConfigAll(rxMsg, respMsg);
+ break;
+ case emulator::GET_PROPERTY_CMD:
+ doGetProperty(rxMsg, respMsg);
+ break;
+ case emulator::GET_PROPERTY_ALL_CMD:
+ doGetPropertyAll(rxMsg, respMsg);
+ break;
+ case emulator::SET_PROPERTY_CMD:
+ doSetProperty(rxMsg, respMsg);
+ break;
+ default:
+ ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
+ respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+ break;
+ }
+
+ // Send the reply
+ txMsg(respMsg);
+ } else {
+ ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
+ }
+}
+
+// Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig
+void DefaultVehicleHal::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ const VehiclePropConfig& cfg) {
+ protoCfg->set_prop(cfg.prop);
+ protoCfg->set_access(toInt(cfg.access));
+ protoCfg->set_change_mode(toInt(cfg.changeMode));
+ protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+ if (!isGlobalProp(cfg.prop)) {
+ protoCfg->set_supported_areas(cfg.supportedAreas);
+ }
+
+ for (auto& configElement : cfg.configArray) {
+ protoCfg->add_config_array(configElement);
+ }
+
+ if (cfg.configString.size() > 0) {
+ protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+ }
+
+ // Populate the min/max values based on property type
+ switch (getPropType(cfg.prop)) {
+ case VehiclePropertyType::STRING:
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32_VEC:
+ case VehiclePropertyType::FLOAT_VEC:
+ case VehiclePropertyType::BYTES:
+ case VehiclePropertyType::COMPLEX:
+ // Do nothing. These types don't have min/max values
+ break;
+ case VehiclePropertyType::INT64:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
+ aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
+ }
+ break;
+ case VehiclePropertyType::FLOAT:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
+ aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
+ }
+ break;
+ case VehiclePropertyType::INT32:
+ if (cfg.areaConfigs.size() > 0) {
+ emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+ aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
+ aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
+ }
+ break;
+ default:
+ ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop)));
+ break;
+ }
+
+ protoCfg->set_min_sample_rate(cfg.minSampleRate);
+ protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+// Copies internal VehiclePropValue data structure to protobuf VehiclePropValue
+void DefaultVehicleHal::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ const VehiclePropValue* val) {
+ protoVal->set_prop(val->prop);
+ protoVal->set_value_type(toInt(getPropType(val->prop)));
+ protoVal->set_timestamp(val->timestamp);
+ protoVal->set_area_id(val->areaId);
+
+ // Copy value data if it is set.
+ // - for bytes and strings, this is indicated by size > 0
+ // - for int32, int64, and float, copy the values if vectors have data
+ if (val->value.stringValue.size() > 0) {
+ protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
+ }
+
+ if (val->value.bytes.size() > 0) {
+ protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
+ }
+
+ for (auto& int32Value : val->value.int32Values) {
+ protoVal->add_int32_values(int32Value);
+ }
+
+ for (auto& int64Value : val->value.int64Values) {
+ protoVal->add_int64_values(int64Value);
+ }
+
+ for (auto& floatValue : val->value.floatValues) {
+ protoVal->add_float_values(floatValue);
+ }
+}
+
+void DefaultVehicleHal::rxMsg() {
+ int numBytes = 0;
+
+ while (mExit == 0) {
+ std::vector<uint8_t> msg = mComm->read();
+
+ if (msg.size() > 0) {
+ // Received a message.
+ parseRxProtoBuf(msg);
+ } else {
+ // This happens when connection is closed
+ ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
+ static_cast<int32_t>(msg.size()));
+ break;
+ }
+ }
+}
+
+void DefaultVehicleHal::rxThread() {
+ bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
+
+ if (isEmulator) {
+ // Initialize pipe to Emulator
+ mComm.reset(new PipeComm);
+ } else {
+ // Initialize socket over ADB
+ mComm.reset(new SocketComm);
+ }
+
+ int retVal = mComm->open();
+
+ if (retVal == 0) {
+ // Comms are properly opened
+ while (mExit == 0) {
+ retVal = mComm->connect();
+
+ if (retVal >= 0) {
+ rxMsg();
+ }
+
+ // Check every 100ms for a new connection
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ }
+}
+
+// This function sets the default value of a property if we are interested in setting it.
+// TODO: Co-locate the default values with the configuration structure, to make it easier to
+// add new properties and their defaults.
+void DefaultVehicleHal::setDefaultValue(VehiclePropValue* prop) {
+ switch (prop->prop) {
+ case toInt(VehicleProperty::INFO_MAKE):
+ prop->value.stringValue = "Default Car";
+ break;
+ case toInt(VehicleProperty::PERF_VEHICLE_SPEED):
+ prop->value.floatValues[0] = 0;
+ break;
+ case toInt(VehicleProperty::CURRENT_GEAR):
+ prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
+ break;
+ case toInt(VehicleProperty::PARKING_BRAKE_ON):
+ prop->value.int32Values[0] = 1;
+ break;
+ case toInt(VehicleProperty::FUEL_LEVEL_LOW):
+ prop->value.int32Values[0] = 0;
+ break;
+ case toInt(VehicleProperty::HVAC_POWER_ON):
+ prop->value.int32Values[0] = 1;
+ break;
+ case toInt(VehicleProperty::HVAC_DEFROSTER):
+ prop->value.int32Values[0] = 0;
+ break;
+ case toInt(VehicleProperty::HVAC_RECIRC_ON):
+ prop->value.int32Values[0] = 1;
+ break;
+ case toInt(VehicleProperty::HVAC_AC_ON):
+ prop->value.int32Values[0] = 1;
+ break;
+ case toInt(VehicleProperty::HVAC_AUTO_ON):
+ prop->value.int32Values[0] = 1;
+ break;
+ case toInt(VehicleProperty::HVAC_FAN_SPEED):
+ prop->value.int32Values[0] = 3;
+ break;
+ case toInt(VehicleProperty::HVAC_FAN_DIRECTION):
+ prop->value.int32Values[0] = toInt(VehicleHvacFanDirection::FACE);
+ break;
+ case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
+ prop->value.floatValues[0] = 16;
+ break;
+ case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
+ prop->value.floatValues[0] = 25;
+ break;
+ case toInt(VehicleProperty::NIGHT_MODE):
+ prop->value.int32Values[0] = 0;
+ break;
+ case toInt(VehicleProperty::DRIVING_STATUS):
+ prop->value.int32Values[0] = toInt(VehicleDrivingStatus::UNRESTRICTED);
+ break;
+ case toInt(VehicleProperty::GEAR_SELECTION):
+ prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
+ break;
+ case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
+ prop->value.floatValues[0] = 123000.0f; // In milliliters
+ break;
+ case toInt(VehicleProperty::ENGINE_OIL_TEMP):
+ prop->value.floatValues[0] = 101;
+ break;
+ case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
+ prop->value.int32Values[0] = 7;
+ break;
+ case toInt(VehicleProperty::IGNITION_STATE):
+ prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
+ break;
+ default:
+ ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
+ break;
+ }
+}
+
+// Transmit a reply back to the emulator
+void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
+ int numBytes = txMsg.ByteSize();
+ std::vector<uint8_t> msg(numBytes);
+
+ if (txMsg.SerializeToArray(msg.data(), msg.size())) {
+ int retVal = 0;
+
+ // Send the message
+ if (mExit == 0) {
+ mComm->write(msg);
+ }
+
+ if (retVal < 0) {
+ ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
+ }
+ } else {
+ ALOGE("%s: SerializeToString failed!", __func__);
+ }
+}
+
+// Updates the property value held in the HAL
+StatusCode DefaultVehicleHal::updateProperty(const VehiclePropValue& propValue) {
+ auto propId = propValue.prop;
+ auto areaId = propValue.areaId;
+ StatusCode status = StatusCode::INVALID_ARG;
+
+ {
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
+ if (internalPropValue != nullptr) {
+ internalPropValue->value = propValue.value;
+ internalPropValue->timestamp = propValue.timestamp;
+ status = StatusCode::OK;
+ }
+ }
+ return status;
+}
+
+VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
+ const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
+ auto areaId = requestedPropValue.areaId;
+ auto& pool = *getValuePool();
+ auto propId = requestedPropValue.prop;
+ StatusCode status;
+ VehiclePropValuePtr v = nullptr;
+
+ switch (propId) {
+ default:
+ {
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ VehiclePropValue *internalPropValue = getVehiclePropValueLocked(propId, areaId);
+ if (internalPropValue != nullptr) {
+ v = pool.obtain(*internalPropValue);
+ }
+ }
+
+ if (v != nullptr) {
+ status = StatusCode::OK;
+ } else {
+ status = StatusCode::INVALID_ARG;
+ }
+ break;
+ }
+
+ *outStatus = status;
+ return v;
+}
+
+StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
+ auto propId = propValue.prop;
+ StatusCode status;
+ switch (propId) {
+ default:
+ if (mHvacPowerProps.count(propId)) {
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+ auto hvacPowerOn = getVehiclePropValueLocked(toInt(VehicleProperty::HVAC_POWER_ON),
+ toInt(VehicleAreaZone::ROW_1));
+
+ if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
+ && hvacPowerOn->value.int32Values[0] == 0) {
+ status = StatusCode::NOT_AVAILABLE;
+ break;
+ }
+ }
+ status = updateProperty(propValue);
+ if (status == StatusCode::OK) {
+ // Send property update to emulator
+ emulator::EmulatorMessage msg;
+ emulator::VehiclePropValue *val = msg.add_value();
+ populateProtoVehiclePropValue(val, &propValue);
+ msg.set_status(emulator::RESULT_OK);
+ msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+ txMsg(msg);
+ }
+ break;
+ }
+
+ return status;
+}
+
+V2_0::StatusCode DefaultVehicleHal::addCustomProperty(int32_t property,
+ std::unique_ptr<CustomVehiclePropertyHandler>&& handler) {
+ mProps[std::make_pair(property, 0)] = std::move(handler);
+ ALOGW("%s: Added custom property: propId = 0x%x", __func__, property);
+ return StatusCode::OK;
+}
+
+// Parse supported properties list and generate vector of property values to hold current values.
+void DefaultVehicleHal::onCreate() {
+ // Initialize member variables
+ mExit = 0;
+
+ for (auto& prop : kHvacPowerProperties) {
+ mHvacPowerProps.insert(prop);
+ }
+
+ // Get the list of configurations supported by this HAL
+ std::vector<VehiclePropConfig> configs = listProperties();
+
+ for (auto& cfg : configs) {
+ VehiclePropertyType propType = getPropType(cfg.prop);
+ int32_t supportedAreas = cfg.supportedAreas;
+ int32_t vecSize;
+
+ // Set the vector size based on property type
+ switch (propType) {
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32:
+ case VehiclePropertyType::INT64:
+ case VehiclePropertyType::FLOAT:
+ vecSize = 1;
+ break;
+ case VehiclePropertyType::INT32_VEC:
+ case VehiclePropertyType::FLOAT_VEC:
+ case VehiclePropertyType::BYTES:
+ // TODO: Add proper support for these types
+ vecSize = 1;
+ break;
+ case VehiclePropertyType::STRING:
+ // Require individual handling
+ vecSize = 0;
+ break;
+ case VehiclePropertyType::COMPLEX:
+ switch (cfg.prop) {
+ default:
+ // Need to handle each complex property separately
+ break;
+ }
+ continue;
+ default:
+ ALOGE("%s: propType=0x%x not found", __func__, propType);
+ vecSize = 0;
+ break;
+ }
+
+ // A global property will have supportedAreas = 0
+ if (getPropArea(cfg.prop) == VehicleArea::GLOBAL) {
+ supportedAreas = 0;
+ }
+
+ // This loop is a do-while so it executes at least once to handle global properties
+ do {
+ int32_t curArea = supportedAreas;
+
+ // Clear the right-most bit of supportedAreas
+ supportedAreas &= supportedAreas - 1;
+
+ // Set curArea to the previously cleared bit
+ curArea ^= supportedAreas;
+
+ // Create a separate instance for each individual zone
+ std::unique_ptr<VehiclePropValue> prop = createVehiclePropValue(propType, vecSize);
+ prop->areaId = curArea;
+ prop->prop = cfg.prop;
+ setDefaultValue(prop.get());
+ std::unique_ptr<CustomVehiclePropertyHandler> handler;
+ handler.reset(new StoredValueCustomVehiclePropertyHandler());
+ handler->set(*prop);
+ mProps[std::make_pair(prop->prop, prop->areaId)] =
+ std::move(handler);
+ } while (supportedAreas != 0);
+ }
+
+ // Start rx thread
+ mThread = std::thread(&DefaultVehicleHal::rxThread, this);
+}
+
+void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
+ VehiclePropValuePtr v;
+
+ auto& pool = *getValuePool();
+
+ for (int32_t property : properties) {
+ if (isContinuousProperty(property)) {
+ // In real implementation this value should be read from sensor, random
+ // value used for testing purpose only.
+ std::lock_guard<std::mutex> lock(mPropsMutex);
+
+ VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
+ if (internalPropValue != nullptr) {
+ v = pool.obtain(*internalPropValue);
+ }
+ if (VehiclePropertyType::FLOAT == getPropType(property)) {
+ // Just get some randomness to continuous properties to see slightly differnt values
+ // on the other end.
+ v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
+ }
+ } else {
+ ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
+ }
+
+ if (v.get()) {
+ v->timestamp = elapsedRealtimeNano();
+ doHalEvent(std::move(v));
+ }
+ }
+}
+
+StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
+ float sampleRate) {
+ ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
+
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
+ }
+ return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
+ ALOGI("%s propId: 0x%x", __func__, property);
+ if (isContinuousProperty(property)) {
+ mRecurrentTimer.unregisterRecurrentEvent(property);
+ }
+ return StatusCode::OK;
+}
+
+const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
+ auto it = mPropConfigMap.find(propId);
+ return it == mPropConfigMap.end() ? nullptr : it->second;
+}
+
+bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
+ const VehiclePropConfig* config = getPropConfig(propId);
+ if (config == nullptr) {
+ ALOGW("Config not found for property: 0x%x", propId);
+ return false;
+ }
+ return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
+}
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
new file mode 100644
index 0000000..c8310b3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
+
+#include <map>
+#include <memory>
+#include <sys/socket.h>
+#include <thread>
+#include <unordered_set>
+
+#include <utils/SystemClock.h>
+
+#include "CommBase.h"
+#include "VehicleHalProto.pb.h"
+
+#include <vhal_v2_0/RecurrentTimer.h>
+#include <vhal_v2_0/VehicleHal.h>
+
+#include "DefaultConfig.h"
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class DefaultVehicleHal : public VehicleHal {
+public:
+ class CustomVehiclePropertyHandler {
+ public:
+ virtual VehiclePropValue* get() = 0;
+ virtual StatusCode set(const VehiclePropValue& propValue) = 0;
+ virtual ~CustomVehiclePropertyHandler() = default;
+ };
+
+protected:
+ class StoredValueCustomVehiclePropertyHandler :
+ public CustomVehiclePropertyHandler {
+ public:
+ VehiclePropValue* get() override {
+ return mPropValue.get();
+ }
+
+ StatusCode set(const VehiclePropValue& propValue) {
+ *mPropValue = propValue;
+ return StatusCode::OK;
+ }
+private:
+ std::unique_ptr<VehiclePropValue> mPropValue{new VehiclePropValue()};
+};
+
+public:
+ DefaultVehicleHal() : mRecurrentTimer(
+ std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
+ for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+ mPropConfigMap[kVehicleProperties[i].prop] = &kVehicleProperties[i];
+ }
+ }
+
+ ~DefaultVehicleHal() override {
+ // Notify thread to finish and wait for it to terminate
+ mExit = 1;
+
+ // Close emulator socket if it is open
+ mComm->stop();
+
+ mThread.join();
+ }
+
+ std::vector<VehiclePropConfig> listProperties() override {
+ return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
+ std::end(kVehicleProperties));
+ }
+
+ VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+ StatusCode* outStatus) override;
+
+ void onCreate() override;
+
+ StatusCode set(const VehiclePropValue& propValue) override;
+
+ StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
+
+ StatusCode unsubscribe(int32_t property) override;
+
+ /**
+ * Add custom property information to this HAL instance.
+ *
+ * This is useful for allowing later versions of Vehicle HAL to coalesce
+ * the list of properties they support with a previous version of the HAL.
+ *
+ * @param property The identifier of the new property
+ * @param handler The object that will handle get/set requests
+ * @return OK on success, an error code on failure
+ */
+ virtual StatusCode addCustomProperty(int32_t,
+ std::unique_ptr<CustomVehiclePropertyHandler>&&);
+
+ /**
+ * Add custom property information to this HAL instance.
+ *
+ * This is useful for allowing later versions of Vehicle HAL to coalesce
+ * the list of properties they support with a previous version of the HAL.
+ *
+ * @param initialValue The initial value for the new property. This is not
+ * constant data, as later set() operations can change
+ * this value at will
+ * @return OK on success, an error code on failure
+ */
+ virtual StatusCode addCustomProperty(
+ const VehiclePropValue& initialValue) {
+ std::unique_ptr<CustomVehiclePropertyHandler> handler;
+ handler.reset(new StoredValueCustomVehiclePropertyHandler());
+ StatusCode setResponse = handler->set(initialValue);
+ if (StatusCode::OK == setResponse) {
+ return addCustomProperty(initialValue.prop,
+ std::move(handler));
+ } else {
+ return setResponse;
+ }
+ }
+
+private:
+ void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+ void doGetConfigAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+ void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+ void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+ void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+ VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
+ const VehiclePropConfig* getPropConfig(int32_t propId) const;
+ bool isContinuousProperty(int32_t propId) const;
+ void parseRxProtoBuf(std::vector<uint8_t>& msg);
+ void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+ const VehiclePropConfig& cfg);
+ void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+ const VehiclePropValue* val);
+ void setDefaultValue(VehiclePropValue* prop);
+ void rxMsg();
+ void rxThread();
+ void txMsg(emulator::EmulatorMessage& txMsg);
+ StatusCode updateProperty(const VehiclePropValue& propValue);
+
+ constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
+ return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
+ }
+
+ void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
+
+private:
+ std::map<
+ std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
+ std::unique_ptr<CustomVehiclePropertyHandler>> mProps;
+ std::atomic<int> mExit;
+ std::unordered_set<int32_t> mHvacPowerProps;
+ std::mutex mPropsMutex;
+ std::thread mThread;
+ std::unique_ptr<CommBase> mComm{nullptr};
+ RecurrentTimer mRecurrentTimer;
+ std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
new file mode 100644
index 0000000..6f219fa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "PipeComm"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/log.h>
+#include <system/qemu_pipe.h>
+
+#include "PipeComm.h"
+
+#define CAR_SERVICE_NAME "pipe:qemud:car"
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+PipeComm::PipeComm() {
+ // Initialize member vars
+ mPipeFd = -1;
+}
+
+
+int PipeComm::open() {
+ int fd = qemu_pipe_open(CAR_SERVICE_NAME);
+
+ if (fd < 0) {
+ ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd);
+ return -errno;
+ }
+
+ ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd);
+ mPipeFd = fd;
+ return 0;
+}
+
+std::vector<uint8_t> PipeComm::read() {
+ static constexpr int MAX_RX_MSG_SZ = 2048;
+ std::vector<uint8_t> msg = std::vector<uint8_t>(MAX_RX_MSG_SZ);
+ int numBytes;
+
+ numBytes = qemu_pipe_frame_recv(mPipeFd, msg.data(), msg.size());
+
+ if (numBytes == MAX_RX_MSG_SZ) {
+ ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ);
+ } else if (numBytes > 0) {
+ msg.resize(numBytes);
+ return msg;
+ } else {
+ ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes);
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPipeFd = -1;
+ }
+ }
+
+ return std::vector<uint8_t>();
+}
+
+int PipeComm::write(const std::vector<uint8_t>& data) {
+ int retVal = 0;
+
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mPipeFd != -1) {
+ retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size());
+ }
+ }
+
+ if (retVal < 0) {
+ retVal = -errno;
+ ALOGE("%s: send_cmd: (fd=%d): ERROR: %s", __FUNCTION__, mPipeFd, strerror(errno));
+ }
+
+ return retVal;
+}
+
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
new file mode 100644
index 0000000..bcd32d0
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
+
+#include <mutex>
+#include <vector>
+#include "CommBase.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator.
+ */
+class PipeComm : public CommBase {
+public:
+ PipeComm();
+
+ /**
+ * Opens a pipe and begins listening.
+ *
+ * @return int Returns 0 on success.
+ */
+ int open() override;
+
+ /**
+ * Blocking call to read data from the connection.
+ *
+ * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be
+ * an empty vector if the connection was closed or some other error occurred.
+ */
+ std::vector<uint8_t> read() override;
+
+ /**
+ * Transmits a string of data to the emulator.
+ *
+ * @param data Serialized protobuf data to transmit.
+ *
+ * @return int Number of bytes transmitted, or -1 if failed.
+ */
+ int write(const std::vector<uint8_t>& data) override;
+
+private:
+ std::mutex mMutex;
+ int mPipeFd;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
new file mode 100644
index 0000000..a3ef4b1
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "SocketComm"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/log.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "SocketComm.h"
+
+// Socket to use when communicating with Host PC
+static constexpr int DEBUG_SOCKET = 33452;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+SocketComm::SocketComm() {
+ // Initialize member vars
+ mCurSockFd = -1;
+ mExit = 0;
+ mSockFd = -1;
+}
+
+
+SocketComm::~SocketComm() {
+ stop();
+}
+
+int SocketComm::connect() {
+ sockaddr_in cliAddr;
+ socklen_t cliLen = sizeof(cliAddr);
+ int cSockFd = accept(mSockFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
+
+ if (cSockFd >= 0) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCurSockFd = cSockFd;
+ }
+ ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd);
+ } else {
+ cSockFd = -1;
+ }
+
+ return cSockFd;
+}
+
+int SocketComm::open() {
+ int retVal;
+ struct sockaddr_in servAddr;
+
+ mSockFd = socket(AF_INET, SOCK_STREAM, 0);
+ if (mSockFd < 0) {
+ ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mSockFd, errno);
+ mSockFd = -1;
+ return -errno;
+ }
+
+ memset(&servAddr, 0, sizeof(servAddr));
+ servAddr.sin_family = AF_INET;
+ servAddr.sin_addr.s_addr = INADDR_ANY;
+ servAddr.sin_port = htons(DEBUG_SOCKET);
+
+ retVal = bind(mSockFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
+ if(retVal < 0) {
+ ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno);
+ close(mSockFd);
+ mSockFd = -1;
+ return -errno;
+ }
+
+ listen(mSockFd, 1);
+
+ // Set the socket to be non-blocking so we can poll it continouously
+ fcntl(mSockFd, F_SETFL, O_NONBLOCK);
+
+ return 0;
+}
+
+std::vector<uint8_t> SocketComm::read() {
+ int32_t msgSize;
+ int numBytes = 0;
+
+ // This is a variable length message.
+ // Read the number of bytes to rx over the socket
+ numBytes = ::read(mCurSockFd, &msgSize, sizeof(msgSize));
+ msgSize = ntohl(msgSize);
+
+ if (numBytes != sizeof(msgSize)) {
+ // This happens when connection is closed
+ ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes);
+ ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCurSockFd = -1;
+ }
+
+ return std::vector<uint8_t>();
+ }
+
+ std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
+
+ numBytes = ::read(mCurSockFd, msg.data(), msgSize);
+
+ if ((numBytes == msgSize) && (msgSize > 0)) {
+ // Received a message.
+ return msg;
+ } else {
+ // This happens when connection is closed
+ ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
+ ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCurSockFd = -1;
+ }
+
+ return std::vector<uint8_t>();
+ }
+}
+
+void SocketComm::stop() {
+ if (mExit == 0) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mExit = 1;
+
+ // Close emulator socket if it is open
+ if (mCurSockFd != -1) {
+ close(mCurSockFd);
+ mCurSockFd = -1;
+ }
+
+ if (mSockFd != -1) {
+ close(mSockFd);
+ mSockFd = -1;
+ }
+ }
+}
+
+int SocketComm::write(const std::vector<uint8_t>& data) {
+ static constexpr int MSG_HEADER_LEN = 4;
+ int retVal = 0;
+ union {
+ uint32_t msgLen;
+ uint8_t msgLenBytes[MSG_HEADER_LEN];
+ };
+
+ // Prepare header for the message
+ msgLen = static_cast<uint32_t>(data.size());
+ msgLen = htonl(msgLen);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCurSockFd != -1) {
+ retVal = ::write(mCurSockFd, msgLenBytes, MSG_HEADER_LEN);
+
+ if (retVal == MSG_HEADER_LEN) {
+ retVal = ::write(mCurSockFd, data.data(), data.size());
+ }
+ }
+
+ return retVal;
+}
+
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
new file mode 100644
index 0000000..12cfb29
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
+
+#include <mutex>
+#include <vector>
+#include "CommBase.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * SocketComm opens a socket via adb's TCP port forwarding to enable a Host PC to connect to
+ * the VehicleHAL.
+ */
+class SocketComm : public CommBase {
+public:
+ SocketComm();
+ virtual ~SocketComm();
+
+ /**
+ * Creates a connection to the other side.
+ *
+ * @return int Returns fd or socket number if connection is successful.
+ * Otherwise, returns -1 if no connection is availble.
+ */
+ int connect() override;
+
+ /**
+ * Opens a socket and begins listening.
+ *
+ * @return int Returns 0 on success.
+ */
+ int open() override;
+
+ /**
+ * Blocking call to read data from the connection.
+ *
+ * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be
+ * an empty vector if the connection was closed or some other error occurred.
+ */
+ std::vector<uint8_t> read() override;
+
+ /**
+ * Closes a connection if it is open.
+ */
+ void stop() override;
+
+ /**
+ * Transmits a string of data to the emulator.
+ *
+ * @param data Serialized protobuf data to transmit.
+ *
+ * @return int Number of bytes transmitted, or -1 if failed.
+ */
+ int write(const std::vector<uint8_t>& data) override;
+
+private:
+ int mCurSockFd;
+ std::atomic<int> mExit;
+ std::mutex mMutex;
+ int mSockFd;
+};
+
+} // impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
new file mode 100644
index 0000000..86433f5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package emulator;
+
+// CMD messages are from workstation --> VHAL
+// RESP messages are from VHAL --> workstation
+enum MsgType {
+ GET_CONFIG_CMD = 0;
+ GET_CONFIG_RESP = 1;
+ GET_CONFIG_ALL_CMD = 2;
+ GET_CONFIG_ALL_RESP = 3;
+ GET_PROPERTY_CMD = 4;
+ GET_PROPERTY_RESP = 5;
+ GET_PROPERTY_ALL_CMD = 6;
+ GET_PROPERTY_ALL_RESP = 7;
+ SET_PROPERTY_CMD = 8;
+ SET_PROPERTY_RESP = 9;
+ SET_PROPERTY_ASYNC = 10;
+}
+enum Status {
+ RESULT_OK = 0;
+ ERROR_UNKNOWN = 1;
+ ERROR_UNIMPLEMENTED_CMD = 2;
+ ERROR_INVALID_PROPERTY = 3;
+ ERROR_INVALID_AREA_ID = 4;
+ ERROR_PROPERTY_UNINITIALIZED = 5;
+ ERROR_WRITE_ONLY_PROPERTY = 6;
+ ERROR_MEMORY_ALLOC_FAILED = 7;
+ ERROR_INVALID_OPERATION = 8;
+}
+
+message VehicleAreaConfig {
+ required int32 area_id = 1;
+ optional sint32 min_int32_value = 2;
+ optional sint32 max_int32_value = 3;
+ optional sint64 min_int64_value = 4;
+ optional sint64 max_int64_value = 5;
+ optional float min_float_value = 6;
+ optional float max_float_value = 7;
+}
+
+message VehiclePropConfig {
+ required int32 prop = 1;
+ optional int32 access = 2;
+ optional int32 change_mode = 3;
+ optional int32 value_type = 4;
+ optional int32 supported_areas = 5;
+ repeated VehicleAreaConfig area_configs = 6;
+ optional int32 config_flags = 7;
+ repeated int32 config_array = 8;
+ optional string config_string = 9;
+ optional float min_sample_rate = 10;
+ optional float max_sample_rate = 11;
+};
+
+message VehiclePropValue {
+ // common data
+ required int32 prop = 1;
+ optional int32 value_type = 2;
+ optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
+
+ // values
+ optional int32 area_id = 4;
+ repeated sint32 int32_values = 5; // this also covers boolean value.
+ repeated sint64 int64_values = 6;
+ repeated float float_values = 7;
+ optional string string_value = 8;
+ optional bytes bytes_value = 9;
+};
+
+// This structure is used to notify what values to get from the Vehicle HAL
+message VehiclePropGet {
+ required int32 prop = 1;
+ optional int32 area_id = 2;
+};
+
+message EmulatorMessage {
+ required MsgType msg_type = 1;
+ optional Status status = 2; // Only for RESP messages
+ repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
+ repeated VehiclePropConfig config = 4;
+ repeated VehiclePropValue value = 5;
+};
diff --git a/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
new file mode 100644
index 0000000..d9611c0
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <fstream>
+#include <unordered_set>
+
+#include "vhal_v2_0/AccessControlConfigParser.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class AccessControlConfigParserTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ std::vector<int32_t> supportedProperties {
+ toInt(VehicleProperty::HVAC_FAN_SPEED),
+ toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+ };
+ parser.reset(new AccessControlConfigParser(supportedProperties));
+ }
+public:
+ PropertyAclMap aclMap;
+ std::unique_ptr<AccessControlConfigParser> parser;
+};
+
+TEST_F(AccessControlConfigParserTest, basicParsing) {
+ std::stringstream file;
+ file << "S:0x0500 1000 RW" << std::endl;
+
+ ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+ ASSERT_EQ(1u, aclMap.size());
+ auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+ ASSERT_NE(aclMap.end(), it);
+ ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+ ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+ ASSERT_EQ(1000u, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, multipleUids) {
+ std::stringstream file;
+ file << "Set AID_AUDIO 1004" << std::endl
+ << "Set AID_SYSTEM 1000" << std::endl
+ << "S:0x0500 AID_SYSTEM RW" << std::endl
+ << "S:0x0500 AID_AUDIO RW" << std::endl
+ << "S:0x0500 0xbeef R" << std::endl; // Read-only.
+
+ std::unordered_set<unsigned> expectedUids {1000, 1004, 0xbeef};
+
+ ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+ auto range = aclMap.equal_range(toInt(VehicleProperty::HVAC_FAN_SPEED));
+ for (auto it = range.first; it != range.second; ++it) {
+ auto& acl = it->second;
+
+ ASSERT_EQ(1u, expectedUids.count(acl.uid))
+ << " uid: " << std::hex << acl.uid;
+
+ if (acl.uid == 0xbeef) {
+ ASSERT_EQ(VehiclePropertyAccess::READ, acl.access);
+ } else {
+ ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, acl.access);
+ }
+ }
+}
+
+TEST_F(AccessControlConfigParserTest, fileContainsJunk) {
+ std::stringstream file;
+ file << "This string will be ignored with warning in the log" << std::endl
+ << "# However comments are quit legitimate" << std::endl
+ << "S:0x0500 0xbeef R # YAY" << std::endl;
+
+ ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+
+ ASSERT_EQ(1u, aclMap.size());
+ auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+ ASSERT_NE(aclMap.end(), it);
+ ASSERT_EQ(VehiclePropertyAccess::READ, it->second.access);
+ ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+ ASSERT_EQ(0xBEEFu, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, badIntegerFormat) {
+ std::stringstream file;
+ file << "S:0x0500 A12 RW " << std::endl;
+
+ ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+ ASSERT_EQ(0u, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, ignoreNotSupportedProperties) {
+ std::stringstream file;
+ file << "S:0x0666 1000 RW " << std::endl;
+
+ ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+ ASSERT_EQ(0u, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, multipleCalls) {
+ std::stringstream configFile;
+ configFile << "S:0x0500 1000 RW" << std::endl;
+
+ ASSERT_TRUE(parser->parseFromStream(&configFile, &aclMap));
+ ASSERT_EQ(1u, aclMap.size());
+
+ std::stringstream configFile2;
+ configFile2 << "S:0x0501 1004 RW" << std::endl;
+ ASSERT_TRUE(parser->parseFromStream(&configFile2, &aclMap));
+ ASSERT_EQ(2u, aclMap.size());
+
+ auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+ ASSERT_NE(aclMap.end(), it);
+ ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+ ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+ ASSERT_EQ(1000u, it->second.uid);
+
+ it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_DIRECTION));
+ ASSERT_NE(aclMap.end(), it);
+ ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+ ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_DIRECTION), it->second.propId);
+ ASSERT_EQ(1004u, it->second.uid);
+}
+
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
new file mode 100644
index 0000000..9fc17c6
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/RecurrentTimer.h"
+
+namespace {
+
+using std::chrono::nanoseconds;
+using std::chrono::milliseconds;
+
+#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
+ASSERT_LE(val1 - tolerance, val2); \
+ASSERT_GE(val1 + tolerance, val2); \
+
+
+TEST(RecurrentTimerTest, oneInterval) {
+ std::atomic<int64_t> counter { 0L };
+ auto counterRef = std::ref(counter);
+ RecurrentTimer timer([&counterRef](const std::vector<int32_t>& cookies) {
+ ASSERT_EQ(1u, cookies.size());
+ ASSERT_EQ(0xdead, cookies.front());
+ counterRef.get()++;
+ });
+
+ timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+ std::this_thread::sleep_for(milliseconds(100));
+ ASSERT_EQ_WITH_TOLERANCE(100, counter.load(), 20);
+}
+
+TEST(RecurrentTimerTest, multipleIntervals) {
+ std::atomic<int64_t> counter1ms { 0L };
+ std::atomic<int64_t> counter5ms { 0L };
+ auto counter1msRef = std::ref(counter1ms);
+ auto counter5msRef = std::ref(counter5ms);
+ RecurrentTimer timer(
+ [&counter1msRef, &counter5msRef](const std::vector<int32_t>& cookies) {
+ for (int32_t cookie : cookies) {
+ if (cookie == 0xdead) {
+ counter1msRef.get()++;
+ } else if (cookie == 0xbeef) {
+ counter5msRef.get()++;
+ } else {
+ FAIL();
+ }
+ }
+ });
+
+ timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+ timer.registerRecurrentEvent(milliseconds(5), 0xbeef);
+
+ std::this_thread::sleep_for(milliseconds(100));
+ ASSERT_EQ_WITH_TOLERANCE(100, counter1ms.load(), 20);
+ ASSERT_EQ_WITH_TOLERANCE(20, counter5ms.load(), 5);
+}
+
+} // anonymous namespace
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
new file mode 100644
index 0000000..7ec9b79
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <functional>
+#include <iostream>
+#include <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/SubscriptionManager.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+using namespace std::placeholders;
+
+class SubscriptionManagerTest : public ::testing::Test {
+public:
+ SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {}
+
+ SubscriptionManager manager;
+ static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED);
+ static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+ sp<IVehicleCallback> cb1 = new MockedVehicleCallback();
+ sp<IVehicleCallback> cb2 = new MockedVehicleCallback();
+ sp<IVehicleCallback> cb3 = new MockedVehicleCallback();
+
+ void SetUp() override {
+ lastUnsubscribedProperty = -1;
+ }
+
+ hidl_vec<SubscribeOptions> subscrToProp1 = {
+ SubscribeOptions {
+ .propId = PROP1,
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ };
+
+ hidl_vec<SubscribeOptions> subscrToProp2 = {
+ SubscribeOptions {
+ .propId = PROP2,
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ };
+
+ hidl_vec<SubscribeOptions> subscrToProp1and2 = {
+ SubscribeOptions {
+ .propId = PROP1,
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ SubscribeOptions {
+ .propId = PROP2,
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ };
+
+ static std::list<sp<IVehicleCallback>> extractCallbacks(
+ const std::list<sp<HalClient>>& clients) {
+ std::list<sp<IVehicleCallback>> callbacks;
+ for (auto c : clients) {
+ callbacks.push_back(c->getCallback());
+ }
+ return callbacks;
+ }
+
+ std::list<sp<HalClient>> clientsToProp1() {
+ return manager.getSubscribedClients(PROP1,
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::DEFAULT);
+ }
+
+ std::list<sp<HalClient>> clientsToProp2() {
+ return manager.getSubscribedClients(PROP2, 0,
+ SubscribeFlags::DEFAULT);
+ }
+
+ void onPropertyUnsubscribed(int propertyId) {
+ // Called when there are no clients who subscribed to particular property. This can happen
+ // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected.
+ lastUnsubscribedProperty = propertyId;
+ }
+
+ void assertOnPropertyUnsubscribedNotCalled() {
+ ASSERT_EQ(-1, lastUnsubscribedProperty);
+ }
+
+ void assertLastUnsubscribedProperty(int expectedPropertyId) {
+ ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty);
+ lastUnsubscribedProperty = -1;
+ }
+
+private:
+ int lastUnsubscribedProperty;
+};
+
+
+TEST_F(SubscriptionManagerTest, multipleClients) {
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp1, &updatedOptions));
+
+ auto clients = manager.getSubscribedClients(
+ PROP1,
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::HAL_EVENT);
+
+ ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
+}
+
+TEST_F(SubscriptionManagerTest, negativeCases) {
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+
+ // Wrong zone
+ auto clients = manager.getSubscribedClients(
+ PROP1,
+ toInt(VehicleAreaZone::ROW_2_LEFT),
+ SubscribeFlags::HAL_EVENT);
+ ASSERT_TRUE(clients.empty());
+
+ // Wrong prop
+ clients = manager.getSubscribedClients(
+ toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::HAL_EVENT);
+ ASSERT_TRUE(clients.empty());
+
+ // Wrong flag
+ clients = manager.getSubscribedClients(
+ PROP1,
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::SET_CALL);
+ ASSERT_TRUE(clients.empty());
+}
+
+TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+
+ auto clients = manager.getSubscribedClients(
+ PROP1,
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::DEFAULT);
+ ASSERT_EQ((size_t) 1, clients.size());
+ ASSERT_EQ(cb1, clients.front()->getCallback());
+
+ // Same property, but different zone, to make sure we didn't unsubscribe
+ // from previous zone.
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, {
+ SubscribeOptions {
+ .propId = PROP1,
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
+ .flags = SubscribeFlags::DEFAULT
+ }
+ }, &updatedOptions));
+
+ clients = manager.getSubscribedClients(PROP1,
+ toInt(VehicleAreaZone::ROW_1_LEFT),
+ SubscribeFlags::DEFAULT);
+ ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
+
+ clients = manager.getSubscribedClients(PROP1,
+ toInt(VehicleAreaZone::ROW_2),
+ SubscribeFlags::DEFAULT);
+ ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
+}
+
+TEST_F(SubscriptionManagerTest, unsubscribe) {
+ std::list<SubscribeOptions> updatedOptions;
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp2, &updatedOptions));
+ ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb3, subscrToProp1and2,
+ &updatedOptions));
+
+ ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1()));
+ ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+ manager.unsubscribe(cb1, PROP1);
+ assertOnPropertyUnsubscribedNotCalled();
+ ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
+
+ // Make sure nothing changed in PROP2 so far.
+ ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+ // No one subscribed to PROP1, subscription for PROP2 is not affected.
+ manager.unsubscribe(cb3, PROP1);
+ assertLastUnsubscribedProperty(PROP1);
+ ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+ manager.unsubscribe(cb3, PROP2);
+ assertOnPropertyUnsubscribedNotCalled();
+ ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
+
+ // The last client unsubscribed from this property.
+ manager.unsubscribe(cb2, PROP2);
+ assertLastUnsubscribedProperty(PROP2);
+
+ // No one subscribed anymore
+ manager.unsubscribe(cb1, PROP1);
+ assertLastUnsubscribedProperty(PROP1);
+}
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
new file mode 100644
index 0000000..b5cdf5c
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <unordered_map>
+#include <iostream>
+
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/VehicleHalManager.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+using namespace std::placeholders;
+
+constexpr char kCarMake[] = "Default Car";
+constexpr int kRetriablePropMockedAttempts = 3;
+
+class MockedVehicleHal : public VehicleHal {
+public:
+ MockedVehicleHal() {
+ mConfigs.assign(std::begin(kVehicleProperties),
+ std::end(kVehicleProperties));
+ }
+
+ std::vector<VehiclePropConfig> listProperties() override {
+ return mConfigs;
+ }
+
+ VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+ StatusCode* outStatus) override {
+ *outStatus = StatusCode::OK;
+ VehiclePropValuePtr pValue;
+ auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
+ int32_t areaId = requestedPropValue.areaId;
+
+ switch (property) {
+ case VehicleProperty::INFO_MAKE:
+ pValue = getValuePool()->obtainString(kCarMake);
+ break;
+ case VehicleProperty::INFO_FUEL_CAPACITY:
+ if (fuelCapacityAttemptsLeft-- > 0) {
+ // Emulate property not ready yet.
+ *outStatus = StatusCode::TRY_AGAIN;
+ } else {
+ pValue = getValuePool()->obtainFloat(42.42);
+ }
+ break;
+ default:
+ if (requestedPropValue.prop == kCustomComplexProperty) {
+ pValue = getValuePool()->obtainComplex();
+ pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
+ pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
+ pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
+ pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
+ pValue->value.stringValue = kCarMake;
+ break;
+ }
+ auto key = makeKey(toInt(property), areaId);
+ if (mValues.count(key) == 0) {
+ ALOGW("");
+ }
+ pValue = getValuePool()->obtain(mValues[key]);
+ }
+
+ if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
+ pValue->prop = toInt(property);
+ pValue->areaId = areaId;
+ pValue->timestamp = elapsedRealtimeNano();
+ }
+
+ return pValue;
+ }
+
+ StatusCode set(const VehiclePropValue& propValue) override {
+ if (toInt(VehicleProperty::MIRROR_FOLD) == propValue.prop
+ && mirrorFoldAttemptsLeft-- > 0) {
+ return StatusCode::TRY_AGAIN;
+ }
+
+ mValues[makeKey(propValue)] = propValue;
+ return StatusCode::OK;
+ }
+
+ StatusCode subscribe(int32_t /* property */,
+ int32_t /* areas */,
+ float /* sampleRate */) override {
+ return StatusCode::OK;
+ }
+
+ StatusCode unsubscribe(int32_t /* property */) override {
+ return StatusCode::OK;
+ }
+
+ void sendPropEvent(recyclable_ptr<VehiclePropValue> value) {
+ doHalEvent(std::move(value));
+ }
+
+ void sendHalError(StatusCode error, int32_t property, int32_t areaId) {
+ doHalPropertySetError(error, property, areaId);
+ }
+
+public:
+ int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts;
+ int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts;
+
+private:
+ int64_t makeKey(const VehiclePropValue& v) const {
+ return makeKey(v.prop, v.areaId);
+ }
+
+ int64_t makeKey(int32_t prop, int32_t area) const {
+ return (static_cast<int64_t>(prop) << 32) | area;
+ }
+
+private:
+ std::vector<VehiclePropConfig> mConfigs;
+ std::unordered_map<int64_t, VehiclePropValue> mValues;
+};
+
+class VehicleHalManagerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ hal.reset(new MockedVehicleHal);
+ manager.reset(new VehicleHalManager(hal.get()));
+
+ objectPool = hal->getValuePool();
+ }
+
+ void TearDown() override {
+ manager.reset(nullptr);
+ hal.reset(nullptr);
+ }
+public:
+ void invokeGet(int32_t property, int32_t areaId) {
+ VehiclePropValue requestedValue {};
+ requestedValue.prop = property;
+ requestedValue.areaId = areaId;
+
+ invokeGet(requestedValue);
+ }
+
+ void invokeGet(const VehiclePropValue& requestedPropValue) {
+ actualValue = VehiclePropValue {}; // reset previous values
+
+ StatusCode refStatus;
+ VehiclePropValue refValue;
+ bool called = false;
+ manager->get(requestedPropValue, [&refStatus, &refValue, &called]
+ (StatusCode status, const VehiclePropValue& value) {
+ refStatus = status;
+ refValue = value;
+ called = true;
+ });
+ ASSERT_TRUE(called) << "callback wasn't called for prop: "
+ << hexString(requestedPropValue.prop);
+
+ actualValue = refValue;
+ actualStatusCode = refStatus;
+ }
+
+public:
+ VehiclePropValue actualValue;
+ StatusCode actualStatusCode;
+
+ VehiclePropValuePool* objectPool;
+ std::unique_ptr<MockedVehicleHal> hal;
+ std::unique_ptr<VehicleHalManager> manager;
+};
+
+TEST_F(VehicleHalManagerTest, getPropConfigs) {
+ hidl_vec<int32_t> properties =
+ { toInt(VehicleProperty::HVAC_FAN_SPEED),
+ toInt(VehicleProperty::INFO_MAKE) };
+ bool called = false;
+
+ manager->getPropConfigs(properties,
+ [&called] (StatusCode status,
+ const hidl_vec<VehiclePropConfig>& c) {
+ ASSERT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(2u, c.size());
+ called = true;
+ });
+
+ ASSERT_TRUE(called); // Verify callback received.
+
+ called = false;
+ manager->getPropConfigs({ toInt(VehicleProperty::HVAC_FAN_SPEED) },
+ [&called] (StatusCode status,
+ const hidl_vec<VehiclePropConfig>& c) {
+ ASSERT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(1u, c.size());
+ ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0]));
+ called = true;
+ });
+ ASSERT_TRUE(called); // Verify callback received.
+
+ // TODO(pavelm): add case case when property was not declared.
+}
+
+TEST_F(VehicleHalManagerTest, getAllPropConfigs) {
+ bool called = false;
+ manager->getAllPropConfigs(
+ [&called] (const hidl_vec<VehiclePropConfig>& propConfigs) {
+ ASSERT_EQ(arraysize(kVehicleProperties), propConfigs.size());
+
+ for (size_t i = 0; i < propConfigs.size(); i++) {
+ ASSERT_EQ(toString(kVehicleProperties[i]),
+ toString(propConfigs[i]));
+ }
+ called = true;
+ });
+ ASSERT_TRUE(called); // Verify callback received.
+}
+
+TEST_F(VehicleHalManagerTest, halErrorEvent) {
+ const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+ sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+ hidl_vec<SubscribeOptions> options = {
+ SubscribeOptions {
+ .propId = PROP,
+ .flags = SubscribeFlags::DEFAULT
+ },
+ };
+
+ StatusCode res = manager->subscribe(cb, options);
+ ASSERT_EQ(StatusCode::OK, res);
+
+ hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
+}
+
+TEST_F(VehicleHalManagerTest, subscribe) {
+ const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+ sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+ hidl_vec<SubscribeOptions> options = {
+ SubscribeOptions {
+ .propId = PROP,
+ .flags = SubscribeFlags::DEFAULT
+ }
+ };
+
+ StatusCode res = manager->subscribe(cb, options);
+ ASSERT_EQ(StatusCode::OK, res);
+
+ auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
+ unsubscribedValue->prop = toInt(VehicleProperty::HVAC_FAN_SPEED);
+
+ hal->sendPropEvent(std::move(unsubscribedValue));
+ auto& receivedEnvents = cb->getReceivedEvents();
+
+ ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
+ << receivedEnvents.size()
+ << (receivedEnvents.size() > 0
+ ? toString(receivedEnvents.front()[0]) : "");
+
+ auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
+ subscribedValue->prop = PROP;
+ subscribedValue->value.int32Values[0] = 42;
+
+ cb->reset();
+ VehiclePropValue actualValue(*subscribedValue.get());
+ hal->sendPropEvent(std::move(subscribedValue));
+
+ ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
+ << receivedEnvents.size();
+
+ ASSERT_EQ(toString(actualValue),
+ toString(cb->getReceivedEvents().front()[0]));
+}
+
+TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
+ const auto PROP = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE);
+
+ sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+ hidl_vec<SubscribeOptions> options = {
+ SubscribeOptions {
+ .propId = PROP,
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ };
+
+ StatusCode res = manager->subscribe(cb, options);
+ // Unable to subscribe on Hal Events for write-only properties.
+ ASSERT_EQ(StatusCode::INVALID_ARG, res);
+
+
+ options[0].flags = SubscribeFlags::SET_CALL;
+
+ res = manager->subscribe(cb, options);
+ // OK to subscribe on SET method call for write-only properties.
+ ASSERT_EQ(StatusCode::OK, res);
+}
+
+TEST_F(VehicleHalManagerTest, get_Complex) {
+ invokeGet(kCustomComplexProperty, 0);
+
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(kCustomComplexProperty, actualValue.prop);
+
+ ASSERT_EQ(3u, actualValue.value.bytes.size());
+ ASSERT_EQ(1, actualValue.value.bytes[0]);
+ ASSERT_EQ(2, actualValue.value.bytes[1]);
+ ASSERT_EQ(3, actualValue.value.bytes[2]);
+
+ ASSERT_EQ(2u, actualValue.value.int32Values.size());
+ ASSERT_EQ(10, actualValue.value.int32Values[0]);
+ ASSERT_EQ(20, actualValue.value.int32Values[1]);
+
+ ASSERT_EQ(2u, actualValue.value.floatValues.size());
+ ASSERT_FLOAT_EQ(1.1, actualValue.value.floatValues[0]);
+ ASSERT_FLOAT_EQ(2.2, actualValue.value.floatValues[1]);
+
+ ASSERT_EQ(2u, actualValue.value.int64Values.size());
+ ASSERT_FLOAT_EQ(30, actualValue.value.int64Values[0]);
+ ASSERT_FLOAT_EQ(40, actualValue.value.int64Values[1]);
+
+ ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
+}
+
+TEST_F(VehicleHalManagerTest, get_StaticString) {
+ invokeGet(toInt(VehicleProperty::INFO_MAKE), 0);
+
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(toInt(VehicleProperty::INFO_MAKE), actualValue.prop);
+ ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
+}
+
+TEST_F(VehicleHalManagerTest, get_NegativeCases) {
+ // Write-only property must fail.
+ invokeGet(toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), 0);
+ ASSERT_EQ(StatusCode::ACCESS_DENIED, actualStatusCode);
+
+ // Unknown property must fail.
+ invokeGet(toInt(VehicleProperty::MIRROR_Z_MOVE), 0);
+ ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
+}
+
+TEST_F(VehicleHalManagerTest, get_Retriable) {
+ actualStatusCode = StatusCode::TRY_AGAIN;
+ int attempts = 0;
+ while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+ invokeGet(toInt(VehicleProperty::INFO_FUEL_CAPACITY), 0);
+
+ }
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+ ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_Basic) {
+ const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+ const auto VAL = 7;
+
+ auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
+ expectedValue->prop = PROP;
+ expectedValue->areaId = 0;
+
+ actualStatusCode = manager->set(*expectedValue.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+ invokeGet(PROP, 0);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
+ const auto PROP = toInt(VehicleProperty::HVAC_FAN_SPEED);
+ const auto VAL1 = 1;
+ const auto VAL2 = 2;
+ const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
+ const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
+
+ {
+ auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
+ expectedValue1->prop = PROP;
+ expectedValue1->areaId = AREA1;
+ actualStatusCode = manager->set(*expectedValue1.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+ auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
+ expectedValue2->prop = PROP;
+ expectedValue2->areaId = AREA2;
+ actualStatusCode = manager->set(*expectedValue2.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ }
+
+ {
+ invokeGet(PROP, AREA1);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(AREA1, actualValue.areaId);
+ ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
+
+ invokeGet(PROP, AREA2);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(AREA2, actualValue.areaId);
+ ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
+ }
+}
+
+TEST_F(VehicleHalManagerTest, set_Retriable) {
+ const auto PROP = toInt(VehicleProperty::MIRROR_FOLD);
+
+ auto v = hal->getValuePool()->obtainBoolean(true);
+ v->prop = PROP;
+ v->areaId = 0;
+
+ actualStatusCode = StatusCode::TRY_AGAIN;
+ int attempts = 0;
+ while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+ actualStatusCode = manager->set(*v.get());
+ }
+
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+
+ invokeGet(PROP, 0);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_TRUE(actualValue.value.int32Values[0]);
+}
+
+TEST(HalClientVectorTest, basic) {
+ HalClientVector clients;
+ sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
+
+ sp<HalClient> c1 = new HalClient(callback1, 10, 20);
+ sp<HalClient> c2 = new HalClient(callback1, 10, 20);
+
+ clients.addOrUpdate(c1);
+ clients.addOrUpdate(c1);
+ clients.addOrUpdate(c2);
+ ASSERT_EQ(2u, clients.size());
+ ASSERT_FALSE(clients.isEmpty());
+ ASSERT_LE(0, clients.indexOf(c1));
+ ASSERT_LE(0, clients.remove(c1));
+ ASSERT_GT(0, clients.indexOf(c1)); // c1 was already removed
+ ASSERT_GT(0, clients.remove(c1)); // attempt to remove c1 again
+ ASSERT_LE(0, clients.remove(c2));
+
+ ASSERT_TRUE(clients.isEmpty());
+}
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
new file mode 100644
index 0000000..28e1a5a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+#include <ios>
+#include <sstream>
+
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+constexpr int32_t kCustomComplexProperty = 0xbeef
+ | VehiclePropertyGroup::VENDOR
+ | VehiclePropertyType::COMPLEX
+ | VehicleArea::GLOBAL;
+
+const VehiclePropConfig kVehicleProperties[] = {
+ {
+ .prop = toInt(VehicleProperty::INFO_MAKE),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ .configString = "Some=config,options=if,you=have_any",
+ },
+
+ {
+ .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .supportedAreas = static_cast<int32_t>(
+ VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minInt32Value = 1,
+ .maxInt32Value = 7},
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minInt32Value = 1,
+ .maxInt32Value = 5,
+ }
+ }
+ },
+
+ // Write-only property
+ {
+ .prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_SET,
+ .supportedAreas = static_cast<int32_t>(
+ VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minInt32Value = 64,
+ .maxInt32Value = 80},
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minInt32Value = 64,
+ .maxInt32Value = 80,
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .minFloatValue = 0,
+ .maxFloatValue = 1.0
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {
+ VehicleAreaConfig {
+ .minInt32Value = 0,
+ .maxInt32Value = 10
+ }
+ }
+ },
+
+ {
+ .prop = toInt(VehicleProperty::MIRROR_FOLD),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+
+ },
+
+ // Complex data type.
+ {
+ .prop = kCustomComplexProperty,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE
+ }
+};
+
+constexpr auto kTimeout = std::chrono::milliseconds(500);
+
+class MockedVehicleCallback : public IVehicleCallback {
+private:
+ using MuxGuard = std::lock_guard<std::mutex>;
+ using HidlVecOfValues = hidl_vec<VehiclePropValue>;
+public:
+ // Methods from ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback follow.
+ Return<void> onPropertyEvent(
+ const hidl_vec<VehiclePropValue>& values) override {
+ {
+ MuxGuard g(mLock);
+ mReceivedEvents.push_back(values);
+ }
+ mEventCond.notify_one();
+ return Return<void>();
+ }
+ Return<void> onPropertySet(const VehiclePropValue& /* value */) override {
+ return Return<void>();
+ }
+ Return<void> onPropertySetError(StatusCode /* errorCode */,
+ int32_t /* propId */,
+ int32_t /* areaId */) override {
+ return Return<void>();
+ }
+
+ bool waitForExpectedEvents(size_t expectedEvents) {
+ std::unique_lock<std::mutex> g(mLock);
+
+ if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
+ // No events expected, let's sleep a little bit to make sure
+ // nothing will show up.
+ return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
+ }
+
+ while (expectedEvents != mReceivedEvents.size()) {
+ if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void reset() {
+ mReceivedEvents.clear();
+ }
+
+ const std::vector<HidlVecOfValues>& getReceivedEvents() {
+ return mReceivedEvents;
+ }
+
+private:
+ std::mutex mLock;
+ std::condition_variable mEventCond;
+ std::vector<HidlVecOfValues> mReceivedEvents;
+};
+
+template<typename T>
+inline std::string hexString(T value) {
+ std::stringstream ss;
+ ss << std::showbase << std::hex << value;
+ return ss.str();
+}
+
+template <typename T, typename Collection>
+inline void assertAllExistsAnyOrder(
+ std::initializer_list<T> expected,
+ const Collection& actual,
+ const char* msg) {
+ std::set<T> expectedSet = expected;
+
+ for (auto a: actual) {
+ ASSERT_EQ(1u, expectedSet.erase(a))
+ << msg << "\nContains not unexpected value.\n";
+ }
+
+ ASSERT_EQ(0u, expectedSet.size())
+ << msg
+ << "\nDoesn't contain expected value.";
+}
+
+#define ASSERT_ALL_EXISTS(...) \
+ assertAllExistsAnyOrder(__VA_ARGS__, (std::string("Called from: ") + \
+ std::string(__FILE__) + std::string(":") + \
+ std::to_string(__LINE__)).c_str()); \
+
+template<typename T>
+inline std::string enumToHexString(T value) {
+ return hexString(toInt(value));
+}
+
+template <typename T>
+inline std::string vecToString(const hidl_vec<T>& vec) {
+ std::stringstream ss("[");
+ for (size_t i = 0; i < vec.size(); i++) {
+ if (i != 0) ss << ",";
+ ss << vec[i];
+ }
+ ss << "]";
+ return ss.str();
+}
+
+inline std::string toString(const VehiclePropValue &v) {
+ std::stringstream ss;
+ ss << "VehiclePropValue {n"
+ << " prop: " << hexString(v.prop) << ",\n"
+ << " areaId: " << hexString(v.areaId) << ",\n"
+ << " timestamp: " << v.timestamp << ",\n"
+ << " value {\n"
+ << " int32Values: " << vecToString(v.value.int32Values) << ",\n"
+ << " floatValues: " << vecToString(v.value.floatValues) << ",\n"
+ << " int64Values: " << vecToString(v.value.int64Values) << ",\n"
+ << " bytes: " << vecToString(v.value.bytes) << ",\n"
+ << " string: " << v.value.stringValue.c_str() << ",\n"
+ << " }\n"
+ << "}\n";
+
+ return ss.str();
+}
+
+inline std::string toString(const VehiclePropConfig &config) {
+ std::stringstream ss;
+ ss << "VehiclePropConfig {\n"
+ << " prop: " << hexString(config.prop) << ",\n"
+ << " supportedAreas: " << hexString(config.supportedAreas) << ",\n"
+ << " access: " << enumToHexString(config.access) << ",\n"
+ << " changeMode: " << enumToHexString(config.changeMode) << ",\n"
+ << " configFlags: " << hexString(config.configFlags) << ",\n"
+ << " minSampleRate: " << config.minSampleRate << ",\n"
+ << " maxSampleRate: " << config.maxSampleRate << ",\n"
+ << " configString: " << config.configString.c_str() << ",\n";
+
+ ss << " areaConfigs {\n";
+ for (size_t i = 0; i < config.areaConfigs.size(); i++) {
+ const auto &area = config.areaConfigs[i];
+ ss << " areaId: " << hexString(area.areaId) << ",\n"
+ << " minFloatValue: " << area.minFloatValue << ",\n"
+ << " minFloatValue: " << area.maxFloatValue << ",\n"
+ << " minInt32Value: " << area.minInt32Value << ",\n"
+ << " minInt32Value: " << area.maxInt32Value << ",\n"
+ << " minInt64Value: " << area.minInt64Value << ",\n"
+ << " minInt64Value: " << area.maxInt64Value << ",\n";
+ }
+ ss << " }\n"
+ << "}\n";
+
+ return ss.str();
+}
+
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif //android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
diff --git a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
new file mode 100644
index 0000000..a291351
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vhal_v2_0/VehicleObjectPool.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class VehicleObjectPoolTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ stats = PoolStats::instance();
+ resetStats();
+ valuePool.reset(new VehiclePropValuePool);
+ }
+
+ void TearDown() override {
+ // At the end, all created objects should be either recycled or deleted.
+ // Some objects could be recycled multiple times, that's why it's <=
+ ASSERT_EQ(stats->Obtained, stats->Recycled);
+ ASSERT_LE(stats->Created, stats->Recycled);
+ }
+private:
+ void resetStats() {
+ stats->Obtained = 0;
+ stats->Created = 0;
+ stats->Recycled = 0;
+ }
+
+public:
+ PoolStats* stats;
+ std::unique_ptr<VehiclePropValuePool> valuePool;
+};
+
+TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) {
+ void* raw = valuePool->obtain(VehiclePropertyType::INT32).get();
+ // At this point, v1 should be recycled and the only object in the pool.
+ ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get());
+ // Obtaining value of another type - should return a new object
+ ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get());
+
+ ASSERT_EQ(3u, stats->Obtained);
+ ASSERT_EQ(2u, stats->Created);
+}
+
+TEST_F(VehicleObjectPoolTest, valuePoolStrings) {
+ valuePool->obtain(VehiclePropertyType::STRING);
+ auto vs = valuePool->obtain(VehiclePropertyType::STRING);
+ vs->value.stringValue = "Hello";
+ void* raw = vs.get();
+ vs.reset(); // delete the pointer
+
+ auto vs2 = valuePool->obtain(VehiclePropertyType::STRING);
+ ASSERT_EQ(0u, vs2->value.stringValue.size());
+ ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::STRING).get());
+
+ ASSERT_EQ(0u, stats->Obtained);
+}
+
+TEST_F(VehicleObjectPoolTest, valuePoolMultithreadedBenchmark) {
+ // In this test we have T threads that concurrently in C cycles
+ // obtain and release O VehiclePropValue objects of FLOAT / INT32 types.
+
+ const int T = 2;
+ const int C = 500;
+ const int O = 100;
+
+ auto poolPtr = valuePool.get();
+
+ std::vector<std::thread> threads;
+ auto start = elapsedRealtimeNano();
+ for (int i = 0; i < T; i++) {
+ threads.push_back(std::thread([&poolPtr] () {
+ for (int j = 0; j < C; j++) {
+ std::vector<recyclable_ptr<VehiclePropValue>> vec;
+ for (int k = 0; k < O; k++) {
+ vec.push_back(
+ poolPtr->obtain(k % 2 == 0
+ ? VehiclePropertyType::FLOAT
+ : VehiclePropertyType::INT32));
+ }
+ }
+ }));
+ }
+
+ for (auto& t : threads) {
+ t.join();
+ }
+ auto finish = elapsedRealtimeNano();
+
+ ASSERT_EQ(static_cast<uint32_t>(T * C * O), stats->Obtained);
+ ASSERT_EQ(static_cast<uint32_t>(T * C * O), stats->Recycled);
+ // Created less than obtained.
+ ASSERT_GE(static_cast<uint32_t>(T * O), stats->Created);
+
+ auto elapsedMs = (finish - start) / 1000000;
+ ASSERT_GE(1000, elapsedMs); // Less a second to access 100K objects.
+ // Typically it takes about 0.1s on Nexus6P.
+}
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp
new file mode 100644
index 0000000..0f65820
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/VehiclePropConfigIndex.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class PropConfigTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ configs.assign(std::begin(kVehicleProperties),
+ std::end(kVehicleProperties));
+ }
+
+ void TearDown() override {}
+
+public:
+ std::vector<VehiclePropConfig> configs;
+};
+
+TEST_F(PropConfigTest, hasConfig) {
+ VehiclePropConfigIndex index(configs);
+
+ ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::HVAC_FAN_SPEED)));
+ ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_MAKE)));
+ ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY)));
+
+ ASSERT_FALSE(index.hasConfig(toInt(VehicleProperty::INVALID)));
+}
+
+TEST_F(PropConfigTest, getAllConfig) {
+ VehiclePropConfigIndex index(configs);
+
+ std::vector<VehiclePropConfig> actualConfigs = index.getAllConfigs();
+ ASSERT_EQ(configs.size(), actualConfigs.size());
+
+ for (size_t i = 0; i < actualConfigs.size(); i++) {
+ ASSERT_EQ(toString(configs[i]), toString(actualConfigs[i]));
+ }
+}
+
+TEST_F(PropConfigTest, getConfigs) {
+ VehiclePropConfigIndex index(configs);
+ auto actualConfig = index.getConfig(toInt(VehicleProperty::HVAC_FAN_SPEED));
+ ASSERT_EQ(toString(configs[1]), toString(actualConfig));
+}
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
new file mode 100644
index 0000000..a998d33
--- /dev/null
+++ b/automotive/vehicle/2.0/types.hal
@@ -0,0 +1,2689 @@
+/*
+ * Copyright (C) 2016 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.automotive.vehicle@2.0;
+
+/*
+ * Enumerates supported data types for VehicleProperty.
+ *
+ * This is a bitwise flag that supposed to be used in VehicleProperty enum.
+ */
+enum VehiclePropertyType : int32_t {
+ STRING = 0x00100000,
+ BOOLEAN = 0x00200000,
+ INT32 = 0x00400000,
+ INT32_VEC = 0x00410000,
+ INT64 = 0x00500000,
+ FLOAT = 0x00600000,
+ FLOAT_VEC = 0x00610000,
+ BYTES = 0x00700000,
+
+ /*
+ * Any combination of scalar or vector types. The exact format must be
+ * provided in the description of the property.
+ */
+ COMPLEX = 0x00e00000,
+
+ MASK = 0x00ff0000
+};
+
+/*
+ * Some properties may be associated with particular vehicle areas. For
+ * example, VehicleProperty:DOOR_LOCK property must be associated with
+ * particular door, thus this property must be marked with
+ * VehicleArea:DOOR flag.
+ *
+ * Other properties may not be associated with particular vehicle area,
+ * these kind of properties must have VehicleArea:GLOBAL flag.
+ *
+ * This is a bitwise flag that supposed to be used in VehicleProperty enum.
+ */
+enum VehicleArea : int32_t {
+ GLOBAL = 0x01000000,
+ ZONE = 0x02000000,
+ WINDOW = 0x03000000,
+ MIRROR = 0x04000000,
+ SEAT = 0x05000000,
+ DOOR = 0x06000000,
+
+ MASK = 0x0f000000,
+};
+
+/*
+ * Enumerates property groups.
+ *
+ * This is a bitwise flag that supposed to be used in VehicleProperty enum.
+ */
+enum VehiclePropertyGroup : int32_t {
+ /*
+ * Properties declared in AOSP must have this flag.
+ */
+ SYSTEM = 0x10000000,
+
+ /*
+ * Properties declared by vendors must have this flag.
+ */
+ VENDOR = 0x20000000,
+
+ MASK = 0xf0000000,
+};
+
+/*
+ * Declares all vehicle properties. VehicleProperty has a bitwise structure.
+ * Each property must have:
+ * - an unique id from range 0x0100 - 0xffff
+ * - associated data type using VehiclePropertyType
+ * - property group (VehiclePropertyGroup)
+ * - vehicle area (VehicleArea)
+ *
+ * Vendors are allowed to extend this enum with their own properties. In this
+ * case they must use VehiclePropertyGroup:VENDOR flag when property is
+ * declared.
+ */
+enum VehicleProperty: int32_t {
+
+ /* Undefined property. */
+ INVALID = 0x00000000,
+
+ /*
+ * VIN of vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ INFO_VIN= (
+ 0x0100
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Maker name of vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ INFO_MAKE = (
+ 0x0101
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Model of vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ INFO_MODEL = (
+ 0x0102
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Model year of vehicle.
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:YEAR
+ */
+ INFO_MODEL_YEAR = (
+ 0x0103
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Fuel capacity of the vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:MILLILITER
+ */
+ INFO_FUEL_CAPACITY = (
+ 0x0104
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Current odometer value of the vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE | VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:KILOMETER
+ */
+ PERF_ODOMETER = (
+ 0x0204
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Speed of the vehicle
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:METER_PER_SEC
+ */
+ PERF_VEHICLE_SPEED = (
+ 0x0207
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Temperature of engine coolant
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:CELSIUS
+ */
+ ENGINE_COOLANT_TEMP = (
+ 0x0301
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Temperature of engine oil
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:CELSIUS
+ */
+ ENGINE_OIL_TEMP = (
+ 0x0304
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Engine rpm
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:RPM
+ */
+ ENGINE_RPM = (
+ 0x0305
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Currently selected gear
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ * @data_enum VehicleGear
+ */
+ GEAR_SELECTION = (
+ 0x0400
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Current gear. In non-manual case, selected gear does not necessarily
+ * match the current gear.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ * @data_enum VehicleGear
+ */
+ CURRENT_GEAR = (
+ 0x0401
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Parking brake state.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ PARKING_BRAKE_ON = (
+ 0x0402
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Driving status policy.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ * @data_enum VehicleDrivingStatus
+ */
+ DRIVING_STATUS = (
+ 0x0404
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Warning for fuel low level.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ FUEL_LEVEL_LOW = (
+ 0x0405
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Night mode or not.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ NIGHT_MODE = (
+ 0x0407
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /*
+ * State of the vehicles turn signals
+ *
+ * Values from VehicleTurnSignal
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ TURN_SIGNAL_STATE = (
+ 0x0408
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Represents ignition state
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ IGNITION_STATE = (
+ 0x0409
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Fan speed setting
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_FAN_SPEED = (
+ 0x0500
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:ZONE),
+
+ /*
+ * Fan direction setting
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @data_enum VehicleHvacFanDirection
+ */
+ HVAC_FAN_DIRECTION = (
+ 0x0501
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:ZONE),
+
+ /*
+ * HVAC current temperature.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_TEMPERATURE_CURRENT = (
+ 0x0502
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:ZONE),
+
+ /*
+ * HVAC, target temperature set.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_TEMPERATURE_SET = (
+ 0x0503
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off defrost
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_DEFROSTER = (
+ 0x0504
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:WINDOW),
+
+ /*
+ * On/off AC
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_flags Supported zones
+ */
+ HVAC_AC_ON = (
+ 0x0505
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off max AC
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_MAX_AC_ON = (
+ 0x0506
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off max defrost
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_MAX_DEFROST_ON = (
+ 0x0507
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off re-circulation
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_RECIRC_ON = (
+ 0x0508
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off dual. This must be defined per each row.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_DUAL_ON = (
+ 0x0509
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * On/off automatic mode
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_AUTO_ON = (
+ 0x050A
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * Seat temperature
+ *
+ * Negative values indicate cooling.
+ * 0 indicates off.
+ * Positive values indicate heating.
+ *
+ * Some vehicles may have multiple levels of heating and cooling. The
+ * min/max range defines the allowable range and number of steps in each
+ * direction.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_SEAT_TEMPERATURE = (
+ 0x050B
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /**
+ * Side Mirror Heat
+ *
+ * Increase values denote higher heating levels for side mirrors.
+ * 0 indicates heating is turned off.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_SIDE_MIRROR_HEAT = (
+ 0x050C
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:MIRROR),
+
+ /**
+ * Steering Wheel Temperature
+ *
+ * Sets the temperature for the steering wheel
+ * Positive value indicates heating.
+ * Negative value indicates cooling.
+ * 0 indicates temperature control is off.
+ *
+ * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+ * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for
+ * details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_STEERING_WHEEL_TEMP = (
+ 0x050D
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Temperature units
+ *
+ * Indicates whether the temperature is in Celsius, Fahrenheit, or a
+ * different unit from VehicleUnit enum.
+ * This parameter affects all HVAC temperatures in the system.
+ *
+ * IVehicle#get is not guaranteed to work if HVAC unit is off. See
+ * HVAC_POWER_ON property for details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ HVAC_TEMPERATURE_UNITS = (
+ 0x050E
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:ZONE),
+
+ /**
+ * Actual fan speed
+ *
+ * IVehicle#get is not guaranteed to work if HVAC unit is off. See
+ * HVAC_POWER_ON property for details.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ HVAC_ACTUAL_FAN_SPEED_RPM = (
+ 0x050F
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:ZONE),
+
+ /**
+ * Fan Positions Available
+ *
+ * This is a bit mask of fan positions available for the zone. Each entry in
+ * vehicle_hvac_fan_direction is selected by bit position. For instance, if
+ * only the FAN_DIRECTION_FACE (0x1) and FAN_DIRECTION_DEFROST (0x4) are available,
+ * then this value shall be set to 0x12.
+ *
+ * 0x12 = (1 << 1) | (1 << 4)
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ HVAC_FAN_DIRECTION_AVAILABLE = (
+ 0x0511
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:ZONE),
+
+ /*
+ * Represents power state for HVAC. Some HVAC properties must require
+ * matching power to be turned on to get out of OFF state. For non-zoned
+ * HVAC properties, VEHICLE_ALL_ZONE corresponds to global power state.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_string list of HVAC properties whose power is controlled by this
+ * property. Format is hexa-decimal number (0x...) separated
+ * by comma like "0x500,0x503". All zones defined in these
+ * affected properties must be available in the property.
+ */
+ HVAC_POWER_ON = (
+ 0x0510
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:ZONE),
+
+ /*
+ * Outside temperature
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:CELSIUS
+ */
+ ENV_OUTSIDE_TEMPERATURE = (
+ 0x0703
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Cabin temperature
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:CELSIUS
+ */
+ ENV_CABIN_TEMPERATURE = (
+ 0x0704
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Radio presets stored on the Car radio module. The data type used is int32
+ * array with the following fields:
+ * <ul>
+ * <li> int32Values[0]: Preset number </li>
+ * <li> int32Values[1]: Band type (see #RADIO_BAND_FM in
+ * system/core/include/system/radio.h).
+ * <li> int32Values[2]: Channel number </li>
+ * <li> int32Values[3]: Sub channel number </li>
+ * </ul>
+ *
+ * NOTE: When getting a current preset config ONLY set preset number (i.e.
+ * int32Values[0]). For setting a preset other fields are required.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_flags Number of presets supported
+ */
+ RADIO_PRESET = (
+ 0x0801
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Represents audio focus state of Android side. Note that car's audio
+ * module must own audio focus and grant audio focus to Android side when
+ * requested by Android side. The focus has both per stream characteristics
+ * and global characteristics.
+ *
+ * Focus request (get of this property) must take the following form:
+ * int32Values[0]: VehicleAudioFocusRequest type
+ * int32Values[1]: bit flags of streams requested by this focus request.
+ * There can be up to 32 streams.
+ * int32Values[2]: External focus state flags. For request, only flag like
+ * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG or
+ * VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG can be
+ * used.
+ * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG is for case
+ * like radio where android side app still needs to hold
+ * focus but playback is done outside Android.
+ * VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG is for
+ * muting media channel including radio.
+ * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG can be set
+ * even if android side releases focus (request type
+ * REQUEST_RELEASE). In that case, audio module must
+ * maintain mute state until user's explicit action to
+ * play some media.
+ * int32Values[3]: Currently active audio contexts. Use combination of
+ * flags from VehicleAudioContextFlag.
+ * This can be used as a hint to adjust audio policy or
+ * other policy decision.
+ * Note that there can be multiple context active at the
+ * same time. And android can send the same focus request
+ * type gain due to change in audio contexts.
+ * Note that each focus request can request multiple streams that is
+ * expected to be used for the current request. But focus request itself
+ * is global behavior as GAIN or GAIN_TRANSIENT expects all sounds played
+ * by car's audio module to stop. Note that stream already allocated to
+ * android before this focus request must not be affected by focus
+ * request.
+ *
+ * Focus response (set and subscription callback for this property) must
+ * take the following form:
+ * int32Values[0]: VehicleAudioFocusState type
+ * int32Values[1]: bit flags of streams allowed.
+ * int32Values[2]: External focus state: bit flags of currently active
+ * audio focus in car side (outside Android). Active
+ * audio focus does not necessarily mean currently
+ * playing, but represents the state of having focus or
+ * waiting for focus (pause state).
+ * One or combination of flags from
+ * VehicleAudioExtFocusFlag.
+ * 0 means no active audio focus holder outside Android.
+ * The state must have following values for each
+ * VehicleAudioFocusState:
+ * GAIN: 0 or VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG
+ * when radio is active in Android side.
+ * GAIN_TRANSIENT: 0. Can be
+ * VehicleAudioExtFocusFlag#PERMANENT_FLAG or
+ * VehicleAudioExtFocusFlag#TRANSIENT_FLAG if android
+ * side has requested
+ * REQUEST_GAIN_TRANSIENT_MAY_DUCK and car side is
+ * ducking.
+ * LOSS: 0 when no focus is audio is active in car side.
+ * VehicleAudioExtFocusFlag#PERMANENT_FLAG when car
+ * side is playing something permanent.
+ * LOSS_TRANSIENT: always must be
+ * VehicleAudioExtFocusFlag#PERMANENT_FLAG
+ * int32Values[3]: context requested by android side when responding to
+ * focus request. When car side is taking focus away,
+ * this must be zero.
+ *
+ * A focus response must be sent per each focus request even if there is
+ * no change in focus state. This can happen in case like focus request
+ * only involving context change where android side still needs matching
+ * focus response to confirm that audio module has made necessary changes.
+ *
+ * If car does not support AUDIO_FOCUS, focus is assumed to be granted
+ * always.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ AUDIO_FOCUS = (
+ 0x0900
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * A property to allow external component to control audio focus. Depending on
+ * H/W architecture, audio HAL may need to control audio focus while vehicle
+ * HAL is still interacting with upper layer. In such case, audio HAL may set
+ * this property and vehicle HAL may use this property value to decide
+ * response sent through AUDIO_FOCUS property.
+ * Data format is the same as AUDIO_FOCUS property.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ AUDIO_FOCUS_EXT_SYNC = (
+ 0x0910
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to control audio volume of each audio context.
+ *
+ * VehiclePropConfig
+ * configArray[0] : bit flags of all supported audio contexts from
+ * VehicleAudioContextFlag. If this is 0, audio volume is
+ * controlled per physical stream.
+ * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to
+ * represent audio module's capability.
+ * configArray[2..3] : reserved
+ * configArray[4..N+3] : maximum values for each audio context, where N is
+ * the number of audio contexts provided in
+ * configArray[0], minimum value is always 0 which
+ * indicates mute state.
+ *
+ * Data type looks like:
+ * int32Values[0] : stream context as defined in VehicleAudioContextFlag.
+ * If only physical stream is supported
+ * (configArray[0] == 0), this must represent physical
+ * stream number.
+ * int32Values[1] : volume level, valid range is 0 (mute) to max level
+ * defined in the config.
+ * int32Values[2] : One of VehicleAudioVolumeState.
+ *
+ * This property requires per stream based get. HAL implementation must
+ * check stream number in get call to return the right volume.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_flags all audio contexts supported.
+ */
+ AUDIO_VOLUME = (
+ 0x0901
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to allow audio volume sync from external components like audio HAL.
+ * Some vehicle HAL implementation may get volume control from audio HAL and in such
+ * case, setting AUDIO_VOLUME_EXT_SYNC property may trigger event in AUDIO_VOLUME property.
+ * Data format for this property is the same as AUDIO_VOLUME property.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_flags all audio contexts supported.
+ */
+ AUDIO_VOLUME_EXT_SYNC = (
+ 0x0911
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property for handling volume limit set by user. This limits maximum
+ * volume that can be set per each context or physical stream.
+ *
+ * VehiclePropConfig
+ * configArray[0] : bit flags of all supported audio contexts. If this is
+ * 0, audio volume is controlled per physical stream.
+ * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag
+ * to represent audio module's capability.
+ *
+ * Data type looks like:
+ * int32Values[0] : stream context as defined in VehicleAudioFocusFlag.
+ * If only physical stream is supported
+ * (configArray[0] == 0), this must represent physical
+ * stream number.
+ * int32Values[1] : maximum volume set to the stream. If there is no
+ * restriction, this value must be bigger than
+ * AUDIO_VOLUME's max value.
+ *
+ * If car does not support this feature, this property must not be
+ * populated by HAL.
+ * This property requires per stream based get. HAL implementation must
+ * check stream number in get call to return the right volume.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_flags all audio contexts supported.
+ */
+ AUDIO_VOLUME_LIMIT = (
+ 0x0902
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to share audio routing policy of android side. This property is
+ * set at the beginning to pass audio policy in android side down to
+ * vehicle HAL and car audio module.
+ * This can be used as a hint to adjust audio policy or other policy
+ * decision.
+ *
+ * int32Values[0] : audio stream where the audio for the application
+ * context must be routed by default. Note that this is
+ * the default setting from system, but each app may
+ * still use different audio stream for whatever reason.
+ * int32Values[1] : All audio contexts that must be sent through the
+ * physical stream. Flag is defined in
+ * VehicleAudioFocusFlag.
+
+ * Setting of this property must be done for all available physical streams
+ * based on audio H/W variant information acquired from AUDIO_HW_VARIANT
+ * property.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ AUDIO_ROUTING_POLICY = (
+ 0x0903
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to return audio H/W variant type used in this car. This allows
+ * android side to support different audio policy based on H/W variant used.
+ * Note that other components like CarService may need overlay update to
+ * support additional variants. If this property does not
+ * exist, default audio policy must be used.
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ * @config_flags Additional info on audio H/W. Must use
+ * VehicleAudioHwVariantConfigFlag for this.
+ */
+ AUDIO_HW_VARIANT = (
+ 0x0904
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to pass hint on external audio routing. When android side
+ * request focus with VehicleAudioExtFocusflag, this
+ * property must be set before setting AUDIO_FOCUS property as a hint for
+ * external audio source routing.
+ * Note that setting this property alone must not trigger any change.
+ * Audio routing must be changed only when AUDIO_FOCUS property is set.
+ * Note that this property allows passing custom value as long as it is
+ * defined in VehiclePropConfig#configString. This allows supporting
+ * non-standard routing options through this property.
+ * It is recommended to use separate name space for custom property to
+ * prevent conflict in future android releases.
+ * Enabling each external routing option is done by enabling each bit flag
+ * for the routing.
+ * This property can support up to 128 external routings.
+ * To give full flexibility, there is no standard definition for each bit
+ * flag and assigning each big flag to specific routing type is decided by
+ * VehiclePropConfig#configString. VehiclePropConfig#configString has
+ * format of each entry separated by ',' and each entry has format of
+ * bitFlagPositon:typeString[:physicalStreamNumber].
+ * bitFlagPosition: represents which big flag will be set to enable this
+ * routing. 0 means
+ * LSB in int32Values[0]. 31 will be MSB in int32Values[0]. 127 will MSB
+ * in int32Values[3].
+ * typeString: string representation of external routing. Some types are
+ * already defined in AUDIO_EXT_ROUTING_SOURCE_* and use them first
+ * before adding something custom. Applications will find each routing
+ * using this string.
+ * physicalStreamNumber: This part is optional and represents physical
+ * stream to android which will be disabled when this routing is enabled.
+ * If not specified, this routing must not affect physical streams to
+ * android.
+ * As an example, let's assume a system with two physical streams, 0 for
+ * media and 1 for nav guidance. And let's assume external routing option
+ * of am fm radio, external navigation guidance, satellite radio, and one
+ * custom. Let's assume that radio and satellite replaces physical stream 0
+ * and external navigation replaces physical stream 1. And bit flag will be
+ * assigned in the order listed above. This configuration will look like
+ * this in config_string:
+ * "0:RADIO_AM_FM:0,1:EXT_NAV_GUIDANCE:1,2:RADIO_SATELLITE:0,3:com.test.SOMETHING_CUSTOM"
+ * When android requests RADIO_AM_FM, int32Values[0] will be set to 0x1.
+ * When android requests RADIO_SATELLITE + EXT_NAV_GUIDANCE, int32Values[0]
+ * will be set to 0x2|0x4.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @config_string List of all avaiable external source in the system.
+ */
+ AUDIO_EXT_ROUTING_HINT = (
+ 0x0905
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Represents state of audio stream. Audio HAL should set this when a stream is starting or
+ * ending. Car service can request focus for audio played without focus. If such feature
+ * is not required, this property does not need to be implemented.
+ * Car service only monitors setting of this property. It is up to each vehicle HAL
+ * implementation to add necessary action but default implementation will be doing nothing on
+ * this propery's set from audio HAL.
+ * Actual streaming of data should be done only after getting focus for the given stream from
+ * car audio module. Focus can be already granted when stream is started. Focus state can be
+ * monitored by monitoring AUDIO_FOCUS property. If car does not support
+ * AUDIO_FOCUS property, there is no need to monitor focus as focus is assumed to be
+ * granted always.
+ * Data has the following format:
+ * int32_array[0] : vehicle_audio_stream_state, 0: stopped, 1: started
+ * int32_array[1] : stream number like 0, 1, 2, ...
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ AUDIO_STREAM_STATE = (
+ 0x0906
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Property to control car specific audio parameters. Each parameter is defined as string key-
+ * value pair.
+ * set and event notification can pass multiple parameters using the
+ * following format:
+ * key1=value1;key2=value2;...
+ * get call can request multiple parameters using the following format:
+ * key1;key2;...
+ * Response for get call has the same format as set.
+ *
+ * VehiclePropConfig
+ * configString: give list of all supported keys with ; as separator. For example:
+ * key1;key2;...
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ AUDIO_PARAMETERS = (
+ 0x907
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:STRING
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to control power state of application processor
+ *
+ * It is assumed that AP's power state is controller by separate power
+ * controller.
+ *
+ * For configuration information, VehiclePropConfig.configFlags can
+ * have bit flag combining values in VehicleApPowerStateConfigFlag.
+ *
+ * Value format for IVehicle#get / IVehicle#subscribe:
+ * int32Values[0] : vehicle_ap_power_state_type
+ * int32Values[1] : additional parameter relevant for each state,
+ * 0 if not used.
+ * Value format for IVehicle#set:
+ * int32Values[0] : vehicle_ap_power_state_set_type
+ * int32Values[1] : additional parameter relevant for each request. should be 0 if not used.
+ *
+ * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE
+ * @access VEHICLE_PROP_ACCESS_READ_WRITE
+ */
+ AP_POWER_STATE = (
+ 0x0A00
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to represent brightness of the display. Some cars have single
+ * control for the brightness of all displays and this property is to share
+ * change in that control.
+ *
+ * If this is writable, android side can set this value when user changes
+ * display brightness from Settings. If this is read only, user may still
+ * change display brightness from Settings, but that will not be reflected
+ * to other displays.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ DISPLAY_BRIGHTNESS = (
+ 0x0A01
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to report bootup reason for the current power on. This is a
+ * static property that will not change for the whole duration until power
+ * off. For example, even if user presses power on button after automatic
+ * power on with door unlock, bootup reason must stay with
+ * VehicleApPowerBootupReason#USER_UNLOCK.
+ *
+ * int32Values[0] must be VehicleApPowerBootupReason.
+ *
+ * @change_mode VehiclePropertyChangeMode:STATIC
+ * @access VehiclePropertyAccess:READ
+ */
+ AP_POWER_BOOTUP_REASON = (
+ 0x0A02
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to feed H/W input events to android
+ *
+ * int32Values[0] : action defined by VehicleHwKeyInputAction
+ * int32Values[1] : key code, must use standard android key code
+ * int32Values[2] : target display defined in VehicleDisplay. Events not
+ * tied to specific display must be sent to
+ * VehicleDisplay#MAIN.
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ * @config_flags
+ */
+ HW_KEY_INPUT = (
+ 0x0A10
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Property to define instrument cluster information.
+ * For VehicleInstrumentClusterType:EXTERNAL_DISPLAY:
+ * READ:
+ * int32Values[0] : The current screen mode index. Screen mode is defined
+ * as a configuration in car service and represents
+ * which area of screen is renderable.
+ * int32Values[1] : Android can render to instrument cluster (=1) or
+ * not(=0). When this is 0, instrument cluster may be
+ * rendering some information in the area allocated for
+ * android and android side rendering is invisible.
+ * WRITE from android:
+ * int32Values[0] : Preferred mode for android side. Depending on the app
+ * rendering to instrument cluster, preferred mode can
+ * change. Instrument cluster still needs to send
+ * event with new mode to trigger actual mode change.
+ * int32Values[1] : The current app context relevant for instrument
+ * cluster. Use the same flag with VehicleAudioFocusFlag
+ * but this context represents active apps, not
+ * active audio. Instrument cluster side may change mode
+ * depending on the currently active contexts.
+ * When system boots up, Android side will write {0, 0, 0, 0} when it is
+ * ready to render to instrument cluster. Before this message, rendering
+ * from android must not be visible in the cluster.
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @configArray 0:VehicleInstrumentClusterType 1:hw type
+ */
+ INSTRUMENT_CLUSTER_INFO = (
+ 0x0A20
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Current date and time, encoded as Unix time.
+ * This value denotes the number of seconds that have elapsed since
+ * 1/1/1970.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_SET
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @unit VehicleUnit:SECS
+ */
+ UNIX_TIME = (
+ 0x0A30
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT64
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Current time only.
+ * Some vehicles may not keep track of date. This property only affects
+ * the current time, in seconds during the day. Thus, the max value for
+ * this parameter is 86,400 (24 * 60 * 60)
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_SET
+ * @access VehiclePropertyAccess:READ_WRITE
+ * @unit VehicleUnit:SECS
+ */
+ CURRENT_TIME_IN_SECONDS = (
+ 0x0A31
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Door position
+ *
+ * This is an integer in case a door may be set to a particular position.
+ * Max value indicates fully open, min value (0) indicates fully closed.
+ *
+ * Some vehicles (minivans) can open the door electronically. Hence, the
+ * ability to write this property.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ DOOR_POS = (
+ 0x0B00
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:DOOR),
+
+ /*
+ * Door move
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ DOOR_MOVE = (
+ 0x0B01
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:DOOR),
+
+ /*
+ * Door lock
+ *
+ * 'true' indicates door is locked
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ DOOR_LOCK = (
+ 0x0B02
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:DOOR),
+
+ /*
+ * Mirror Z Position
+ *
+ * Positive value indicates tilt upwards, negative value is downwards
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_Z_POS = (
+ 0x0B40
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:MIRROR),
+
+ /*
+ * Mirror Z Move
+ *
+ * Positive value indicates tilt upwards, negative value is downwards
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_Z_MOVE = (
+ 0x0B41
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:MIRROR),
+
+ /*
+ * Mirror Y Position
+ *
+ * Positive value indicate tilt right, negative value is left
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_Y_POS = (
+ 0x0B42
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:MIRROR),
+
+ /*
+ * Mirror Y Move
+ *
+ * Positive value indicate tilt right, negative value is left
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_Y_MOVE = (
+ 0x0B43
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:MIRROR),
+
+ /*
+ * Mirror Lock
+ *
+ * True indicates mirror positions are locked and not changeable
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_LOCK = (
+ 0x0B44
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Mirror Fold
+ *
+ * True indicates mirrors are folded
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ MIRROR_FOLD = (
+ 0x0B45
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Seat memory select
+ *
+ * This parameter selects the memory preset to use to select the seat
+ * position. The minValue is always 0, and the maxValue determines the
+ * number of seat positions available.
+ *
+ * For instance, if the driver's seat has 3 memory presets, the maxValue
+ * will be 3. When the user wants to select a preset, the desired preset
+ * number (1, 2, or 3) is set.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ SEAT_MEMORY_SELECT = (
+ 0x0B80
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat memory set
+ *
+ * This setting allows the user to save the current seat position settings
+ * into the selected preset slot. The maxValue for each seat position
+ * shall match the maxValue for SEAT_MEMORY_SELECT.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ SEAT_MEMORY_SET = (
+ 0x0B81
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seatbelt buckled
+ *
+ * True indicates belt is buckled.
+ *
+ * Write access indicates automatic seat buckling capabilities. There are
+ * no known cars at this time, but you never know...
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BELT_BUCKLED = (
+ 0x0B82
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:SEAT),
+
+ /*
+ * Seatbelt height position
+ *
+ * Adjusts the shoulder belt anchor point.
+ * Max value indicates highest position
+ * Min value indicates lowest position
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BELT_HEIGHT_POS = (
+ 0x0B83
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seatbelt height move
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BELT_HEIGHT_MOVE = (
+ 0x0B84
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat fore/aft position
+ *
+ * Sets the seat position forward (closer to steering wheel) and backwards.
+ * Max value indicates closest to wheel, min value indicates most rearward
+ * position.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_FORE_AFT_POS = (
+ 0x0B85
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat fore/aft move
+ *
+ * Moves the seat position forward and aft.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_FORE_AFT_MOVE = (
+ 0x0B86
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat backrest angle 1 position
+ *
+ * Backrest angle 1 is the actuator closest to the bottom of the seat.
+ * Max value indicates angling forward towards the steering wheel.
+ * Min value indicates full recline.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BACKREST_ANGLE_1_POS = (
+ 0x0B87
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat backrest angle 1 move
+ *
+ * Moves the backrest forward or recline.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BACKREST_ANGLE_1_MOVE = (
+ 0x0B88
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat backrest angle 2 position
+ *
+ * Backrest angle 2 is the next actuator up from the bottom of the seat.
+ * Max value indicates angling forward towards the steering wheel.
+ * Min value indicates full recline.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BACKREST_ANGLE_2_POS = (
+ 0x0B89
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat backrest angle 2 move
+ *
+ * Moves the backrest forward or recline.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_BACKREST_ANGLE_2_MOVE = (
+ 0x0B8A
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat height position
+ *
+ * Sets the seat height.
+ * Max value indicates highest position.
+ * Min value indicates lowest position.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEIGHT_POS = (
+ 0x0B8B
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat height move
+ *
+ * Moves the seat height.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEIGHT_MOVE = (
+ 0x0B8C
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat depth position
+ *
+ * Sets the seat depth, distance from back rest to front edge of seat.
+ * Max value indicates longest depth position.
+ * Min value indicates shortest position.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_DEPTH_POS = (
+ 0x0B8D
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat depth move
+ *
+ * Adjusts the seat depth.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_DEPTH_MOVE = (
+ 0x0B8E
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat tilt position
+ *
+ * Sets the seat tilt.
+ * Max value indicates front edge of seat higher than back edge.
+ * Min value indicates front edge of seat lower than back edge.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_TILT_POS = (
+ 0x0B8F
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Seat tilt move
+ *
+ * Tilts the seat.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_TILT_MOVE = (
+ 0x0B90
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Lumber fore/aft position
+ *
+ * Pushes the lumbar support forward and backwards
+ * Max value indicates most forward position.
+ * Min value indicates most rearward position.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_LUMBAR_FORE_AFT_POS = (
+ 0x0B91
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Lumbar fore/aft move
+ *
+ * Adjusts the lumbar support.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_LUMBAR_FORE_AFT_MOVE = (
+ 0x0B92
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Lumbar side support position
+ *
+ * Sets the amount of lateral lumbar support.
+ * Max value indicates widest lumbar setting (i.e. least support)
+ * Min value indicates thinnest lumbar setting.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_LUMBAR_SIDE_SUPPORT_POS = (
+ 0x0B93
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Lumbar side support move
+ *
+ * Adjusts the amount of lateral lumbar support.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_LUMBAR_SIDE_SUPPORT_MOVE = (
+ 0x0B94
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Headrest height position
+ *
+ * Sets the headrest height.
+ * Max value indicates tallest setting.
+ * Min value indicates shortest setting.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_HEIGHT_POS = (
+ 0x0B95
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Headrest height move
+ *
+ * Moves the headrest up and down.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_HEIGHT_MOVE = (
+ 0x0B96
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Headrest angle position
+ *
+ * Sets the angle of the headrest.
+ * Max value indicates most upright angle.
+ * Min value indicates shallowest headrest angle.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_ANGLE_POS = (
+ 0x0B97
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Headrest angle move
+ *
+ * Adjusts the angle of the headrest
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_ANGLE_MOVE = (
+ 0x0B98
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Headrest fore/aft position
+ *
+ * Adjusts the headrest forwards and backwards.
+ * Max value indicates position closest to front of car.
+ * Min value indicates position closest to rear of car.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_FORE_AFT_POS = (
+ 0x0B99
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Headrest fore/aft move
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SEAT_HEADREST_FORE_AFT_MOVE = (
+ 0x0B9A
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:SEAT),
+
+ /*
+ * Window Position
+ *
+ * Max = window up / closed
+ * Min = window down / open
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ WINDOW_POS = (
+ 0x0BC0
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Window Move
+ *
+ * Max = window up / closed
+ * Min = window down / open
+ * Magnitude denotes relative speed. I.e. +2 is faster than +1 in raising
+ * the window.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ WINDOW_MOVE = (
+ 0x0BC1
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Window Vent Position
+ *
+ * This feature is used to control the vent feature on a sunroof.
+ *
+ * Max = vent open
+ * Min = vent closed
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ WINDOW_VENT_POS = (
+ 0x0BC2
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Window Vent Move
+ *
+ * This feature is used to control the vent feature on a sunroof.
+ *
+ * Max = vent open
+ * Min = vent closed
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ WINDOW_VENT_MOVE = (
+ 0x0BC3
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:INT32
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Window Lock
+ *
+ * True indicates windows are locked and can't be moved.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ WINDOW_LOCK = (
+ 0x0BC4
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:GLOBAL),
+};
+
+/*
+ * Bit flags for fan direction
+ */
+enum VehicleHvacFanDirection : int32_t {
+ FACE = 0x1,
+ FLOOR = 0x2,
+ FACE_AND_FLOOR = 0x3,
+ DEFROST = 0x4,
+ DEFROST_AND_FLOOR = 0x5,
+};
+
+/*
+ * Constants relevant to radio.
+ */
+enum VehicleRadioConstants : int32_t {
+ /* Minimum value for the radio preset */
+ VEHICLE_RADIO_PRESET_MIN_VALUE = 1,
+};
+
+enum VehicleAudioFocusRequest : int32_t {
+ REQUEST_GAIN = 0x1,
+ REQUEST_GAIN_TRANSIENT = 0x2,
+ REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3,
+ /*
+ * This is for the case where android side plays sound like UI feedback
+ * and car side does not need to duck existing playback as long as
+ * requested stream is available.
+ */
+ REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4,
+ REQUEST_RELEASE = 0x5,
+
+};
+
+enum VehicleAudioFocusState : int32_t {
+ /*
+ * Android side has permanent focus and can play allowed streams.
+ */
+ STATE_GAIN = 0x1,
+
+ /*
+ * Android side has transient focus and can play allowed streams.
+ */
+ STATE_GAIN_TRANSIENT = 0x2,
+
+ /*
+ * Car audio module is playing guidance kind of sound outside Android.
+ * Android side can still play through allowed streams with ducking.
+ */
+ STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3,
+
+ /*
+ * Car audio module is playing transient sound outside Android. Android side
+ * must stop playing any sounds.
+ */
+ STATE_LOSS_TRANSIENT = 0x4,
+
+ /*
+ * Android side has lost focus and cannot play any sound.
+ */
+ STATE_LOSS = 0x5,
+
+ /*
+ * car audio module is playing safety critical sound, and Android side cannot
+ * request focus until the current state is finished. car audio module
+ * restore it to the previous state when it can allow Android to play.
+ */
+ STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6,
+
+};
+
+/*
+ * Flags to represent multiple streams by combining these.
+ */
+enum VehicleAudioStreamFlag : int32_t {
+ STREAM0_FLAG = (0x1 << 0),
+ STREAM1_FLAG = (0x1 << 1),
+ STREAM2_FLAG = (0x1 << 2),
+};
+
+/*
+ * Represents stream number (always 0 to N -1 where N is max number of streams).
+ * Can be used for audio related property expecting one stream.
+ */
+enum VehicleAudioStream : int32_t {
+ STREAM0 = 0,
+ STREAM1 = 1,
+};
+
+/*
+ * Flag to represent external focus state (outside Android).
+ */
+enum VehicleAudioExtFocusFlag : int32_t {
+ /*
+ * No external focus holder.
+ */
+ NONE_FLAG = 0x0,
+
+ /*
+ * Car side (outside Android) has component holding GAIN kind of focus state.
+ */
+ PERMANENT_FLAG = 0x1,
+
+ /*
+ * Car side (outside Android) has component holding GAIN_TRANSIENT kind of
+ * focus state.
+ */
+ TRANSIENT_FLAG = 0x2,
+
+ /*
+ * Car side is expected to play something while focus is held by Android side.
+ * One example can be radio attached in car side. But Android's radio app
+ * still must have focus, and Android side must be in GAIN state, but
+ * media stream will not be allocated to Android side and car side can play
+ * radio any time while this flag is active.
+ */
+ PLAY_ONLY_FLAG = 0x4,
+
+ /*
+ * Car side must mute any media including radio. This can be used with any
+ * focus request including GAIN* and RELEASE.
+ */
+ MUTE_MEDIA_FLAG = 0x8,
+};
+
+/*
+ * Index in int32Values for VehicleProperty#AUDIO_FOCUS property.
+ */
+enum VehicleAudioFocusIndex : int32_t {
+ FOCUS = 0,
+ STREAMS = 1,
+ EXTERNAL_FOCUS_STATE = 2,
+ AUDIO_CONTEXTS = 3,
+};
+
+/*
+ * Flags to tell the current audio context.
+ */
+enum VehicleAudioContextFlag : int32_t {
+ /* Music playback is currently active. */
+ MUSIC_FLAG = 0x1,
+
+ /* Navigation is currently running. */
+ NAVIGATION_FLAG = 0x2,
+
+ /* Voice command session is currently running. */
+ VOICE_COMMAND_FLAG = 0x4,
+
+ /* Voice call is currently active. */
+ CALL_FLAG = 0x8,
+
+ /*
+ * Alarm is active.
+ * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
+ */
+ ALARM_FLAG = 0x10,
+
+ /*
+ * Notification sound is active.
+ * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
+ */
+ NOTIFICATION_FLAG = 0x20,
+
+ /*
+ * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to
+ * represent default stream for unknown contents.
+ */
+ UNKNOWN_FLAG = 0x40,
+
+ /* Safety alert / warning is played. */
+ SAFETY_ALERT_FLAG = 0x80,
+
+ /* CD / DVD kind of audio is played */
+ CD_ROM_FLAG = 0x100,
+
+ /* Aux audio input is played */
+ AUX_AUDIO_FLAG = 0x200,
+
+ /* system sound like UI feedback */
+ SYSTEM_SOUND_FLAG = 0x400,
+
+ /* Radio is played */
+ RADIO_FLAG = 0x800,
+
+ /* Ext source is played. This is for tagging generic ext sources. */
+ EXT_SOURCE_FLAG = 0x1000,
+};
+
+/*
+ * flags to represent capability of audio volume property.
+ * used in configArray[1] of VehiclePropConfig.
+ */
+enum VehicleAudioVolumeCapabilityFlag : int32_t {
+ /*
+ * External audio module or vehicle hal has persistent storage
+ * to keep the volume level. This must be set only when per context
+ * volume level is supported. When this is set, audio volume level per
+ * each context will be retrieved from the property when system starts up.
+ * And external audio module is also expected to adjust volume automatically
+ * whenever there is an audio context change.
+ * When this flag is not set, android side will assume that there is no
+ * persistent storage and stored value in android side will be used to
+ * initialize the volume level. And android side will set volume level
+ * of each physical streams whenever there is an audio context change.
+ */
+ PERSISTENT_STORAGE = 0x1,
+
+ /*
+ * When this flag is set, the H/W can support only single master volume for
+ * all streams.
+ * There is no way to set volume level differently per each stream or context.
+ */
+ MASTER_VOLUME_ONLY = 0x2,
+};
+
+/*
+ * enum to represent audio volume state.
+ */
+enum VehicleAudioVolumeState : int32_t {
+ STATE_OK = 0,
+
+ /*
+ * Audio volume has reached volume limit set in
+ * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume
+ * further is not allowed.
+ */
+ LIMIT_REACHED = 1,
+};
+
+/*
+ * Index in int32Values for VehicleProperty#AUDIO_VOLUME property.
+ */
+enum VehicleAudioVolumeIndex : int32_t {
+ INDEX_STREAM = 0,
+ INDEX_VOLUME = 1,
+ INDEX_STATE = 2,
+};
+
+/*
+ * Index in int32Values for VehicleProperty#AUDIO_VOLUME_LIMIT property.
+ */
+enum VehicleAudioVolumeLimitIndex : int32_t {
+ STREAM = 0,
+ MAX_VOLUME = 1,
+};
+
+/*
+ * Index in int32Values for VehicleProperty#AUDIO_ROUTING_POLICY property.
+ */
+enum VehicleAudioRoutingPolicyIndex : int32_t {
+ STREAM = 0,
+ CONTEXTS = 1,
+};
+
+/*
+ * Flag to be used in VehiclePropConfig#configFlags for
+ * VehicleProperty#AUDIO_HW_VARIANT.
+ */
+enum VehicleAudioHwVariantConfigFlag : int32_t {
+ /*
+ * Flag to tell that radio is internal to android and radio must
+ * be treated like other android stream like media.
+ * When this flag is not set or AUDIO_HW_VARIANT does not exist,
+ * radio is treated as external module. This brins some delta in audio focus
+ * handling as well.
+ */
+ INTERNAL_RADIO_FLAG = 0x1,
+};
+
+enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ {
+ /*
+ * AP can enter deep sleep state. If not set, AP will always shutdown from
+ * VehicleApPowerState#SHUTDOWN_PREPARE power state.
+ */
+ ENABLE_DEEP_SLEEP_FLAG = 0x1,
+
+ /*
+ * The power controller can power on AP from off state after timeout
+ * specified in VehicleApPowerSet VEHICLE_AP_POWER_SET_SHUTDOWN_READY message.
+ */
+ CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2,
+};
+
+enum VehicleApPowerState : int32_t /* NOTE: type is guessed */ {
+ /* vehicle HAL will never publish this state to AP */
+ OFF = 0,
+
+ /* vehicle HAL will never publish this state to AP */
+ DEEP_SLEEP = 1,
+
+ /* AP is on but display must be off. */
+ ON_DISP_OFF = 2,
+
+ /* AP is on with display on. This state allows full user interaction. */
+ ON_FULL = 3,
+
+ /*
+ * The power controller has requested AP to shutdown. AP can either enter
+ * sleep state or start full shutdown. AP can also request postponing
+ * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The
+ * power controller must change power state to this state to shutdown
+ * system.
+ *
+ * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+ */
+ SHUTDOWN_PREPARE = 4,
+};
+
+enum VehicleApPowerStateShutdownParam : int32_t {
+ /* AP must shutdown immediately. Postponing is not allowed. */
+ SHUTDOWN_IMMEDIATELY = 1,
+
+ /* AP can enter deep sleep instead of shutting down completely. */
+ CAN_SLEEP = 2,
+
+ /* AP can only shutdown with postponing allowed. */
+ SHUTDOWN_ONLY = 3,
+};
+
+enum VehicleApPowerSetState : int32_t /* NOTE: type is guessed */ {
+ /*
+ * AP has finished boot up, and can start shutdown if requested by power
+ * controller.
+ */
+ BOOT_COMPLETE = 0x1,
+
+ /*
+ * AP is entering deep sleep state. How this state is implemented may vary
+ * depending on each H/W, but AP's power must be kept in this state.
+ */
+ DEEP_SLEEP_ENTRY = 0x2,
+
+ /*
+ * AP is exiting from deep sleep state, and is in
+ * VehicleApPowerState#SHUTDOWN_PREPARE state.
+ * The power controller may change state to other ON states based on the
+ * current state.
+ */
+ DEEP_SLEEP_EXIT = 0x3,
+
+ /*
+ * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be
+ * 5000 ms.
+ * If AP needs more time, it will send another POSTPONE
+ * message before the previous one expires.
+ */
+ SHUTDOWN_POSTPONE = 0x4,
+
+ /*
+ * AP is starting shutting down. When system completes shutdown, everything
+ * will stop in AP as kernel will stop all other contexts. It is
+ * responsibility of vehicle HAL or lower level to synchronize that state
+ * with external power controller. As an example, some kind of ping
+ * with timeout in power controller can be a solution.
+ *
+ * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
+ * AP after specified time so that AP can run tasks like
+ * update. If it is set to 0, there is no wake up, and power
+ * controller may not necessarily support wake-up. If power
+ * controller turns on AP due to timer, it must start with
+ * VehicleApPowerState#ON_DISP_OFF state, and after
+ * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall
+ * do state transition to
+ * VehicleApPowerState#SHUTDOWN_PREPARE.
+ */
+ SHUTDOWN_START = 0x5,
+
+ /*
+ * User has requested to turn off headunit's display, which is detected in
+ * android side.
+ * The power controller may change the power state to
+ * VehicleApPowerState#ON_DISP_OFF.
+ */
+ DISPLAY_OFF = 0x6,
+
+ /*
+ * User has requested to turn on headunit's display, most probably from power
+ * key input which is attached to headunit. The power controller may change
+ * the power state to VehicleApPowerState#ON_FULL.
+ */
+ DISPLAY_ON = 0x7,
+};
+
+/*
+ * Index in int32Values for VehicleProperty#AP_POWER_STATE property.
+ */
+enum VehicleApPowerStateIndex : int32_t {
+ STATE = 0,
+ ADDITIONAL = 1,
+};
+
+/*
+ * Enum to represent bootup reason.
+ */
+enum VehicleApPowerBootupReason : int32_t {
+ /*
+ * Power on due to user's pressing of power key or rotating of ignition
+ * switch.
+ */
+ USER_POWER_ON = 0,
+
+ /*
+ * Automatic power on triggered by door unlock or any other kind of automatic
+ * user detection.
+ */
+ USER_UNLOCK = 1,
+
+ /*
+ * Automatic power on triggered by timer. This only happens when AP has asked
+ * wake-up after
+ * certain time through time specified in
+ * VehicleApPowerSetState#SHUTDOWN_START.
+ */
+ TIMER = 2,
+};
+
+enum VehicleHwKeyInputAction : int32_t {
+ /* Key down */
+ ACTION_DOWN = 0,
+
+ /* Key up */
+ ACTION_UP = 1,
+};
+
+enum VehicleDisplay : int32_t {
+ /* center console */
+ MAIN = 0,
+
+ INSTRUMENT_CLUSTER = 1,
+};
+
+/*
+ * Represents instrument cluster type available in system
+ */
+enum VehicleInstrumentClusterType : int32_t {
+ /* Android has no access to instument cluster */
+ NONE = 0,
+
+ /*
+ * Instrument cluster can communicate through vehicle hal with additional
+ * properties to exchange meta-data
+ */
+ HAL_INTERFACE = 1,
+
+ /*
+ * Instrument cluster is external display where android can render contents
+ */
+ EXTERNAL_DISPLAY = 2,
+};
+
+/*
+ * Units used for int or float type with no attached enum types.
+ */
+enum VehicleUnit : int32_t {
+ SHOULD_NOT_USE = 0x000,
+
+ METER_PER_SEC = 0x01,
+ RPM = 0x02,
+ HERTZ = 0x03,
+ PERCENTILE = 0x10,
+ MILLIMETER = 0x20,
+ METER = 0x21,
+ KILOMETER = 0x23,
+ CELSIUS = 0x30,
+ FAHRENHEIT = 0x31,
+ KELVIN = 0x32,
+ MILLILITER = 0x40,
+ NANO_SECS = 0x50,
+ SECS = 0x53,
+ YEAR = 0x59,
+};
+
+ /*
+ * This describes how value of property can change.
+ */
+enum VehiclePropertyChangeMode : int32_t {
+ /*
+ * Property of this type must never be changed. Subscription is not supported
+ * for these properties.
+ */
+ STATIC = 0x00,
+
+ /*
+ * Property of this type must be reported when there is a change.
+ * IVehicle#get call must return the current value.
+ * Set operation for this property is assumed to be asynchronous. When the
+ * property is read (using IVehicle#get) after IVehicle#set, it may still
+ * return old value until underlying H/W backing this property has actually
+ * changed the state. Once state is changed, the property must dispatch
+ * changed value as event.
+ */
+ ON_CHANGE = 0x01,
+
+ /*
+ * Property of this type change continuously and requires fixed rate of
+ * sampling to retrieve the data.
+ */
+ CONTINUOUS = 0x02,
+
+ /*
+ * Property of this type may be polled to get the current value.
+ */
+ POLL = 0x03,
+
+ /*
+ * This is for property where change event must be sent only when the
+ * value is set from external component. Normal value change must not trigger
+ * event. For example, clock property can send change event only when it is
+ * set, outside android, for case like user setting time or time getting
+ * update. There is no need to send it per every value change.
+ */
+ ON_SET = 0x04,
+};
+
+/*
+ * Property config defines the capabilities of it. User of the API
+ * must first get the property config to understand the output from get()
+ * commands and also to ensure that set() or events commands are in sync with
+ * the expected output.
+ */
+enum VehiclePropertyAccess : int32_t {
+ NONE = 0x00,
+
+ READ = 0x01,
+ WRITE = 0x02,
+ READ_WRITE = 0x03,
+};
+
+/*
+ * Car states.
+ *
+ * The driving states determine what features of the UI will be accessible.
+ */
+enum VehicleDrivingStatus : int32_t {
+ UNRESTRICTED = 0x00,
+ NO_VIDEO = 0x01,
+ NO_KEYBOARD_INPUT = 0x02,
+ NO_VOICE_INPUT = 0x04,
+ NO_CONFIG = 0x08,
+ LIMIT_MESSAGE_LEN = 0x10,
+};
+
+/*
+ * Various gears which can be selected by user and chosen in system.
+ */
+enum VehicleGear: int32_t {
+ GEAR_NEUTRAL = 0x0001,
+ GEAR_REVERSE = 0x0002,
+ GEAR_PARK = 0x0004,
+ GEAR_DRIVE = 0x0008,
+ GEAR_LOW = 0x0010,
+ GEAR_1 = 0x0010,
+ GEAR_2 = 0x0020,
+ GEAR_3 = 0x0040,
+ GEAR_4 = 0x0080,
+ GEAR_5 = 0x0100,
+ GEAR_6 = 0x0200,
+ GEAR_7 = 0x0400,
+ GEAR_8 = 0x0800,
+ GEAR_9 = 0x1000,
+};
+
+/*
+ * Various zones in the car.
+ *
+ * Zones are used for Air Conditioning purposes and divide the car into physical
+ * area zones.
+ */
+enum VehicleAreaZone : int32_t {
+ ROW_1_LEFT = 0x00000001,
+ ROW_1_CENTER = 0x00000002,
+ ROW_1_RIGHT = 0x00000004,
+ ROW_1 = 0x00000008,
+ ROW_2_LEFT = 0x00000010,
+ ROW_2_CENTER = 0x00000020,
+ ROW_2_RIGHT = 0x00000040,
+ ROW_2 = 0x00000080,
+ ROW_3_LEFT = 0x00000100,
+ ROW_3_CENTER = 0x00000200,
+ ROW_3_RIGHT = 0x00000400,
+ ROW_3 = 0x00000800,
+ ROW_4_LEFT = 0x00001000,
+ ROW_4_CENTER = 0x00002000,
+ ROW_4_RIGHT = 0x00004000,
+ ROW_4 = 0x00008000,
+ WHOLE_CABIN = 0x80000000,
+};
+
+/*
+ * Various Seats in the car.
+ */
+enum VehicleAreaSeat : int32_t {
+ ROW_1_LEFT = 0x0001,
+ ROW_1_CENTER = 0x0002,
+ ROW_1_RIGHT = 0x0004,
+ ROW_2_LEFT = 0x0010,
+ ROW_2_CENTER = 0x0020,
+ ROW_2_RIGHT = 0x0040,
+ ROW_3_LEFT = 0x0100,
+ ROW_3_CENTER = 0x0200,
+ ROW_3_RIGHT = 0x0400
+};
+
+/*
+ * Various windshields/windows in the car.
+ */
+enum VehicleAreaWindow : int32_t {
+ FRONT_WINDSHIELD = 0x0001,
+ REAR_WINDSHIELD = 0x0002,
+ ROOF_TOP = 0x0004,
+ ROW_1_LEFT = 0x0010,
+ ROW_1_RIGHT = 0x0020,
+ ROW_2_LEFT = 0x0100,
+ ROW_2_RIGHT = 0x0200,
+ ROW_3_LEFT = 0x1000,
+ ROW_3_RIGHT = 0x2000,
+};
+
+enum VehicleAreaDoor : int32_t {
+ ROW_1_LEFT = 0x00000001,
+ ROW_1_RIGHT = 0x00000004,
+ ROW_2_LEFT = 0x00000010,
+ ROW_2_RIGHT = 0x00000040,
+ ROW_3_LEFT = 0x00000100,
+ ROW_3_RIGHT = 0x00000400,
+ HOOD = 0x10000000,
+ REAR = 0x20000000,
+};
+
+enum VehicleAreaMirror : int32_t {
+ DRIVER_LEFT = 0x00000001,
+ DRIVER_RIGHT = 0x00000002,
+ DRIVER_CENTER = 0x00000004,
+};
+
+enum VehicleTurnSignal : int32_t {
+ NONE = 0x00,
+ RIGHT = 0x01,
+ LEFT = 0x02,
+ EMERGENCY = 0x04,
+};
+
+struct VehicleAreaConfig {
+ /*
+ * Area id is ignored for VehiclePropertyGroup:GLOBAL properties.
+ */
+ int32_t areaId;
+
+ int32_t minInt32Value;
+ int32_t maxInt32Value;
+
+ int64_t minInt64Value;
+ int64_t maxInt64Value;
+
+ float minFloatValue;
+ float maxFloatValue;
+};
+
+struct VehiclePropConfig {
+ /* Property identifier */
+ int32_t prop;
+
+ /*
+ * Defines if the property is read or write or both.
+ */
+ VehiclePropertyAccess access;
+
+ /*
+ * Defines the change mode of the property.
+ */
+ VehiclePropertyChangeMode changeMode;
+
+ /*
+ * Some of the properties may have associated areas (for example, some hvac
+ * properties are associated with VehicleAreaZone), in these
+ * cases the config may contain an ORed value for the associated areas.
+ */
+ int32_t supportedAreas;
+
+ /*
+ * Contains per-area configuration.
+ */
+ vec<VehicleAreaConfig> areaConfigs;
+
+ /*
+ * Configuration flags for this property.
+ *
+ * For example, it may store the number of presets that are stored by the
+ * radio module.
+ */
+ int32_t configFlags;
+
+ /* Contains additional configuration parameters */
+ vec<int32_t> configArray;
+
+ /*
+ * Some properties may require additional information passed over this
+ * string. Most properties do not need to set this.
+ */
+ string configString;
+
+ /*
+ * Min sample rate in Hz.
+ * Must be defined for VehiclePropertyChangeMode::CONTINUOUS
+ */
+ float minSampleRate;
+
+ /*
+ * Must be defined for VehiclePropertyChangeMode::CONTINUOUS
+ * Max sample rate in Hz.
+ */
+ float maxSampleRate;
+};
+
+/*
+ * Encapsulates the property name and the associated value. It
+ * is used across various API calls to set values, get values or to register for
+ * events.
+ */
+struct VehiclePropValue {
+ /* Property identifier */
+ int32_t prop;
+
+ /* Time is elapsed nanoseconds since boot */
+ int64_t timestamp;
+
+ /*
+ * Area type(s) for non-global property it must be one of the value from
+ * VehicleArea* enums or 0 for global properties.
+ */
+ int32_t areaId;
+
+ /*
+ * Contains value for a single property. Depending on property data type of
+ * this property (VehiclePropetyType) one field of this structure must be filled in.
+ */
+ struct RawValue {
+ /*
+ * This is used for properties of types VehiclePropertyType#INT
+ * and VehiclePropertyType#INT_VEC
+ */
+ vec<int32_t> int32Values;
+
+ /*
+ * This is used for properties of types VehiclePropertyType#FLOAT
+ * and VehiclePropertyType#FLOAT_VEC
+ */
+ vec<float> floatValues;
+
+ /* This is used for properties of type VehiclePropertyType#INT64 */
+ vec<int64_t> int64Values;
+
+ /* This is used for properties of type VehiclePropertyType#BYTES */
+ vec<uint8_t> bytes;
+
+ /* This is used for properties of type VehiclePropertyType#STRING */
+ string stringValue;
+ };
+
+ RawValue value;
+};
+
+enum VehicleIgnitionState : int32_t {
+ UNDEFINED = 0,
+
+ /* Steering wheel is locked */
+ LOCK = 1,
+
+ /*
+ * Steering wheel is not locked, engine and all accessories are OFF. If
+ * car can be in LOCK and OFF state at the same time than HAL must report
+ * LOCK state.
+ */
+ OFF,
+
+ /*
+ * Typically in this state accessories become available (e.g. radio).
+ * Instrument cluster and engine are turned off
+ */
+ ACC,
+
+ /*
+ * Ignition is in state ON. Accessories and instrument cluster available,
+ * engine might be running or ready to be started.
+ */
+ ON,
+
+ /* Typically in this state engine is starting (cranking). */
+ START
+};
+
+
+/*
+ * Represent the operation where the current error has happened.
+ */
+enum VehiclePropertyOperation : int32_t {
+ /*
+ * Generic error to this property which is not tied to any operation.
+ */
+ GENERIC = 0,
+
+ /*
+ * Error happened while handling property set.
+ */
+ SET = 1,
+
+ /*
+ * Error happened while handling property get.
+ */
+ GET = 2,
+
+ /*
+ * Error happened while handling property subscription.
+ */
+ SUBSCRIBE = 3,
+};
+
+
+enum SubscribeFlags : int32_t {
+ UNDEFINED = 0x0,
+
+ /*
+ * Subscribe to event that was originated in vehicle HAL
+ * (most likely this event came from the vehicle itself).
+ */
+ HAL_EVENT = 0x1,
+
+ /*
+ * Use this flag to subscribe on events when IVehicle#set(...) was called by
+ * vehicle HAL's client (e.g. Car Service).
+ */
+ SET_CALL = 0x2,
+
+ DEFAULT = HAL_EVENT,
+};
+
+/*
+ * Encapsulates information about subscription to vehicle property events.
+ */
+struct SubscribeOptions {
+ /* Property to subscribe */
+ int32_t propId;
+
+ /*
+ * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe
+ * to all areas.
+ */
+ int32_t vehicleAreas;
+
+ /*
+ * Sample rate in Hz.
+ *
+ * Must be provided for properties with
+ * VehiclePropertyChangeMode::CONTINUOUS. The value must be within
+ * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate
+ * for a given property.
+ * This value indicates how many updates per second client wants to receive.
+ */
+ float sampleRate;
+
+ /* Flags that indicate what kind of events listen to. */
+ SubscribeFlags flags;
+};
+
+/* Error codes used in vehicle HAL interface. */
+enum StatusCode : int32_t {
+ OK = 0,
+
+ /* Try again. */
+ TRY_AGAIN = 1,
+
+ /* Invalid argument provided. */
+ INVALID_ARG = 2,
+
+ /*
+ * This code must be returned when device that associated with the vehicle
+ * property is not available. For example, when client tries to set HVAC
+ * temperature when the whole HVAC unit is turned OFF.
+ */
+ NOT_AVAILABLE = 3,
+
+ /* Access denied */
+ ACCESS_DENIED = 4,
+
+ /* Something unexpected has happened in Vehicle HAL */
+ INTERNAL_ERROR = 5,
+};
+
+enum Wheel : int32_t {
+ UNKNOWN = 0x0,
+
+ LEFT_FRONT = 0x1,
+ RIGHT_FRONT = 0x2,
+ LEFT_REAR = 0x4,
+ RIGHT_REAR = 0x8,
+};
diff --git a/automotive/vehicle/2.1/Android.bp b/automotive/vehicle/2.1/Android.bp
new file mode 100644
index 0000000..cf4d8b0
--- /dev/null
+++ b/automotive/vehicle/2.1/Android.bp
@@ -0,0 +1,64 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.automotive.vehicle@2.1_hal",
+ srcs: [
+ "types.hal",
+ "IVehicle.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.vehicle@2.1_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1",
+ srcs: [
+ ":android.hardware.automotive.vehicle@2.1_hal",
+ ],
+ out: [
+ "android/hardware/automotive/vehicle/2.1/types.cpp",
+ "android/hardware/automotive/vehicle/2.1/VehicleAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.automotive.vehicle@2.1_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1",
+ srcs: [
+ ":android.hardware.automotive.vehicle@2.1_hal",
+ ],
+ out: [
+ "android/hardware/automotive/vehicle/2.1/types.h",
+ "android/hardware/automotive/vehicle/2.1/IVehicle.h",
+ "android/hardware/automotive/vehicle/2.1/IHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.1/BnHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.1/BpHwVehicle.h",
+ "android/hardware/automotive/vehicle/2.1/BsVehicle.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.automotive.vehicle@2.1",
+ generated_sources: ["android.hardware.automotive.vehicle@2.1_genc++"],
+ generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"],
+ export_generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.automotive.vehicle@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.automotive.vehicle@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/automotive/vehicle/2.1/Android.mk b/automotive/vehicle/2.1/Android.mk
new file mode 100644
index 0000000..f030af08
--- /dev/null
+++ b/automotive/vehicle/2.1/Android.mk
@@ -0,0 +1,534 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.automotive.vehicle@2.1-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hardware.automotive.vehicle@2.0-java \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (CommonIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CompressionIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelSystemStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.FuelType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (IgnitionMonitorKind)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2FloatSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2IntegerSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SecondaryAirStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SparkIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleProperty)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VehicleProperty
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageIntegerValuesIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VmsMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicle.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::IVehicle
+
+$(GEN): $(LOCAL_PATH)/IVehicle.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.automotive.vehicle@2.1-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hardware.automotive.vehicle@2.0-java-static \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (CommonIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CompressionIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelSystemStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FuelType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.FuelType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (IgnitionMonitorKind)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2FloatSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Obd2IntegerSensorIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SecondaryAirStatus)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SparkIgnitionMonitors)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VehicleProperty)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VehicleProperty
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageIntegerValuesIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::types.VmsMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVehicle.hal
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.automotive.vehicle@2.1::IVehicle
+
+$(GEN): $(LOCAL_PATH)/IVehicle.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/automotive/vehicle/2.1/IVehicle.hal b/automotive/vehicle/2.1/IVehicle.hal
new file mode 100644
index 0000000..5b6a23f
--- /dev/null
+++ b/automotive/vehicle/2.1/IVehicle.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.automotive.vehicle@2.1;
+
+import android.hardware.automotive.vehicle@2.0;
+
+/*
+ * New revision of IVehicle interface that supports properties defined in
+ * VehicleProperty enum version 2.1.
+ *
+ * NOTE: this HAL interface is under development and shouldn't be used in
+ * production.
+ *
+ * TODO(pavelm): update comment when this interface is ready for prod.
+ */
+interface IVehicle extends @2.0::IVehicle {
+};
diff --git a/automotive/vehicle/2.1/default/Android.mk b/automotive/vehicle/2.1/default/Android.mk
new file mode 100644
index 0000000..3075956
--- /dev/null
+++ b/automotive/vehicle/2.1/default/Android.mk
@@ -0,0 +1,122 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+vhal_v2_0 = android.hardware.automotive.vehicle@2.0
+vhal_v2_1 = android.hardware.automotive.vehicle@2.1
+
+###############################################################################
+# Vehicle reference implementation lib
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(vhal_v2_1)-manager-lib
+LOCAL_SRC_FILES := \
+ common/src/Obd2SensorStore.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/common/include/vhal_v2_1 \
+ $(LOCAL_PATH)/../../2.0/default/common/include/vhal_v2_0 \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/common/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libutils \
+ $(vhal_v2_1) \
+
+include $(BUILD_STATIC_LIBRARY)
+
+###############################################################################
+# Vehicle default VehicleHAL implementation
+###############################################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= $(vhal_v2_1)-default-impl-lib
+LOCAL_SRC_FILES:= \
+ impl/vhal_v2_1/DefaultVehicleHal.cpp \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/impl/vhal_v2_1 \
+ $(LOCAL_PATH)/common/include
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/impl \
+ $(LOCAL_PATH)/common/include
+
+
+# LOCAL_WHOLE_STATIC_LIBRARIES := \
+
+LOCAL_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-default-impl-lib \
+ $(vhal_v2_0)-manager-lib \
+ $(vhal_v2_1)-manager-lib \
+ $(vhal_v2_0)-libproto-native
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libutils \
+ libprotobuf-cpp-lite \
+ $(vhal_v2_0) \
+ $(vhal_v2_1) \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
+include $(BUILD_STATIC_LIBRARY)
+
+###############################################################################
+# Vehicle HAL service
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(vhal_v2_1)-service
+LOCAL_INIT_RC := $(vhal_v2_1)-service.rc
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SRC_FILES := \
+ service.cpp
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-libproto-native \
+
+LOCAL_STATIC_LIBRARIES := \
+ $(vhal_v2_0)-manager-lib \
+ $(vhal_v2_0)-default-impl-lib \
+ $(vhal_v2_1)-default-impl-lib \
+ $(vhal_v2_1)-manager-lib \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ liblog \
+ libutils \
+ libprotobuf-cpp-lite \
+ $(vhal_v2_0) \
+ $(vhal_v2_1) \
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
+include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc b/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc
new file mode 100644
index 0000000..8929d25
--- /dev/null
+++ b/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc
@@ -0,0 +1,4 @@
+service vehicle-hal-2.1 /vendor/bin/hw/android.hardware.automotive.vehicle@2.1-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
new file mode 100644
index 0000000..945e3e0
--- /dev/null
+++ b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_
+#define android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_
+
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+// This class wraps all the logic required to create an OBD2 frame.
+// It allows storing sensor values, setting appropriate bitmasks as needed,
+// and returning appropriately laid out storage of sensor values suitable
+// for being returned via a VehicleHal implementation.
+class Obd2SensorStore {
+public:
+ // Creates a sensor storage with a given number of vendor-specific sensors.
+ Obd2SensorStore(size_t numVendorIntegerSensors,
+ size_t numVendorFloatSensors);
+
+ // Stores an integer-valued sensor.
+ V2_0::StatusCode setIntegerSensor(Obd2IntegerSensorIndex index, int32_t value);
+ // Stores an integer-valued sensor.
+ V2_0::StatusCode setIntegerSensor(size_t index, int32_t value);
+
+ // Stores a float-valued sensor.
+ V2_0::StatusCode setFloatSensor(Obd2FloatSensorIndex index, float value);
+ // Stores a float-valued sensor.
+ V2_0::StatusCode setFloatSensor(size_t index, float value);
+
+ // Returns a vector that contains all integer sensors stored.
+ const std::vector<int32_t>& getIntegerSensors() const;
+ // Returns a vector that contains all float sensors stored.
+ const std::vector<float>& getFloatSensors() const;
+ // Returns a vector that contains a bitmask for all stored sensors.
+ const std::vector<uint8_t>& getSensorsBitmask() const;
+
+ // Given a stringValue, fill in a VehiclePropValue
+ void fillPropValue(V2_0::VehiclePropValue *propValue,
+ std::string dtc) const;
+
+private:
+ class BitmaskInVector {
+ public:
+ BitmaskInVector(size_t numBits = 0);
+ void resize(size_t numBits);
+ bool get(size_t index) const;
+ void set(size_t index, bool value);
+
+ const std::vector<uint8_t>& getBitmask() const;
+
+ private:
+ std::vector<uint8_t> mStorage;
+ };
+
+ std::vector<int32_t> mIntegerSensors;
+ std::vector<float> mFloatSensors;
+ BitmaskInVector mSensorsBitmask;
+};
+
+} // namespace V2_1
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_
diff --git a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
new file mode 100644
index 0000000..b07717b
--- /dev/null
+++ b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "Obd2SensorStore.h"
+
+#include <utils/SystemClock.h>
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+Obd2SensorStore::BitmaskInVector::BitmaskInVector(size_t numBits)
+{
+ resize(numBits);
+}
+
+void Obd2SensorStore::BitmaskInVector::resize(size_t numBits) {
+ mStorage = std::vector<uint8_t>((numBits+7)/8, 0);
+}
+
+void Obd2SensorStore::BitmaskInVector::set(size_t index, bool value) {
+ const size_t byteIndex = index / 8;
+ const size_t bitIndex = index % 8;
+ const uint8_t byte = mStorage[byteIndex];
+ uint8_t newValue = value ? (byte | (1 << bitIndex)) :
+ (byte & ~(1 << bitIndex));
+ mStorage[byteIndex] = newValue;
+}
+
+bool Obd2SensorStore::BitmaskInVector::get(size_t index) const {
+ const size_t byteIndex = index / 8;
+ const size_t bitIndex = index % 8;
+ const uint8_t byte = mStorage[byteIndex];
+ return (byte & (1 << bitIndex)) != 0;
+}
+
+const std::vector<uint8_t>& Obd2SensorStore::BitmaskInVector::getBitmask() const {
+ return mStorage;
+}
+
+Obd2SensorStore::Obd2SensorStore(size_t numVendorIntegerSensors,
+ size_t numVendorFloatSensors) {
+ // because the last index is valid *inclusive*
+ const size_t numSystemIntegerSensors = V2_0::toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)+1;
+ const size_t numSystemFloatSensors = V2_0::toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)+1;
+ mIntegerSensors = std::vector<int32_t>(
+ numSystemIntegerSensors+numVendorIntegerSensors, 0);
+ mFloatSensors = std::vector<float>(
+ numSystemFloatSensors+numVendorFloatSensors, 0);
+ mSensorsBitmask.resize(mIntegerSensors.size()+mFloatSensors.size());
+}
+
+V2_0::StatusCode Obd2SensorStore::setIntegerSensor(Obd2IntegerSensorIndex index,
+ int32_t value) {
+ return setIntegerSensor(V2_0::toInt(index), value);
+}
+V2_0::StatusCode Obd2SensorStore::setFloatSensor(Obd2FloatSensorIndex index,
+ float value) {
+ return setFloatSensor(V2_0::toInt(index), value);
+}
+
+V2_0::StatusCode Obd2SensorStore::setIntegerSensor(size_t index, int32_t value) {
+ mIntegerSensors[index] = value;
+ mSensorsBitmask.set(index, true);
+ return V2_0::StatusCode::OK;
+}
+
+V2_0::StatusCode Obd2SensorStore::setFloatSensor(size_t index, float value) {
+ mFloatSensors[index] = value;
+ mSensorsBitmask.set(index + mIntegerSensors.size(), true);
+ return V2_0::StatusCode::OK;
+}
+
+const std::vector<int32_t>& Obd2SensorStore::getIntegerSensors() const {
+ return mIntegerSensors;
+}
+
+const std::vector<float>& Obd2SensorStore::getFloatSensors() const {
+ return mFloatSensors;
+}
+
+const std::vector<uint8_t>& Obd2SensorStore::getSensorsBitmask() const {
+ return mSensorsBitmask.getBitmask();
+}
+
+void Obd2SensorStore::fillPropValue(V2_0::VehiclePropValue *propValue,
+ std::string dtc) const {
+ propValue->timestamp = elapsedRealtimeNano();
+ propValue->value.int32Values = getIntegerSensors();
+ propValue->value.floatValues = getFloatSensors();
+ propValue->value.bytes = getSensorsBitmask();
+ propValue->value.stringValue = dtc;
+}
+
+
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
new file mode 100644
index 0000000..6bdec59
--- /dev/null
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_
+#define android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_
+
+#include <android/hardware/automotive/vehicle/2.1/types.h>
+#include <vhal_v2_0/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+namespace impl {
+
+const V2_0::VehiclePropConfig kVehicleProperties[] = {
+ {
+ .prop = V2_0::toInt(V2_1::VehicleProperty::WHEEL_TICK),
+ .access = V2_0::VehiclePropertyAccess::READ,
+ .changeMode = V2_0::VehiclePropertyChangeMode::CONTINUOUS,
+ },
+
+ {
+ .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME),
+ .access = V2_0::VehiclePropertyAccess::READ,
+ .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0,0}
+ },
+
+ {
+ .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME),
+ .access = V2_0::VehiclePropertyAccess::READ,
+ .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {0,0}
+ },
+
+ {
+ .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO),
+ .access = V2_0::VehiclePropertyAccess::READ,
+ .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
+ },
+
+ {
+ .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR),
+ .access = V2_0::VehiclePropertyAccess::WRITE,
+ .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
+ },
+
+ {
+ .prop = V2_0::toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
+ .access = V2_0::VehiclePropertyAccess::READ_WRITE,
+ .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
+ }
+};
+
+} // impl
+
+} // namespace V2_1
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp
new file mode 100644
index 0000000..b147ce7
--- /dev/null
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "DefaultVehicleHal_v2_1"
+#include <android/log.h>
+
+#include <algorithm>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "DefaultVehicleHal.h"
+#include "VehicleHalProto.pb.h"
+
+#define DEBUG_SOCKET (33452)
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+namespace impl {
+
+static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(
+ size_t numVendorIntegerSensors,
+ size_t numVendorFloatSensors) {
+ std::unique_ptr<Obd2SensorStore> sensorStore(new Obd2SensorStore(
+ numVendorIntegerSensors, numVendorFloatSensors));
+
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
+ V2_0::toInt(FuelSystemStatus::CLOSED_LOOP));
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
+ V2_0::toInt(IgnitionMonitorKind::SPARK));
+ sensorStore->setIntegerSensor(Obd2IntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
+ CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
+ CommonIgnitionMonitors::MISFIRE_AVAILABLE |
+ SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
+ SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
+ V2_0::toInt(SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
+ sensorStore->setIntegerSensor(
+ Obd2IntegerSensorIndex::FUEL_TYPE, V2_0::toInt(FuelType::GASOLINE));
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::ENGINE_RPM, 1250.);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::VEHICLE_SPEED, 40.);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::TIMING_ADVANCE, 2.5);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::THROTTLE_POSITION, 19.75);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, -0.373);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 190.);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
+ sensorStore->setFloatSensor(
+ Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
+
+ return sensorStore;
+}
+
+void DefaultVehicleHal::initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
+ V2_0::VehiclePropValue* liveObd2Frame) {
+ auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
+ propConfig.configArray[1]);
+ sensorStore->fillPropValue(liveObd2Frame, "");
+ liveObd2Frame->prop = V2_0::toInt(VehicleProperty::OBD2_LIVE_FRAME);
+}
+
+void DefaultVehicleHal::initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig) {
+ auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0],
+ propConfig.configArray[1]);
+
+ mFreezeObd2Frames.push_back(
+ createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
+ mFreezeObd2Frames.push_back(
+ createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
+ mFreezeObd2Frames.push_back(
+ createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0));
+
+ sensorStore->fillPropValue(mFreezeObd2Frames[0].get(), "P0070");
+ sensorStore->fillPropValue(mFreezeObd2Frames[1].get(), "P0102");
+ sensorStore->fillPropValue(mFreezeObd2Frames[2].get(), "P0123");
+}
+
+template<typename Iterable>
+typename Iterable::const_iterator findPropValueAtTimestamp(
+ const Iterable& frames,
+ int64_t timestamp) {
+ return std::find_if(frames.begin(),
+ frames.end(),
+ [timestamp] (const std::unique_ptr<V2_0::VehiclePropValue>&
+ propValue) -> bool {
+ return propValue->timestamp == timestamp;
+ });
+}
+
+V2_0::StatusCode DefaultVehicleHal::fillObd2FreezeFrame(
+ const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::VehiclePropValue* v) {
+ if (requestedPropValue.value.int64Values.size() != 1) {
+ ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
+ return V2_0::StatusCode::INVALID_ARG;
+ }
+ auto timestamp = requestedPropValue.value.int64Values[0];
+ auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
+ timestamp);
+ if(mFreezeObd2Frames.end() == freezeFrameIter) {
+ ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
+ return V2_0::StatusCode::INVALID_ARG;
+ }
+ const auto& freezeFrame = *freezeFrameIter;
+ v->prop = V2_0::toInt(VehicleProperty::OBD2_FREEZE_FRAME);
+ v->value.int32Values = freezeFrame->value.int32Values;
+ v->value.floatValues = freezeFrame->value.floatValues;
+ v->value.bytes = freezeFrame->value.bytes;
+ v->value.stringValue = freezeFrame->value.stringValue;
+ v->timestamp = freezeFrame->timestamp;
+ return V2_0::StatusCode::OK;
+}
+
+V2_0::StatusCode DefaultVehicleHal::clearObd2FreezeFrames(
+ const V2_0::VehiclePropValue& propValue) {
+ if (propValue.value.int64Values.size() == 0) {
+ mFreezeObd2Frames.clear();
+ return V2_0::StatusCode::OK;
+ } else {
+ for(int64_t timestamp: propValue.value.int64Values) {
+ auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames,
+ timestamp);
+ if(mFreezeObd2Frames.end() == freezeFrameIter) {
+ ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
+ return V2_0::StatusCode::INVALID_ARG;
+ }
+ mFreezeObd2Frames.erase(freezeFrameIter);
+ }
+ }
+ return V2_0::StatusCode::OK;
+}
+
+V2_0::StatusCode DefaultVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* v) {
+ std::vector<int64_t> timestamps;
+ for(const auto& freezeFrame: mFreezeObd2Frames) {
+ timestamps.push_back(freezeFrame->timestamp);
+ }
+ v->value.int64Values = timestamps;
+ return V2_0::StatusCode::OK;
+}
+
+void DefaultVehicleHal::onCreate() {
+ mVehicleHal20->init(getValuePool(),
+ std::bind(&DefaultVehicleHal::doHalEvent, this, _1),
+ std::bind(&DefaultVehicleHal::doHalPropertySetError, this, _1, _2, _3));
+
+ std::vector<V2_0::VehiclePropConfig> configs = listProperties();
+ for (auto& cfg : configs) {
+ switch(cfg.prop) {
+ case V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME): {
+ auto liveObd2Frame = createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX, 0);
+ initObd2LiveFrame(cfg, liveObd2Frame.get());
+ mVehicleHal20->addCustomProperty(*liveObd2Frame);
+ }
+ break;
+ case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
+ initObd2FreezeFrame(cfg);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+DefaultVehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
+ const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::StatusCode* outStatus) {
+
+ auto propId = requestedPropValue.prop;
+ VehiclePropValuePtr v = nullptr;
+ auto& pool = *getValuePool();
+
+ switch (propId) {
+ case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME):
+ v = pool.obtainComplex();
+ *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
+ return v;
+ case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO):
+ v = pool.obtainComplex();
+ *outStatus = fillObd2DtcInfo(v.get());
+ return v;
+ default:
+ return mVehicleHal20->get(requestedPropValue, outStatus);
+ }
+}
+
+V2_0::StatusCode DefaultVehicleHal::set(
+ const V2_0::VehiclePropValue& propValue) {
+
+ auto propId = propValue.prop;
+ switch (propId) {
+ case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR):
+ return clearObd2FreezeFrames(propValue);
+ break;
+ case V2_0::toInt(V2_1::VehicleProperty::VEHICLE_MAP_SERVICE):
+ // Placeholder for future implementation of VMS property in the default hal. For now, just
+ // returns OK; otherwise, hal clients crash with property not supported.
+ return V2_0::StatusCode::OK;
+ break;
+ default:
+ return mVehicleHal20->set(propValue);
+ }
+}
+
+} // impl
+
+} // namespace V2_1
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h
new file mode 100644
index 0000000..af21138
--- /dev/null
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_
+#define android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_
+
+#include <memory>
+
+#include <utils/SystemClock.h>
+
+#include <vhal_v2_0/VehicleHal.h>
+#include <vhal_v2_0/DefaultVehicleHal.h>
+#include <vhal_v2_1/Obd2SensorStore.h>
+
+#include "DefaultConfig.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_1 {
+
+namespace impl {
+
+using namespace std::placeholders;
+
+class DefaultVehicleHal : public V2_0::VehicleHal {
+public:
+ DefaultVehicleHal(V2_0::impl::DefaultVehicleHal* vhal20) :
+ mVehicleHal20(vhal20) {}
+
+ std::vector<V2_0::VehiclePropConfig> listProperties() override {
+ std::vector<V2_0::VehiclePropConfig> propConfigs(mVehicleHal20->listProperties());
+
+ // Join Vehicle Hal 2.0 and 2.1 configs.
+ propConfigs.insert(propConfigs.end(),
+ std::begin(kVehicleProperties),
+ std::end(kVehicleProperties));
+
+ return propConfigs;
+ }
+
+ VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::StatusCode* outStatus) override;
+
+ V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override;
+
+ V2_0::StatusCode subscribe(int32_t property,
+ int32_t areas,
+ float sampleRate) override {
+ return mVehicleHal20->subscribe(property, areas, sampleRate);
+ }
+
+ V2_0::StatusCode unsubscribe(int32_t property) override {
+ return mVehicleHal20->unsubscribe(property);
+ }
+
+ void onCreate() override;
+
+private:
+ void initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig,
+ V2_0::VehiclePropValue* liveObd2Frame);
+ void initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig);
+ V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue,
+ V2_0::VehiclePropValue* v);
+ V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *v);
+ V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue);
+
+private:
+ V2_0::impl::DefaultVehicleHal* mVehicleHal20;
+ std::vector<std::unique_ptr<V2_0::VehiclePropValue>> mFreezeObd2Frames;
+};
+
+} // impl
+
+} // namespace V2_1
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.1/default/service.cpp b/automotive/vehicle/2.1/default/service.cpp
new file mode 100644
index 0000000..0844622
--- /dev/null
+++ b/automotive/vehicle/2.1/default/service.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "automotive.vehicle@2.1-service"
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <iostream>
+
+#include <android/hardware/automotive/vehicle/2.1/IVehicle.h>
+
+#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/DefaultVehicleHal.h>
+
+#include <vhal_v2_1/DefaultVehicleHal.h>
+
+using namespace android;
+using namespace android::hardware;
+
+namespace V2_1 = ::android::hardware::automotive::vehicle::V2_1;
+namespace V2_0 = ::android::hardware::automotive::vehicle::V2_0;
+
+using StatusCode = V2_0::StatusCode;
+using VehiclePropValue = V2_0::VehiclePropValue;
+
+/* Just wrapper that passes all calls to the provided V2_0::IVehicle object */
+struct Vehicle_V2_1 : public V2_1::IVehicle {
+
+ Vehicle_V2_1(V2_0::IVehicle* vehicle20) : mVehicle20(vehicle20) {}
+
+ // Methods derived from IVehicle
+ Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override {
+ return mVehicle20->getAllPropConfigs(_hidl_cb);
+ }
+
+ Return<void> getPropConfigs(const hidl_vec<int32_t>& properties,
+ getPropConfigs_cb _hidl_cb) override {
+ return mVehicle20->getPropConfigs(properties, _hidl_cb);
+ }
+
+ Return<void> get(const V2_0::VehiclePropValue& requestedPropValue,
+ get_cb _hidl_cb) override {
+ return mVehicle20->get(requestedPropValue, _hidl_cb);
+ }
+
+ Return<StatusCode> set(const VehiclePropValue& value) override {
+ return mVehicle20->set(value);
+ }
+
+ Return<StatusCode> subscribe(const sp<V2_0::IVehicleCallback>& callback,
+ const hidl_vec<V2_0::SubscribeOptions>&
+ options) override {
+ return mVehicle20->subscribe(callback, options);
+ }
+
+ Return<StatusCode> unsubscribe(const sp<V2_0::IVehicleCallback>& callback,
+ int32_t propId) override {
+ return mVehicle20->unsubscribe(callback, propId);
+ }
+
+ Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override {
+ return mVehicle20->debugDump(_hidl_cb);
+ }
+
+private:
+ V2_0::IVehicle* mVehicle20;
+};
+
+int main(int /* argc */, char* /* argv */ []) {
+ auto halImpl20 = std::make_unique<V2_0::impl::DefaultVehicleHal>();
+ auto halImpl21 = std::make_unique<V2_1::impl::DefaultVehicleHal>(halImpl20.get());
+
+ auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(halImpl21.get());
+
+ Vehicle_V2_1 vehicle21(vehicleManager.get());
+
+ ALOGI("Registering as service...");
+ vehicle21.registerAsService();
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ ALOGI("Ready");
+ joinRpcThreadpool();
+}
diff --git a/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp b/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp
new file mode 100644
index 0000000..a01c0f4
--- /dev/null
+++ b/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+ #include <gtest/gtest.h>
+
+#include "vhal_v2_0/Obd2SensorStore.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+static constexpr size_t getNumVendorIntegerSensors() {
+ return 5;
+}
+static constexpr size_t getNumVendorFloatSensors() {
+ return 3;
+}
+
+// this struct holds information necessary for a test to be able to validate
+// that the sensor bitmask contains the right data:
+// - the index of the byte at which the bit for a given sensor lives
+// - the expected value of that byte given that a certain sensor is present
+class BitmaskIndexingInfo {
+public:
+ size_t mByteIndex;
+ uint8_t mExpectedByteValue;
+
+ // Returns the information required to validate the bitmask for an
+ // integer-valued sensor.
+ static BitmaskIndexingInfo getForIntegerSensor(size_t index) {
+ const size_t indexInBitstream = index;
+ return getForBitstreamIndex(indexInBitstream);
+ }
+
+ // Returns the information required to validate the bitmask for a
+ // float-valued sensor.
+ static BitmaskIndexingInfo getForFloatSensor(size_t index) {
+ const size_t indexInBitstream = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) +
+ 1 + getNumVendorIntegerSensors() + index;
+ return getForBitstreamIndex(indexInBitstream);
+ }
+
+private:
+ static BitmaskIndexingInfo getForBitstreamIndex(size_t indexInBitstream) {
+ BitmaskIndexingInfo indexingInfo;
+ indexingInfo.mByteIndex = indexInBitstream / 8;
+ indexingInfo.mExpectedByteValue = 1 << (indexInBitstream % 8);
+ return indexingInfo;
+ }
+};
+
+static Obd2SensorStore getSensorStore() {
+ return Obd2SensorStore(getNumVendorIntegerSensors(),
+ getNumVendorFloatSensors());
+}
+
+// Test that one can set and retrieve a value for the first integer sensor.
+TEST(Obd2SensorStoreTest, setFirstIntegerSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setIntegerSensor(
+ Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
+ toInt(FuelSystemStatus::CLOSED_LOOP));
+ const auto& integerSensors(sensorStore.getIntegerSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(
+ toInt(FuelSystemStatus::CLOSED_LOOP),
+ integerSensors[toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the first float sensor.
+TEST(Obd2SensorStoreTest, setFirstFloatSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setFloatSensor(
+ Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD,
+ 1.25f);
+ const auto& floatSensors(sensorStore.getFloatSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(
+ 1.25f,
+ floatSensors[toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for an integer sensor.
+TEST(Obd2SensorStoreTest, setAnyIntegerSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setIntegerSensor(
+ Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE,
+ 4000);
+ const auto& integerSensors(sensorStore.getIntegerSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(4000,
+ integerSensors[toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for a float sensor.
+TEST(Obd2SensorStoreTest, setAnyFloatSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setFloatSensor(
+ Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE,
+ 2.5f);
+ const auto& floatSensors(sensorStore.getFloatSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(2.5f,
+ floatSensors[toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the last system integer sensor.
+TEST(Obd2SensorStoreTest, setLastSystemIntegerSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setIntegerSensor(
+ Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX,
+ 30);
+ const auto& integerSensors(sensorStore.getIntegerSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(30,
+ integerSensors[toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the last system float sensor.
+TEST(Obd2SensorStoreTest, setLastSystemFloatSensor) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setFloatSensor(
+ Obd2FloatSensorIndex::LAST_SYSTEM_INDEX,
+ 2.5f);
+ const auto& floatSensors(sensorStore.getFloatSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(2.5f,
+ floatSensors[toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for two integer sensors at once.
+TEST(Obd2SensorStoreTest, setTwoIntegerSensors) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setIntegerSensor(
+ Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE,
+ 6);
+ sensorStore.setIntegerSensor(
+ Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED,
+ 1245);
+ const auto& integerSensors(sensorStore.getIntegerSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(6,
+ integerSensors[toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)]);
+ ASSERT_EQ(1245,
+ integerSensors[toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)]);
+ const BitmaskIndexingInfo voltageIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)));
+ const BitmaskIndexingInfo timeIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)));
+ if (voltageIndexingInfo.mByteIndex == timeIndexingInfo.mByteIndex) {
+ ASSERT_EQ(
+ voltageIndexingInfo.mExpectedByteValue |
+ timeIndexingInfo.mExpectedByteValue,
+ sensorBitmask[timeIndexingInfo.mByteIndex]);
+ }
+ else {
+ ASSERT_EQ(
+ timeIndexingInfo.mExpectedByteValue,
+ sensorBitmask[timeIndexingInfo.mByteIndex]);
+ ASSERT_EQ(
+ voltageIndexingInfo.mExpectedByteValue,
+ sensorBitmask[voltageIndexingInfo.mByteIndex]);
+ }
+}
+
+// Test that one can set and retrieve a value for two float sensors at once.
+TEST(Obd2SensorStoreTest, setTwoFloatSensors) {
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setFloatSensor(
+ Obd2FloatSensorIndex::VEHICLE_SPEED,
+ 1.25f);
+ sensorStore.setFloatSensor(
+ Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE,
+ 2.5f);
+ const auto& floatSensors(sensorStore.getFloatSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(1.25f,
+ floatSensors[toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)]);
+ ASSERT_EQ(2.5f,
+ floatSensors[toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)]);
+ const BitmaskIndexingInfo speedIndexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)));
+ const BitmaskIndexingInfo airflowIndexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)));
+ if (speedIndexingInfo.mByteIndex == airflowIndexingInfo.mByteIndex) {
+ ASSERT_EQ(
+ speedIndexingInfo.mExpectedByteValue |
+ airflowIndexingInfo.mExpectedByteValue,
+ sensorBitmask[airflowIndexingInfo.mByteIndex]);
+ }
+ else {
+ ASSERT_EQ(
+ speedIndexingInfo.mExpectedByteValue,
+ sensorBitmask[speedIndexingInfo.mByteIndex]);
+ ASSERT_EQ(
+ airflowIndexingInfo.mExpectedByteValue,
+ sensorBitmask[airflowIndexingInfo.mByteIndex]);
+ }
+}
+
+// Test that one can set and retrieve a value for a vendor integer sensor.
+TEST(Obd2SensorStoreTest, setVendorIntegerSensor) {
+ const size_t sensorIndex = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + 2;
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setIntegerSensor(sensorIndex, 22);
+ const auto& integerSensors(sensorStore.getIntegerSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(22, integerSensors[sensorIndex]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+ sensorIndex));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for a vendor float sensor.
+TEST(Obd2SensorStoreTest, setVendorFloatSensor) {
+ const size_t sensorIndex = toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX) + 2;
+ Obd2SensorStore sensorStore(getSensorStore());
+ sensorStore.setFloatSensor(sensorIndex, 1.25f);
+ const auto& floatSensors(sensorStore.getFloatSensors());
+ const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+ ASSERT_EQ(1.25f, floatSensors[sensorIndex]);
+ const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+ sensorIndex));
+ ASSERT_EQ(
+ indexingInfo.mExpectedByteValue,
+ sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+} // namespace anonymous
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.1/types.hal b/automotive/vehicle/2.1/types.hal
new file mode 100644
index 0000000..9b219b2
--- /dev/null
+++ b/automotive/vehicle/2.1/types.hal
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.automotive.vehicle@2.1;
+
+import android.hardware.automotive.vehicle@2.0;
+
+/*
+ * Extension of VehicleProperty enum declared in Vehicle HAL 2.0
+ */
+enum VehicleProperty: @2.0::VehicleProperty {
+ /*
+ * Reports wheel rotational distance in meters since last wheel tick
+ * event
+ *
+ * The value is a vector each element represents distance for individual
+ * wheel in the following order: left front, right front, left rear,
+ * right rear. VehiclePropValue.timestamp must be correctly filled in.
+ *
+ * Vendors must specify wheels that support this sensor in
+ * VehiclePropConfig.configFlags. The format of this field is a bitset of
+ * values from Wheel enum.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE |VehiclePropertyChangeMode:CONTINUOUS
+ * @access VehiclePropertyAccess:READ
+ * @unit VehicleUnit:METER
+ */
+ WHEEL_TICK = (
+ 0x0306
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:FLOAT_VEC
+ | VehicleArea:GLOBAL),
+
+ /*
+ * OBD2 Live Sensor Data
+ *
+ * This property uses COMPLEX data to send a snapshot of the current (live)
+ * values of the OBD2 sensors provided by the vehicle.
+ *
+ * VehiclePropConfig
+ * configArray[0] : number of vendor-specific integer-valued sensors
+ * that can be returned in a frame.
+ * configArray[1] : number of vendor-specific float-valued sensors
+ * that can be returned in a frame.
+ *
+ * The values are to be interpreted as follows:
+ * the indices defined in Obd2IntegerSensorIndex are to be used to
+ * read from int32Values;
+ * the indices defined in Obd2FloatSensorIndex are to be used to
+ * read from floatValues.
+ * the elements of bytes are to be interpreted as a bitmask, such that
+ * the bits 0 thru the integer value of
+ * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0]
+ * are 1 if the corresponding index is a valid sensor index whose value can
+ * be read in the returned int32Values vector, 0 otherwise.
+ * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru
+ * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1]
+ * are 1 if the corresponding index is a valid sensor index whose value
+ * can be read in the returned floatValues vector, 0 otherwise.
+ *
+ * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and
+ * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping
+ * is only valid if the corresponding bits in the bytes vector are set to 1.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ OBD2_LIVE_FRAME = (
+ 0x0D00
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:COMPLEX
+ | VehicleArea:GLOBAL),
+
+ /*
+ * OBD2 Freeze Frame Sensor Data
+ *
+ * This property uses COMPLEX data to send a snapshot of the values of the
+ * OBD2 sensors provided by the vehicle at the time that a diagnostic
+ * troubleshooting code (DTC) was recorded by the vehicle.
+ *
+ * VehiclePropConfig
+ * configArray[0] : number of vendor-specific integer-valued sensors
+ * that can be returned in a frame.
+ * configArray[1] : number of vendor-specific float-valued sensors
+ * that can be returned in a frame.
+ *
+ * A get of this property must take the following form:
+ * int64Values[0]: timestamp of the freeze frame to retrieve.
+ * Valid timestamps are given by OBD2_DTC_INFO.
+ *
+ * The values are to be interpreted as follows:
+ * the indices defined in Obd2IntegerSensorIndex are to be used to
+ * read from int32Values;
+ * the indices defined in Obd2FloatSensorIndex are to be used to
+ * read from floatValues;
+ * the elements of bytes are to be interpreted as a bitmask, such that
+ * the bits 0 thru the integer value of
+ * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0]
+ * are 1 if the corresponding index is a valid sensor index whose value can
+ * be read in the returned int32Values vector, 0 otherwise.
+ * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru
+ * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1]
+ * are 1 if the corresponding index is a valid sensor index whose value
+ * can be read in the returned floatValues vector, 0 otherwise.
+ * stringValue is the DTC that caused this freeze frame to be recorded.
+ *
+ * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and
+ * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping
+ * is only valid if the corresponding bits in the bytes vector are set to 1,
+ * and a possible valid stringValue is "P0176" to indicate a malfunction
+ * of the fuel composition sensor circuit.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ OBD2_FREEZE_FRAME = (
+ 0x0D01
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:COMPLEX
+ | VehicleArea:GLOBAL),
+
+ /*
+ * OBD2 Freeze Frame Information
+ *
+ * This property describes the current freeze frames stored in vehicle
+ * memory and available for retrieval via OBD2_FREEZE_FRAME.
+ *
+ * The values are to be interpreted as follows:
+ * each element of int64Values is the timestamp at which a a fault code
+ * has been detected and the corresponding freeze frame stored, and each
+ * such element can be used as the key to OBD2_FREEZE_FRAME to retrieve
+ * the corresponding freeze frame.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ
+ */
+ OBD2_FREEZE_FRAME_INFO = (
+ 0x0D02
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:COMPLEX
+ | VehicleArea:GLOBAL),
+
+ /*
+ * OBD2 Freeze Frame Clear
+ *
+ * This property allows deletion of any of the freeze frames stored in
+ * vehicle memory, as described by OBD2_DTC_INFO.
+ *
+ * A set of this property is to be interpreted as follows:
+ * if int64Values contains no elements, then all DTCs stored will be cleared;
+ * if int64Values contains one or more elements, then DTCs at the timestamps
+ * stored in int64Values will be cleared, and the others not cleared, except
+ * the memory will be compacted so that all remaining DTCs are stored
+ * contiguously.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:WRITE
+ */
+ OBD2_FREEZE_FRAME_CLEAR = (
+ 0x0D03
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:COMPLEX
+ | VehicleArea:GLOBAL),
+
+ /*
+ * Vehicle Maps Service (VMS) message
+ *
+ * This property uses COMPLEX data to communicate vms messages.
+ *
+ * Its contents are to be interpreted as follows:
+ * the indices defined in VmsMessageIntegerValuesIndex are to be used to
+ * read from int32Values;
+ * bytes is a serialized VMS message as defined in the vms protocol
+ * which is opaque to the framework;
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ VEHICLE_MAP_SERVICE = (
+ 0x0C00
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:COMPLEX
+ | VehicleArea:GLOBAL),
+};
+
+/* The status of a fuel system as described by the OBD2 specification. */
+enum FuelSystemStatus : int32_t {
+ OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1,
+
+ CLOSED_LOOP = 2,
+
+ OPEN_ENGINE_LOAD_OR_DECELERATION = 4,
+
+ OPEN_SYSTEM_FAILURE = 8,
+
+ CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16,
+};
+
+/* Defines which ignition monitors are available to be read. */
+enum IgnitionMonitorKind : int32_t {
+ SPARK = 0,
+
+ COMPRESSION = 1,
+};
+
+/* These ignition monitors are common to both SPARK and COMPRESSION. */
+enum CommonIgnitionMonitors : int32_t {
+ COMPONENTS_AVAILABLE = 0x1 << 0,
+ COMPONENTS_INCOMPLETE = 0x1 << 1,
+
+ FUEL_SYSTEM_AVAILABLE = 0x1 << 2,
+ FUEL_SYSTEM_INCOMPLETE = 0x1 << 3,
+
+ MISFIRE_AVAILABLE = 0x1 << 4,
+ MISFIRE_INCOMPLETE = 0x1 << 5,
+};
+
+/* Ignition monitors available for SPARK vehicles. */
+enum SparkIgnitionMonitors : CommonIgnitionMonitors {
+ EGR_AVAILABLE = 0x1 << 6,
+ EGR_INCOMPLETE = 0x1 << 7,
+
+ OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8,
+ OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9,
+
+ OXYGEN_SENSOR_AVAILABLE = 0x1 << 10,
+ OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11,
+
+ AC_REFRIGERANT_AVAILABLE = 0x1 << 12,
+ AC_REFRIGERANT_INCOMPLETE = 0x1 << 13,
+
+ SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14,
+ SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15,
+
+ EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16,
+ EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17,
+
+ HEATED_CATALYST_AVAILABLE = 0x1 << 18,
+ HEATED_CATALYST_INCOMPLETE = 0x1 << 19,
+
+ CATALYST_AVAILABLE = 0x1 << 20,
+ CATALYST_INCOMPLETE = 0x1 << 21,
+};
+
+/* Ignition monitors only available for COMPRESSION vehicles. */
+enum CompressionIgnitionMonitors : CommonIgnitionMonitors {
+ EGR_OR_VVT_AVAILABLE = 0x1 << 6,
+ EGR_OR_VVT_INCOMPLETE = 0x1 << 7,
+
+ PM_FILTER_AVAILABLE = 0x1 << 8,
+ PM_FILTER_INCOMPLETE = 0x1 << 9,
+
+ EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10,
+ EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11,
+
+ BOOST_PRESSURE_AVAILABLE = 0x1 << 12,
+ BOOST_PRESSURE_INCOMPLETE = 0x1 << 13,
+
+ NOx_SCR__AVAILABLE = 0x1 << 14,
+ NOx_SCR_INCOMPLETE = 0x1 << 15,
+
+ NMHC_CATALYST_AVAILABLE = 0x1 << 16,
+ NMHC_CATALYST_INCOMPLETE = 0x1 << 17,
+};
+
+enum SecondaryAirStatus : int32_t {
+ UPSTREAM = 1,
+
+ DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2,
+
+ FROM_OUTSIDE_OR_OFF = 4,
+
+ PUMP_ON_FOR_DIAGNOSTICS = 8,
+};
+
+enum FuelType : int32_t {
+ NOT_AVAILABLE = 0,
+
+ GASOLINE = 1,
+
+ METHANOL = 2,
+
+ ETHANOL = 3,
+
+ DIESEL = 4,
+
+ LPG = 5,
+
+ CNG = 6,
+
+ PROPANE = 7,
+
+ ELECTRIC = 8,
+
+ BIFUEL_RUNNING_GASOLINE = 9,
+
+ BIFUEL_RUNNING_METHANOL = 10,
+
+ BIFUEL_RUNNING_ETHANOL = 11,
+
+ BIFUEL_RUNNING_LPG = 12,
+
+ BIFUEL_RUNNING_CNG = 13,
+
+ BIFUEL_RUNNING_PROPANE = 14,
+
+ BIFUEL_RUNNING_ELECTRIC = 15,
+
+ BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16,
+
+ HYBRID_GASOLINE = 17,
+
+ HYBRID_ETHANOL = 18,
+
+ HYBRID_DIESEL = 19,
+
+ HYBRID_ELECTRIC = 20,
+
+ HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21,
+
+ HYBRID_REGENERATIVE = 22,
+
+ BIFUEL_RUNNING_DIESEL = 23,
+};
+
+/*
+ * This enum provides the canonical mapping for sensor properties that have an integer value.
+ * The ordering of the values is taken from the OBD2 specification.
+ * Some of the properties are represented as an integer mapping to another enum. In those cases
+ * expect a comment by the property definition describing the enum to look at for the mapping.
+ * Any value greater than the last reserved index is available to vendors to map their extensions.
+ */
+enum Obd2IntegerSensorIndex : int32_t {
+ /* refer to FuelSystemStatus for a description of this value. */
+ FUEL_SYSTEM_STATUS = 0,
+
+ MALFUNCTION_INDICATOR_LIGHT_ON = 1,
+
+ /* refer to IgnitionMonitorKind for a description of this value. */
+ IGNITION_MONITORS_SUPPORTED = 2,
+
+ /*
+ * The value of this sensor is a bitmask that specifies whether ignition-specific
+ * tests are available and whether they are complete. The semantics of the individual
+ * bits in this value are given by, respectively, SparkIgnitionMonitors and
+ * CompressionIgnitionMonitors depending on the value of IGNITION_MONITORS_SUPPORTED.
+ */
+ IGNITION_SPECIFIC_MONITORS = 3,
+
+ INTAKE_AIR_TEMPERATURE = 4,
+
+ /* refer to SecondaryAirStatus for a description of this value. */
+ COMMANDED_SECONDARY_AIR_STATUS = 5,
+
+ NUM_OXYGEN_SENSORS_PRESENT = 6,
+
+ RUNTIME_SINCE_ENGINE_START = 7,
+
+ DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8,
+
+ WARMUPS_SINCE_CODES_CLEARED = 9,
+
+ DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10,
+
+ ABSOLUTE_BAROMETRIC_PRESSURE = 11,
+
+ CONTROL_MODULE_VOLTAGE = 12,
+
+ AMBIENT_AIR_TEMPERATURE = 13,
+
+ TIME_WITH_MALFUNCTION_LIGHT_ON = 14,
+
+ TIME_SINCE_TROUBLE_CODES_CLEARED = 15,
+
+ MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16,
+
+ MAX_OXYGEN_SENSOR_VOLTAGE = 17,
+
+ MAX_OXYGEN_SENSOR_CURRENT = 18,
+
+ MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19,
+
+ MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20,
+
+ /* refer to FuelType for a description of this value. */
+ FUEL_TYPE = 21,
+
+ FUEL_RAIL_ABSOLUTE_PRESSURE = 22,
+
+ ENGINE_OIL_TEMPERATURE = 23,
+
+ DRIVER_DEMAND_PERCENT_TORQUE = 24,
+
+ ENGINE_ACTUAL_PERCENT_TORQUE = 25,
+
+ ENGINE_REFERENCE_PERCENT_TORQUE = 26,
+
+ ENGINE_PERCENT_TORQUE_DATA_IDLE = 27,
+
+ ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28,
+
+ ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29,
+
+ ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30,
+
+ ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31,
+
+ LAST_SYSTEM_INDEX = ENGINE_PERCENT_TORQUE_DATA_POINT4,
+};
+
+/*
+ * This enum provides the canonical mapping for sensor properties that have a floating-point value.
+ * The ordering of the values is taken from the OBD2 specification.
+ * Any value greater than the last reserved index is available to vendors to map their extensions.
+ */
+enum Obd2FloatSensorIndex : int32_t {
+ CALCULATED_ENGINE_LOAD = 0,
+
+ ENGINE_COOLANT_TEMPERATURE = 1,
+
+ SHORT_TERM_FUEL_TRIM_BANK1 = 2,
+
+ LONG_TERM_FUEL_TRIM_BANK1 = 3,
+
+ SHORT_TERM_FUEL_TRIM_BANK2 = 4,
+
+ LONG_TERM_FUEL_TRIM_BANK2 = 5,
+
+ FUEL_PRESSURE = 6,
+
+ INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7,
+
+ ENGINE_RPM = 8,
+
+ VEHICLE_SPEED = 9,
+
+ TIMING_ADVANCE = 10,
+
+ MAF_AIR_FLOW_RATE = 11,
+
+ THROTTLE_POSITION = 12,
+
+ OXYGEN_SENSOR1_VOLTAGE = 13,
+
+ OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14,
+
+ OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15,
+
+ OXYGEN_SENSOR2_VOLTAGE = 16,
+
+ OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17,
+
+ OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18,
+
+ OXYGEN_SENSOR3_VOLTAGE = 19,
+
+ OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20,
+
+ OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21,
+
+ OXYGEN_SENSOR4_VOLTAGE = 22,
+
+ OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23,
+
+ OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24,
+
+ OXYGEN_SENSOR5_VOLTAGE = 25,
+
+ OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26,
+
+ OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27,
+
+ OXYGEN_SENSOR6_VOLTAGE = 28,
+
+ OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29,
+
+ OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30,
+
+ OXYGEN_SENSOR7_VOLTAGE = 31,
+
+ OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32,
+
+ OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33,
+
+ OXYGEN_SENSOR8_VOLTAGE = 34,
+
+ OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35,
+
+ OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36,
+
+ FUEL_RAIL_PRESSURE = 37,
+
+ FUEL_RAIL_GAUGE_PRESSURE = 38,
+
+ COMMANDED_EXHAUST_GAS_RECIRCULATION = 39,
+
+ EXHAUST_GAS_RECIRCULATION_ERROR = 40,
+
+ COMMANDED_EVAPORATIVE_PURGE = 41,
+
+ FUEL_TANK_LEVEL_INPUT = 42,
+
+ EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43,
+
+ CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44,
+
+ CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45,
+
+ CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46,
+
+ CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47,
+
+ ABSOLUTE_LOAD_VALUE = 48,
+
+ FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49,
+
+ RELATIVE_THROTTLE_POSITION = 50,
+
+ ABSOLUTE_THROTTLE_POSITION_B = 51,
+
+ ABSOLUTE_THROTTLE_POSITION_C = 52,
+
+ ACCELERATOR_PEDAL_POSITION_D = 53,
+
+ ACCELERATOR_PEDAL_POSITION_E = 54,
+
+ ACCELERATOR_PEDAL_POSITION_F = 55,
+
+ COMMANDED_THROTTLE_ACTUATOR = 56,
+
+ ETHANOL_FUEL_PERCENTAGE = 57,
+
+ ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58,
+
+ SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59,
+
+ SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60,
+
+ SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61,
+
+ SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62,
+
+ LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63,
+
+ LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64,
+
+ LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65,
+
+ LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66,
+
+ RELATIVE_ACCELERATOR_PEDAL_POSITION = 67,
+
+ HYBRID_BATTERY_PACK_REMAINING_LIFE = 68,
+
+ FUEL_INJECTION_TIMING = 69,
+
+ ENGINE_FUEL_RATE = 70,
+
+ LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE,
+};
+
+/*
+ * This enum lists the types of supported VMS messages.
+ */
+enum VmsMessageType : int32_t {
+ /* A client subscribes to a layer. */
+ SUBSCRIBE = 1,
+
+ /* A client unsubscribes from a layer. */
+ UNSUBSCRIBE = 2,
+
+ /* A client publishes a data packet. */
+ DATA = 3,
+};
+
+/*
+ * This enum provides the canonical mapping for VMS properties that have an
+ * integer value.
+ */
+enum VmsMessageIntegerValuesIndex : int32_t {
+ /* The message type as enumerated by VmsMessageType enum. */
+ VMS_MESSAGE_TYPE = 0,
+
+ /* The layer ID as defined in the vms protocol. */
+ VMS_LAYER_ID = 1,
+
+ /* The version of the VMS layer. */
+ VMS_LAYER_VERSION = 2,
+
+ /* The number of bytes in the payload */
+ VMS_PAYLOAD_SIZE_BYTES = 3,
+};
diff --git a/biometrics/Android.bp b/biometrics/Android.bp
new file mode 100644
index 0000000..c87e3af
--- /dev/null
+++ b/biometrics/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "fingerprint/2.1",
+ "fingerprint/2.1/vts/functional",
+]
diff --git a/biometrics/fingerprint/2.1/Android.bp b/biometrics/fingerprint/2.1/Android.bp
new file mode 100644
index 0000000..586e1b3
--- /dev/null
+++ b/biometrics/fingerprint/2.1/Android.bp
@@ -0,0 +1,69 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.biometrics.fingerprint@2.1_hal",
+ srcs: [
+ "types.hal",
+ "IBiometricsFingerprint.hal",
+ "IBiometricsFingerprintClientCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.biometrics.fingerprint@2.1_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.biometrics.fingerprint@2.1",
+ srcs: [
+ ":android.hardware.biometrics.fingerprint@2.1_hal",
+ ],
+ out: [
+ "android/hardware/biometrics/fingerprint/2.1/types.cpp",
+ "android/hardware/biometrics/fingerprint/2.1/BiometricsFingerprintAll.cpp",
+ "android/hardware/biometrics/fingerprint/2.1/BiometricsFingerprintClientCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.biometrics.fingerprint@2.1_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.biometrics.fingerprint@2.1",
+ srcs: [
+ ":android.hardware.biometrics.fingerprint@2.1_hal",
+ ],
+ out: [
+ "android/hardware/biometrics/fingerprint/2.1/types.h",
+ "android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h",
+ "android/hardware/biometrics/fingerprint/2.1/IHwBiometricsFingerprint.h",
+ "android/hardware/biometrics/fingerprint/2.1/BnHwBiometricsFingerprint.h",
+ "android/hardware/biometrics/fingerprint/2.1/BpHwBiometricsFingerprint.h",
+ "android/hardware/biometrics/fingerprint/2.1/BsBiometricsFingerprint.h",
+ "android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h",
+ "android/hardware/biometrics/fingerprint/2.1/IHwBiometricsFingerprintClientCallback.h",
+ "android/hardware/biometrics/fingerprint/2.1/BnHwBiometricsFingerprintClientCallback.h",
+ "android/hardware/biometrics/fingerprint/2.1/BpHwBiometricsFingerprintClientCallback.h",
+ "android/hardware/biometrics/fingerprint/2.1/BsBiometricsFingerprintClientCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.biometrics.fingerprint@2.1",
+ generated_sources: ["android.hardware.biometrics.fingerprint@2.1_genc++"],
+ generated_headers: ["android.hardware.biometrics.fingerprint@2.1_genc++_headers"],
+ export_generated_headers: ["android.hardware.biometrics.fingerprint@2.1_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/biometrics/fingerprint/2.1/Android.mk b/biometrics/fingerprint/2.1/Android.mk
new file mode 100644
index 0000000..567b38a
--- /dev/null
+++ b/biometrics/fingerprint/2.1/Android.mk
@@ -0,0 +1,468 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (FingerprintAcquired)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquired.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquired
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintAcquiredInfo)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquiredInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquiredInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintAuthenticated)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAuthenticated.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAuthenticated
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintEnroll)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintEnroll.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintEnroll
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintError)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintError.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintError
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintFingerId)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintFingerId.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintFingerId
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintIterator)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintIterator.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintIterator
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintMsgType)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintMsgType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintMsgType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (RequestStatus)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/RequestStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.RequestStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IBiometricsFingerprint.hal
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprint.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
+
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprint.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IBiometricsFingerprintClientCallback.hal
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprintClientCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback
+
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (FingerprintAcquired)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquired.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquired
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintAcquiredInfo)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquiredInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquiredInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintAuthenticated)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAuthenticated.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintAuthenticated
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintEnroll)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintEnroll.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintEnroll
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintError)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintError.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintError
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintFingerId)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintFingerId.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintFingerId
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintIterator)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintIterator.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintIterator
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (FingerprintMsgType)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintMsgType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.FingerprintMsgType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (RequestStatus)
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/RequestStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::types.RequestStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IBiometricsFingerprint.hal
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprint.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
+
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprint.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IBiometricsFingerprintClientCallback.hal
+#
+GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprintClientCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback
+
+$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..0b92848
--- /dev/null
+++ b/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 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.biometrics.fingerprint@2.1;
+
+import IBiometricsFingerprintClientCallback;
+
+interface IBiometricsFingerprint {
+ /*
+ * Set notification callback:
+ * Registers a user function that must receive notifications from the HAL
+ * This call must block if the HAL state machine is in busy state until HAL
+ * leaves the busy state.
+ *
+ * @return deviceId is a unique handle for this fingerprint device
+ */
+ @callflow(next={"setActiveGroup"})
+ @entry
+ setNotify(IBiometricsFingerprintClientCallback clientCallback)
+ generates (uint64_t deviceId);
+
+ /*
+ * Fingerprint pre-enroll enroll request:
+ * Generates a unique token to upper layers to indicate the start of
+ * an enrollment transaction. pre-enroll and post-enroll specify
+ * a pin/password cleared time window where enrollment is allowed.
+ * Pre-enroll only generates a challenge, a full hardwareAuthToken is
+ * generated by trustzone after verifying a pin/password/swipe. This is to
+ * ensure adding a new fingerprint template was preceded by some kind of
+ * credential confirmation (e.g. device password).
+ *
+ * @return 0 if function failed, a uint64_t of challenge otherwise.
+ */
+ @callflow(next={"enroll", "postEnroll"})
+ preEnroll() generates (uint64_t authChallenge);
+
+ /*
+ * Fingerprint enroll request:
+ * Switches the HAL state machine to collect and store a new fingerprint
+ * template. Switches back as soon as enroll is complete, signalled by
+ * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING &&
+ * fingerprintMsg.data.enroll.samplesRemaining == 0)
+ * or after timeoutSec seconds.
+ * The fingerprint template must be assigned to the group gid.
+ *
+ * @param hat a valid Hardware Authentication Token (HAT), generated
+ * as a result of a preEnroll() call.
+ * @param gid a framework defined fingerprint set (group) id.
+ * @param timeoutSec a timeout in seconds.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ *
+ * A notify() function may be called with a more detailed error structure.
+ */
+ @callflow(next={"cancel", "enroll", "postEnroll", "remove"})
+ enroll(uint8_t[69] hat, uint32_t gid, uint32_t timeoutSec)
+ generates (RequestStatus debugErrno);
+
+ /*
+ * Finishes the enroll operation and invalidates the preEnroll() generated
+ * challenge. This must be called at the end of a multi-finger enrollment
+ * session to indicate that no more fingers may be added.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"authenticate", "setActiveGroup", "enumerate", "remove"})
+ postEnroll() generates (RequestStatus debugErrno);
+
+ /*
+ * getAuthenticatorId:
+ * Returns a token associated with the current fingerprint set. This value
+ * must change whenever a new fingerprint is enrolled, thus creating a new
+ * fingerprint set.
+ *
+ * @return getAuthenticatorIdRet current authenticator id, 0 if function
+ * failed.
+ */
+ @callflow(next={"authenticate"})
+ getAuthenticatorId() generates (uint64_t AuthenticatorId);
+
+ /*
+ * Cancel pending enroll or authenticate, sending FINGERPRINT_ERROR_CANCELED
+ * to all running clients. Switches the HAL state machine back to the idle
+ * state. Unlike enrollDone() doesn't invalidate the preEnroll() challenge.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"authenticate", "enroll", "enumerate", "remove",
+ "setActiveGroup"})
+ cancel() generates (RequestStatus debugErrno);
+
+ /*
+ * Enumerate all the fingerprint templates found in the directory set by
+ * setActiveGroup():
+ * For each template found a notify() must be called with:
+ * fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENUMERATED
+ * fingerprintMsg.data.enumerated.finger indicating a template id
+ * fingerprintMsg.data.enumerated.remainingTemplates indicating how many more
+ * enumeration messages to expect.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"remove", "enroll", "authenticate", "setActiveGroup"})
+ enumerate() generates (RequestStatus debugErrno);
+
+ /*
+ * Fingerprint remove request:
+ * Deletes fingerprint template(s).
+ * Works only within the path set by setActiveGroup().
+ * For each template found a notify() must be called with:
+ * fingerprintMsg.type == FINGERPRINT_TEMPLATE_REMOVED
+ * fingerprintMsg.data.removed.finger indicating the template id deleted
+ * fingerprintMsg.data.removed.remainingTemplates indicating how many more
+ * templates must be deleted by this operation.
+ *
+ * @param gid group id must match the last group set by setActiveGroup().
+ * @param fid template id to delete or 0 to delete all templates within the
+ * current group.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId",
+ "setActiveGroup"})
+ remove(uint32_t gid, uint32_t fid) generates (RequestStatus debugErrno);
+
+ /*
+ * Restricts the HAL operation to a set of fingerprints belonging to a group
+ * provided. The caller must provide a path to a storage location within the
+ * user's data directory.
+ *
+ * @param gid the fingerprint group (set) id.
+ * @param storePath filesystem path to the template storage directory.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"authenticate", "preEnroll", "enumerate", "remove"})
+ setActiveGroup(uint32_t gid, string storePath)
+ generates (RequestStatus debugErrno);
+
+ /*
+ * Authenticates an operation identified by operationId
+ *
+ * @param operationId operation id.
+ * @param gid fingerprint group id.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ @callflow(next={"cancel", "preEnroll", "remove"})
+ authenticate(uint64_t operationId, uint32_t gid)
+ generates (RequestStatus debugErrno);
+};
diff --git a/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal
new file mode 100644
index 0000000..d913cf1
--- /dev/null
+++ b/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.biometrics.fingerprint@2.1;
+
+/* This HAL interface communicates asynchronous results from the
+ fingerprint driver in response to user actions on the fingerprint sensor
+*/
+interface IBiometricsFingerprintClientCallback {
+ /**
+ * Sent when one enrollment step is complete.
+ * @param deviceId the instance of this fingerprint device
+ * @param fingerId the fingerprint templetate being enrolled
+ * @param groupId the groupid for the template being enrolled
+ * @param remaining the number of remaining steps before enrolllment is complete
+ */
+ oneway onEnrollResult(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining);
+
+ /**
+ * Sent when a fingerprint image is acquired by the sensor
+ * @param deviceId the instance of this fingerprint device
+ * @param acquiredInfo a message about the quality of the acquired image
+ * @param vendorCode a vendor-specific message about the quality of the image. Only
+ * valid when acquiredInfo == ACQUIRED_VENDOR
+ */
+ oneway onAcquired(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo, int32_t vendorCode);
+
+ /**
+ * Sent when a fingerprint is authenticated
+ * @param deviceId the instance of this fingerprint device
+ * @param fingerId the fingerprint templetate that was authenticated
+ * @param groupId the groupid for the template that was authenticated
+ * @param token the hardware authentication token to pass to Keystore.addAuthToken()
+ */
+ oneway onAuthenticated(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, vec<uint8_t> token);
+
+ /**
+ * Sent when a fingerprint error occurs
+ * @param deviceId the instance of this fingerprint device
+ * @param error a message about the error that occurred
+ * @param vendorCode a vendor-speicifc error message. Only valid
+ * when error == ERROR_VENDOR
+ */
+ oneway onError(uint64_t deviceId, FingerprintError error, int32_t vendorCode);
+
+ /**
+ * Sent when one template is removed
+ * @param deviceId the instance of this fingerprint device
+ * @param fingerId the fingerprint templetate being removed
+ * @param groupId the groupid for the template being removed
+ * @param remaining the number of remaining templates that will be removed.
+ */
+ oneway onRemoved(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining);
+
+ /**
+ * Sent when one fingerprint template is enumerated
+ * @param deviceId the instance of this fingerprint device
+ * @param fingerId the fingerprint for this templetate
+ * @param groupId the groupid for this template
+ * @param remaining the number of remaining steps before enumeration is complete
+ */
+ oneway onEnumerate(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining);
+};
diff --git a/biometrics/fingerprint/2.1/default/Android.mk b/biometrics/fingerprint/2.1/default/Android.mk
new file mode 100644
index 0000000..3d06397
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-service
+LOCAL_INIT_RC := android.hardware.biometrics.fingerprint@2.1-service.rc
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ BiometricsFingerprint.cpp \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhardware \
+ libkeystore_binder \
+ libutils \
+ android.hardware.biometrics.fingerprint@2.1 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
new file mode 100644
index 0000000..5b00675
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#define LOG_TAG "android.hardware.biometrics.fingerprint@2.1-service"
+#define LOG_VERBOSE "android.hardware.biometrics.fingerprint@2.1-service"
+
+// For communication with Keystore binder interface
+#include <keystore/keystore.h> // for error codes
+#include <hardware/hw_auth_token.h>
+
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include "BiometricsFingerprint.h"
+
+#include <inttypes.h>
+
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+namespace V2_1 {
+namespace implementation {
+
+// Supported fingerprint HAL version
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1);
+
+using RequestStatus =
+ android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+
+BiometricsFingerprint *BiometricsFingerprint::sInstance = nullptr;
+
+BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr), mDevice(nullptr) {
+ sInstance = this; // keep track of the most recent instance
+ mDevice = openHal();
+ if (!mDevice) {
+ ALOGE("Can't open HAL module");
+ }
+}
+
+BiometricsFingerprint::~BiometricsFingerprint() {
+ ALOGV("~BiometricsFingerprint()");
+ if (mDevice == nullptr) {
+ ALOGE("No valid device");
+ return;
+ }
+ int err;
+ if (0 != (err = mDevice->common.close(
+ reinterpret_cast<hw_device_t*>(mDevice)))) {
+ ALOGE("Can't close fingerprint module, error: %d", err);
+ return;
+ }
+ mDevice = nullptr;
+}
+
+Return<RequestStatus> BiometricsFingerprint::ErrorFilter(int32_t error) {
+ switch(error) {
+ case 0: return RequestStatus::SYS_OK;
+ case -2: return RequestStatus::SYS_ENOENT;
+ case -4: return RequestStatus::SYS_EINTR;
+ case -5: return RequestStatus::SYS_EIO;
+ case -11: return RequestStatus::SYS_EAGAIN;
+ case -12: return RequestStatus::SYS_ENOMEM;
+ case -13: return RequestStatus::SYS_EACCES;
+ case -14: return RequestStatus::SYS_EFAULT;
+ case -16: return RequestStatus::SYS_EBUSY;
+ case -22: return RequestStatus::SYS_EINVAL;
+ case -28: return RequestStatus::SYS_ENOSPC;
+ case -110: return RequestStatus::SYS_ETIMEDOUT;
+ default:
+ ALOGE("An unknown error returned from fingerprint vendor library");
+ return RequestStatus::SYS_UNKNOWN;
+ }
+}
+
+// Translate from errors returned by traditional HAL (see fingerprint.h) to
+// HIDL-compliant FingerprintError.
+FingerprintError BiometricsFingerprint::VendorErrorFilter(int32_t error,
+ int32_t* vendorCode) {
+ *vendorCode = 0;
+ switch(error) {
+ case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+ return FingerprintError::ERROR_HW_UNAVAILABLE;
+ case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+ return FingerprintError::ERROR_UNABLE_TO_PROCESS;
+ case FINGERPRINT_ERROR_TIMEOUT:
+ return FingerprintError::ERROR_TIMEOUT;
+ case FINGERPRINT_ERROR_NO_SPACE:
+ return FingerprintError::ERROR_NO_SPACE;
+ case FINGERPRINT_ERROR_CANCELED:
+ return FingerprintError::ERROR_CANCELED;
+ case FINGERPRINT_ERROR_UNABLE_TO_REMOVE:
+ return FingerprintError::ERROR_UNABLE_TO_REMOVE;
+ case FINGERPRINT_ERROR_LOCKOUT:
+ return FingerprintError::ERROR_LOCKOUT;
+ default:
+ if (error >= FINGERPRINT_ERROR_VENDOR_BASE) {
+ // vendor specific code.
+ *vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE;
+ return FingerprintError::ERROR_VENDOR;
+ }
+ }
+ ALOGE("Unknown error from fingerprint vendor library: %d", error);
+ return FingerprintError::ERROR_UNABLE_TO_PROCESS;
+}
+
+// Translate acquired messages returned by traditional HAL (see fingerprint.h)
+// to HIDL-compliant FingerprintAcquiredInfo.
+FingerprintAcquiredInfo BiometricsFingerprint::VendorAcquiredFilter(
+ int32_t info, int32_t* vendorCode) {
+ *vendorCode = 0;
+ switch(info) {
+ case FINGERPRINT_ACQUIRED_GOOD:
+ return FingerprintAcquiredInfo::ACQUIRED_GOOD;
+ case FINGERPRINT_ACQUIRED_PARTIAL:
+ return FingerprintAcquiredInfo::ACQUIRED_PARTIAL;
+ case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+ return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT;
+ case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+ return FingerprintAcquiredInfo::ACQUIRED_IMAGER_DIRTY;
+ case FINGERPRINT_ACQUIRED_TOO_SLOW:
+ return FingerprintAcquiredInfo::ACQUIRED_TOO_SLOW;
+ case FINGERPRINT_ACQUIRED_TOO_FAST:
+ return FingerprintAcquiredInfo::ACQUIRED_TOO_FAST;
+ default:
+ if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+ // vendor specific code.
+ *vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+ return FingerprintAcquiredInfo::ACQUIRED_VENDOR;
+ }
+ }
+ ALOGE("Unknown acquiredmsg from fingerprint vendor library: %d", info);
+ return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT;
+}
+
+Return<uint64_t> BiometricsFingerprint::setNotify(
+ const sp<IBiometricsFingerprintClientCallback>& clientCallback) {
+ mClientCallback = clientCallback;
+ // This is here because HAL 2.1 doesn't have a way to propagate a
+ // unique token for its driver. Subsequent versions should send a unique
+ // token for each call to setNotify(). This is fine as long as there's only
+ // one fingerprint device on the platform.
+ return reinterpret_cast<uint64_t>(mDevice);
+}
+
+Return<uint64_t> BiometricsFingerprint::preEnroll() {
+ return mDevice->pre_enroll(mDevice);
+}
+
+Return<RequestStatus> BiometricsFingerprint::enroll(const hidl_array<uint8_t, 69>& hat,
+ uint32_t gid, uint32_t timeoutSec) {
+ const hw_auth_token_t* authToken =
+ reinterpret_cast<const hw_auth_token_t*>(hat.data());
+ return ErrorFilter(mDevice->enroll(mDevice, authToken, gid, timeoutSec));
+}
+
+Return<RequestStatus> BiometricsFingerprint::postEnroll() {
+ return ErrorFilter(mDevice->post_enroll(mDevice));
+}
+
+Return<uint64_t> BiometricsFingerprint::getAuthenticatorId() {
+ return mDevice->get_authenticator_id(mDevice);
+}
+
+Return<RequestStatus> BiometricsFingerprint::cancel() {
+ return ErrorFilter(mDevice->cancel(mDevice));
+}
+
+Return<RequestStatus> BiometricsFingerprint::enumerate() {
+ return ErrorFilter(mDevice->enumerate(mDevice));
+}
+
+Return<RequestStatus> BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) {
+ return ErrorFilter(mDevice->remove(mDevice, gid, fid));
+}
+
+Return<RequestStatus> BiometricsFingerprint::setActiveGroup(uint32_t gid,
+ const hidl_string& storePath) {
+ if (storePath.size() >= PATH_MAX || storePath.size() <= 0) {
+ ALOGE("Bad path length: %zd", storePath.size());
+ }
+ return ErrorFilter(mDevice->set_active_group(mDevice, gid,
+ storePath.c_str()));
+}
+
+Return<RequestStatus> BiometricsFingerprint::authenticate(uint64_t operationId,
+ uint32_t gid) {
+ return ErrorFilter(mDevice->authenticate(mDevice, operationId, gid));
+}
+
+IBiometricsFingerprint* BiometricsFingerprint::getInstance() {
+ if (!sInstance) {
+ sInstance = new BiometricsFingerprint();
+ }
+ return sInstance;
+}
+
+fingerprint_device_t* BiometricsFingerprint::openHal() {
+ int err;
+ const hw_module_t *hw_mdl = nullptr;
+ ALOGD("Opening fingerprint hal library...");
+ if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) {
+ ALOGE("Can't open fingerprint HW Module, error: %d", err);
+ return nullptr;
+ }
+
+ if (hw_mdl == nullptr) {
+ ALOGE("No valid fingerprint module");
+ return nullptr;
+ }
+
+ fingerprint_module_t const *module =
+ reinterpret_cast<const fingerprint_module_t*>(hw_mdl);
+ if (module->common.methods->open == nullptr) {
+ ALOGE("No valid open method");
+ return nullptr;
+ }
+
+ hw_device_t *device = nullptr;
+
+ if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) {
+ ALOGE("Can't open fingerprint methods, error: %d", err);
+ return nullptr;
+ }
+
+ if (kVersion != device->version) {
+ // enforce version on new devices because of HIDL@2.1 translation layer
+ ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+ return nullptr;
+ }
+
+ fingerprint_device_t* fp_device =
+ reinterpret_cast<fingerprint_device_t*>(device);
+
+ if (0 != (err =
+ fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) {
+ ALOGE("Can't register fingerprint module callback, error: %d", err);
+ return nullptr;
+ }
+
+ return fp_device;
+}
+
+void BiometricsFingerprint::notify(const fingerprint_msg_t *msg) {
+ BiometricsFingerprint* thisPtr = static_cast<BiometricsFingerprint*>(
+ BiometricsFingerprint::getInstance());
+ if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) {
+ ALOGE("Receiving callbacks before the client callback is registered.");
+ return;
+ }
+ const uint64_t devId = reinterpret_cast<uint64_t>(thisPtr->mDevice);
+ switch (msg->type) {
+ case FINGERPRINT_ERROR: {
+ int32_t vendorCode = 0;
+ FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode);
+ if (!thisPtr->mClientCallback->onError(devId, result, vendorCode).isOk()) {
+ ALOGE("failed to invoke fingerprint onError callback");
+ }
+ }
+ break;
+ case FINGERPRINT_ACQUIRED: {
+ int32_t vendorCode = 0;
+ FingerprintAcquiredInfo result =
+ VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode);
+ if (!thisPtr->mClientCallback->onAcquired(devId, result, vendorCode).isOk()) {
+ ALOGE("failed to invoke fingerprint onAcquired callback");
+ }
+ }
+ break;
+ case FINGERPRINT_TEMPLATE_ENROLLING:
+ if (!thisPtr->mClientCallback->onEnrollResult(devId,
+ msg->data.enroll.finger.fid,
+ msg->data.enroll.finger.gid,
+ msg->data.enroll.samples_remaining).isOk()) {
+ ALOGE("failed to invoke fingerprint onEnrollResult callback");
+ }
+ break;
+ case FINGERPRINT_TEMPLATE_REMOVED:
+ if (!thisPtr->mClientCallback->onRemoved(devId,
+ msg->data.removed.finger.fid,
+ msg->data.removed.finger.gid,
+ msg->data.removed.remaining_templates).isOk()) {
+ ALOGE("failed to invoke fingerprint onRemoved callback");
+ }
+ break;
+ case FINGERPRINT_AUTHENTICATED:
+ if (msg->data.authenticated.finger.fid != 0) {
+ const uint8_t* hat =
+ reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
+ const hidl_vec<uint8_t> token(
+ std::vector<uint8_t>(hat, hat + sizeof(msg->data.authenticated.hat)));
+ if (!thisPtr->mClientCallback->onAuthenticated(devId,
+ msg->data.authenticated.finger.fid,
+ msg->data.authenticated.finger.gid,
+ token).isOk()) {
+ ALOGE("failed to invoke fingerprint onAuthenticated callback");
+ }
+ } else {
+ // Not a recognized fingerprint
+ if (!thisPtr->mClientCallback->onAuthenticated(devId,
+ msg->data.authenticated.finger.fid,
+ msg->data.authenticated.finger.gid,
+ hidl_vec<uint8_t>()).isOk()) {
+ ALOGE("failed to invoke fingerprint onAuthenticated callback");
+ }
+ }
+ break;
+ case FINGERPRINT_TEMPLATE_ENUMERATING:
+ if (!thisPtr->mClientCallback->onEnumerate(devId,
+ msg->data.enumerated.finger.fid,
+ msg->data.enumerated.finger.gid,
+ msg->data.enumerated.remaining_templates).isOk()) {
+ ALOGE("failed to invoke fingerprint onEnumerate callback");
+ }
+ break;
+ }
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h
new file mode 100644
index 0000000..5923c84
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H
+#define ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H
+
+#include <log/log.h>
+#include <android/log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
+using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using ::android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct BiometricsFingerprint : public IBiometricsFingerprint {
+public:
+ BiometricsFingerprint();
+ ~BiometricsFingerprint();
+
+ // Method to wrap legacy HAL with BiometricsFingerprint class
+ static IBiometricsFingerprint* getInstance();
+
+ // Methods from ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint follow.
+ Return<uint64_t> setNotify(const sp<IBiometricsFingerprintClientCallback>& clientCallback) override;
+ Return<uint64_t> preEnroll() override;
+ Return<RequestStatus> enroll(const hidl_array<uint8_t, 69>& hat, uint32_t gid, uint32_t timeoutSec) override;
+ Return<RequestStatus> postEnroll() override;
+ Return<uint64_t> getAuthenticatorId() override;
+ Return<RequestStatus> cancel() override;
+ Return<RequestStatus> enumerate() override;
+ Return<RequestStatus> remove(uint32_t gid, uint32_t fid) override;
+ Return<RequestStatus> setActiveGroup(uint32_t gid, const hidl_string& storePath) override;
+ Return<RequestStatus> authenticate(uint64_t operationId, uint32_t gid) override;
+
+private:
+ static fingerprint_device_t* openHal();
+ static void notify(const fingerprint_msg_t *msg); /* Static callback for legacy HAL implementation */
+ static Return<RequestStatus> ErrorFilter(int32_t error);
+ static FingerprintError VendorErrorFilter(int32_t error, int32_t* vendorCode);
+ static FingerprintAcquiredInfo VendorAcquiredFilter(int32_t error, int32_t* vendorCode);
+ static BiometricsFingerprint* sInstance;
+
+ sp<IBiometricsFingerprintClientCallback> mClientCallback;
+ fingerprint_device_t *mDevice;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H
diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
new file mode 100644
index 0000000..aa767a6
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
@@ -0,0 +1,7 @@
+service fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.1-service
+ # "class hal" causes a race condition on some devices due to files created
+ # in /data. As a workaround, postpone startup until later in boot once
+ # /data is mounted.
+ class late_start
+ user system
+ group system input
diff --git a/biometrics/fingerprint/2.1/default/service.cpp b/biometrics/fingerprint/2.1/default/service.cpp
new file mode 100644
index 0000000..1697c07
--- /dev/null
+++ b/biometrics/fingerprint/2.1/default/service.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "android.hardware.biometrics.fingerprint@2.1-service"
+
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/types.h>
+#include "BiometricsFingerprint.h"
+
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
+using android::hardware::biometrics::fingerprint::V2_1::implementation::BiometricsFingerprint;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::sp;
+
+int main() {
+ android::sp<IBiometricsFingerprint> bio = BiometricsFingerprint::getInstance();
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ if (bio != nullptr) {
+ bio->registerAsService();
+ } else {
+ ALOGE("Can't create instance of BiometricsFingerprint, nullptr");
+ }
+
+ joinRpcThreadpool();
+
+ return 0; // should never get here
+}
diff --git a/biometrics/fingerprint/2.1/types.hal b/biometrics/fingerprint/2.1/types.hal
new file mode 100644
index 0000000..e389773
--- /dev/null
+++ b/biometrics/fingerprint/2.1/types.hal
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 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.biometrics.fingerprint@2.1;
+
+/*
+ * Request status indicates whether the request is accepted by the vendor
+ * implementation or not. These values are taken from the errno set,
+ * except for the SYS_UNKNOWN
+ */
+enum RequestStatus : int32_t {
+ SYS_UNKNOWN = 1,
+ SYS_OK = 0,
+ SYS_ENOENT = -2,
+ SYS_EINTR = -4,
+ SYS_EIO = -5,
+ SYS_EAGAIN = -11,
+ SYS_ENOMEM = -12,
+ SYS_EACCES = -13,
+ SYS_EFAULT = -14,
+ SYS_EBUSY = -16,
+ SYS_EINVAL = -22,
+ SYS_ENOSPC = -28,
+ SYS_ETIMEDOUT = -110,
+};
+
+/*
+ * Fingerprint errors are meant to tell the framework to terminate the current
+ * operation and ask for the user to correct the situation. These will almost
+ * always result in messaging and user interaction to correct the problem.
+ *
+ * For example, ERROR_CANCELED should follow any acquisition message that
+ * results in a situation where the current operation can't continue without
+ * user interaction. For example, if the sensor is dirty during enrollment and
+ * no further enrollment progress can be made, send ACQUIRED_IMAGER_DIRTY
+ * followed by ERROR_CANCELED.
+ */
+enum FingerprintError : int32_t {
+ /* Used for testing, no error returned */
+ ERROR_NO_ERROR = 0,
+ /* The hardware has an error that can't be resolved. */
+ ERROR_HW_UNAVAILABLE = 1,
+ /* Bad data; operation can't continue */
+ ERROR_UNABLE_TO_PROCESS = 2,
+ /* The operation has timed out waiting for user input. */
+ ERROR_TIMEOUT = 3,
+ /* No space available to store a template */
+ ERROR_NO_SPACE = 4,
+ /* The current operation has been canceled */
+ ERROR_CANCELED = 5,
+ /* Unable to remove a template */
+ ERROR_UNABLE_TO_REMOVE = 6,
+ /* The hardware is in lockout due to too many attempts */
+ ERROR_LOCKOUT = 7,
+ /* Vendor-specific error message */
+ ERROR_VENDOR = 8
+};
+
+/*
+ * Fingerprint acquisition info is meant as feedback for the current operation.
+ * Anything but ACQUIRED_GOOD must be shown to the user as feedback on how to
+ * take action on the current operation. For example, ACQUIRED_IMAGER_DIRTY may
+ * be used to tell the user to clean the sensor if it is detected to be dirty.
+ * If this causes the current operation to fail, an additional ERROR_CANCELED
+ * must be sent to stop the operation in progress (e.g. enrollment).
+ * In general, these messages will result in a "Try again" message.
+ */
+enum FingerprintAcquiredInfo : int32_t {
+ ACQUIRED_GOOD = 0,
+ /* sensor needs more data, i.e. longer swipe. */
+ ACQUIRED_PARTIAL = 1,
+ /* image doesn't contain enough detail for recognition*/
+ ACQUIRED_INSUFFICIENT = 2,
+ /* sensor needs to be cleaned */
+ ACQUIRED_IMAGER_DIRTY = 3,
+ /* mostly swipe-type sensors; not enough data collected */
+ ACQUIRED_TOO_SLOW = 4,
+ /* vendor-specific acquisition messages start here */
+ ACQUIRED_TOO_FAST = 5,
+ /* vendor-specific acquisition messages */
+ ACQUIRED_VENDOR = 6
+};
+
+struct FingerprintFingerId {
+ /* Group ID */
+ uint32_t gid;
+ /* Fingerprint template ID */
+ uint32_t fid;
+};
+
+struct FingerprintEnroll {
+ /* Template ID */
+ FingerprintFingerId finger;
+ /* samplesRemaining goes from N (no data collected, but N scans needed)
+ * to 0 (no more data is needed to build a template). */
+ uint32_t samplesRemaining;
+ /* Vendor specific message. Used for user guidance */
+ uint64_t msg;
+};
+
+struct FingerprintIterator {
+ /* Template ID */
+ FingerprintFingerId finger;
+ /* How many templates remain to iterate through */
+ uint32_t remainingTemplates;
+};
+
+typedef FingerprintIterator FingerprintEnumerated;
+typedef FingerprintIterator FingerprintRemoved;
+
+struct FingerprintAcquired {
+ /* information about the image */
+ FingerprintAcquiredInfo acquiredInfo;
+};
+
+struct FingerprintAuthenticated {
+ /* Matched template ID */
+ FingerprintFingerId finger;
+ /* Authentication result from the keymaster */
+ uint8_t[69] hat;
+};
+
+/* Run time type identification for the notify() call payload. */
+enum FingerprintMsgType : int32_t {
+ ERROR = -1,
+ ACQUIRED = 1,
+ TEMPLATE_ENROLLING = 3,
+ TEMPLATE_REMOVED = 4,
+ AUTHENTICATED = 5,
+ TEMPLATE_ENUMERATING = 6,
+};
+
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..27b7157
--- /dev/null
+++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalBiometricsFingerprintV2_1TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "libhidltransport",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.biometrics.fingerprint@2.1",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
+
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
new file mode 100644
index 0000000..cd38f2e
--- /dev/null
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "fingerprint_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+using android::Condition;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::Mutex;
+using android::sp;
+
+class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+
+protected:
+ class MyCallback : public IBiometricsFingerprintClientCallback {
+
+ // implement methods of IBiometricsFingerprintClientCallback
+ virtual Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t,
+ uint32_t) override {
+ callBackCalled();
+ return Return<void>();
+ }
+
+ virtual Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo,
+ int32_t) override {
+ callBackCalled();
+ return Return<void>();
+ }
+
+ virtual Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t,
+ const hidl_vec<uint8_t>&) override {
+ callBackCalled();
+ return Return<void>();
+ }
+
+ virtual Return<void> onError(uint64_t, FingerprintError error, int32_t)
+ override {
+ mTestCase->mErr = error;
+ callBackCalled();
+ return Return<void>();
+ }
+
+ virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t)
+ override {
+ callBackCalled();
+ return Return<void>();
+ }
+
+ virtual Return<void> onEnumerate(uint64_t, uint32_t, uint32_t,
+ uint32_t) override {
+ callBackCalled();
+ return Return<void>();
+ }
+
+ void callBackCalled () {
+ mTestCase->mCallbackCalled = true;
+ mTestCase->mCallbackCond.broadcast();
+ }
+
+ FingerprintHidlTest* mTestCase;
+ public:
+ MyCallback(FingerprintHidlTest* aTest) : mTestCase(aTest) {}
+ };
+
+ sp<MyCallback> mCallback;
+ bool mCallbackCalled;
+ Condition mCallbackCond;
+ FingerprintError mErr;
+ Mutex mLock;
+ sp<IBiometricsFingerprint> mService;
+ static const unsigned int kThresholdInSeconds = 3;
+
+ void clearErr () {
+ mErr = FingerprintError::ERROR_NO_ERROR;
+ }
+
+ // Timed callback mechanism. Will block up to kThresholdInSeconds,
+ // returning true if callback was invoked in that time frame.
+ bool waitForCallback(const unsigned int seconds = kThresholdInSeconds) {
+ nsecs_t reltime = seconds_to_nanoseconds(seconds);
+ Mutex::Autolock _l(mLock);
+ nsecs_t endTime = systemTime() + reltime;
+ while (!mCallbackCalled) {
+ if (reltime == 0) {
+ mCallbackCond.wait(mLock);
+ } else {
+ nsecs_t now = systemTime();
+ if (now > endTime) {
+ return false;
+ }
+ mCallbackCond.waitRelative(mLock, endTime - now);
+ }
+ }
+ return true;
+ }
+public:
+ FingerprintHidlTest (): mCallbackCalled(false) {}
+
+ virtual void SetUp() override {
+ mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>();
+
+ ASSERT_NE(mService, nullptr);
+ clearErr();
+
+ mCallback = new MyCallback(this);
+ // TODO: instantly fail any test that receives a death notification
+ }
+
+ virtual void TearDown() override {}
+};
+
+class FingerprintHidlEnvironment : public ::testing::Environment {
+public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+};
+
+// The service should be reachable.
+TEST_F(FingerprintHidlTest, ConnectTest) {
+ Return<uint64_t> rc = mService->setNotify(mCallback);
+ EXPECT_NE(rc, 0UL);
+}
+
+// Cancel should always return ERROR_CANCELED from any starting state including
+// the IDLE state.
+TEST_F(FingerprintHidlTest, CancelTest) {
+ Return<uint64_t> rc = mService->setNotify(mCallback);
+ EXPECT_NE(rc, 0UL);
+
+ Return<RequestStatus> res = mService->cancel();
+ // make sure callback was invoked within kThresholdInSeconds
+ EXPECT_EQ(true, waitForCallback());
+ // check that we were able to make an IPC request successfully
+ EXPECT_EQ(RequestStatus::SYS_OK, res);
+ // check error should be ERROR_CANCELED
+ EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr);
+}
+
+// A call to cancel should after any other method call should set the error
+// state to canceled.
+TEST_F(FingerprintHidlTest, AuthTest) {
+ Return<uint64_t> rc = mService->setNotify(mCallback);
+ EXPECT_NE(rc, 0UL);
+
+ Return<RequestStatus> res = mService->authenticate(0, 0);
+ // check that we were able to make an IPC request successfully
+ EXPECT_EQ(RequestStatus::SYS_OK, res);
+
+ res = mService->cancel();
+ // make sure callback was invoked within kThresholdInSeconds
+ EXPECT_EQ(true, waitForCallback());
+ // check that we were able to make an IPC request successfully
+ EXPECT_EQ(RequestStatus::SYS_OK, res);
+ // check error should be ERROR_CANCELED
+ EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr);
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(new FingerprintHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/boot/1.0/default/BootControl.cpp b/boot/1.0/default/BootControl.cpp
index 83ee1d2..9a90076 100644
--- a/boot/1.0/default/BootControl.cpp
+++ b/boot/1.0/default/BootControl.cpp
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
#define LOG_TAG "android.hardware.boot@1.0-impl"
#include <log/log.h>
diff --git a/boot/1.0/default/BootControl.h b/boot/1.0/default/BootControl.h
index be8a814..3d668dc 100644
--- a/boot/1.0/default/BootControl.h
+++ b/boot/1.0/default/BootControl.h
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
#ifndef ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
#define ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
diff --git a/boot/1.0/default/service.cpp b/boot/1.0/default/service.cpp
index 247e40e..f3996ef 100644
--- a/boot/1.0/default/service.cpp
+++ b/boot/1.0/default/service.cpp
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
#define LOG_TAG "android.hardware.boot@1.0-service"
#include <android/hardware/boot/1.0/IBootControl.h>
diff --git a/boot/1.0/vts/Android.bp b/boot/1.0/vts/Android.bp
new file mode 100644
index 0000000..7aef46b
--- /dev/null
+++ b/boot/1.0/vts/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+ "*"
+]
diff --git a/radio/1.0/vts/Android.mk b/boot/1.0/vts/Android.mk
similarity index 100%
rename from radio/1.0/vts/Android.mk
rename to boot/1.0/vts/Android.mk
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..5b14f54
--- /dev/null
+++ b/boot/1.0/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalBootV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalBootV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.boot@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
new file mode 100644
index 0000000..9789ee6
--- /dev/null
+++ b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "boot_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <cutils/properties.h>
+
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::boot::V1_0::IBootControl;
+using ::android::hardware::boot::V1_0::CommandResult;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::sp;
+
+// The main test class for the Boot HIDL HAL.
+class BootHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ boot = ::testing::VtsHalHidlTargetTestBase::getService<IBootControl>();
+ ASSERT_NE(boot, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IBootControl> boot;
+};
+
+auto generate_callback(CommandResult *dest) {
+ return [=](CommandResult cr) { *dest = cr; };
+}
+
+// Sanity check Boot::getNumberSlots().
+TEST_F(BootHidlTest, GetNumberSlots) {
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_LE((uint32_t)2, slots);
+}
+
+// Sanity check Boot::getCurrentSlot().
+TEST_F(BootHidlTest, GetCurrentSlot) {
+ Slot curSlot = boot->getCurrentSlot();
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_LT(curSlot, slots);
+}
+
+// Sanity check Boot::markBootSuccessful().
+TEST_F(BootHidlTest, MarkBootSuccessful) {
+ CommandResult cr;
+ Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+ ASSERT_TRUE(result.isOk());
+ if (cr.success) {
+ Slot curSlot = boot->getCurrentSlot();
+ BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
+ EXPECT_EQ(BoolResult::TRUE, ret);
+ }
+}
+
+// Sanity check Boot::setActiveBootSlot() on good and bad inputs.
+TEST_F(BootHidlTest, SetActiveBootSlot) {
+ for (Slot s = 0; s < 2; s++) {
+ CommandResult cr;
+ Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ }
+ {
+ // Restore original flags to avoid problems on reboot
+ CommandResult cr;
+ Return <void> result = boot->markBootSuccessful(generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ }
+ {
+ CommandResult cr;
+ uint32_t slots = boot->getNumberSlots();
+ Return<void> result =
+ boot->setActiveBootSlot(slots, generate_callback(&cr));
+ ASSERT_TRUE(result.isOk());
+ EXPECT_EQ(false, cr.success);
+ }
+}
+
+// Sanity check Boot::setSlotAsUnbootable() on good and bad inputs.
+TEST_F(BootHidlTest, SetSlotAsUnbootable) {
+ {
+ CommandResult cr;
+ Slot curSlot = boot->getCurrentSlot();
+ Slot otherSlot = curSlot ? 0 : 1;
+ Return<void> result =
+ boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ if (cr.success) {
+ EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
+
+ // Restore original flags to avoid problems on reboot
+ result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ result = boot->setActiveBootSlot(curSlot, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ result = boot->markBootSuccessful(generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(cr.success);
+ }
+ }
+ {
+ CommandResult cr;
+ uint32_t slots = boot->getNumberSlots();
+ Return<void> result =
+ boot->setSlotAsUnbootable(slots, generate_callback(&cr));
+ EXPECT_TRUE(result.isOk());
+ EXPECT_EQ(false, cr.success);
+ }
+}
+
+// Sanity check Boot::isSlotBootable() on good and bad inputs.
+TEST_F(BootHidlTest, IsSlotBootable) {
+ for (Slot s = 0; s < 2; s++) {
+ EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
+ }
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
+}
+
+// Sanity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
+TEST_F(BootHidlTest, IsSlotMarkedSuccessful) {
+ for (Slot s = 0; s < 2; s++) {
+ EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
+ }
+ uint32_t slots = boot->getNumberSlots();
+ EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
+}
+
+// Sanity check Boot::getSuffix() on good and bad inputs.
+TEST_F(BootHidlTest, GetSuffix) {
+ const char *suffixPtr;
+ auto cb = [&](hidl_string suffix) { suffixPtr = suffix.c_str(); };
+ for (Slot i = 0; i < 2; i++) {
+ CommandResult cr;
+ Return<void> result = boot->getSuffix(i, cb);
+ EXPECT_TRUE(result.isOk());
+ char correctSuffix[3];
+ snprintf(correctSuffix, sizeof(correctSuffix), "_%c", 'a' + i);
+ ASSERT_EQ(0, strcmp(suffixPtr, correctSuffix));
+ }
+ {
+ char emptySuffix[] = "";
+ Return<void> result = boot->getSuffix(boot->getNumberSlots(), cb);
+ EXPECT_TRUE(result.isOk());
+ ASSERT_EQ(0, strcmp(emptySuffix, suffixPtr));
+ }
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/boot/Android.bp b/boot/Android.bp
index bbb3e4b..67af5bb 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -1,4 +1,6 @@
// This is an autogenerated file, do not edit.
subdirs = [
"1.0",
+ "1.0/vts",
+ "1.0/vts/functional",
]
diff --git a/broadcastradio/1.0/Android.bp b/broadcastradio/1.0/Android.bp
new file mode 100644
index 0000000..3c3a015
--- /dev/null
+++ b/broadcastradio/1.0/Android.bp
@@ -0,0 +1,83 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.broadcastradio@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IBroadcastRadio.hal",
+ "IBroadcastRadioFactory.hal",
+ "ITuner.hal",
+ "ITunerCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.broadcastradio@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.0",
+ srcs: [
+ ":android.hardware.broadcastradio@1.0_hal",
+ ],
+ out: [
+ "android/hardware/broadcastradio/1.0/types.cpp",
+ "android/hardware/broadcastradio/1.0/BroadcastRadioAll.cpp",
+ "android/hardware/broadcastradio/1.0/BroadcastRadioFactoryAll.cpp",
+ "android/hardware/broadcastradio/1.0/TunerAll.cpp",
+ "android/hardware/broadcastradio/1.0/TunerCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.broadcastradio@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.0",
+ srcs: [
+ ":android.hardware.broadcastradio@1.0_hal",
+ ],
+ out: [
+ "android/hardware/broadcastradio/1.0/types.h",
+ "android/hardware/broadcastradio/1.0/IBroadcastRadio.h",
+ "android/hardware/broadcastradio/1.0/IHwBroadcastRadio.h",
+ "android/hardware/broadcastradio/1.0/BnHwBroadcastRadio.h",
+ "android/hardware/broadcastradio/1.0/BpHwBroadcastRadio.h",
+ "android/hardware/broadcastradio/1.0/BsBroadcastRadio.h",
+ "android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.0/IHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.0/BnHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.0/BpHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.0/BsBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.0/ITuner.h",
+ "android/hardware/broadcastradio/1.0/IHwTuner.h",
+ "android/hardware/broadcastradio/1.0/BnHwTuner.h",
+ "android/hardware/broadcastradio/1.0/BpHwTuner.h",
+ "android/hardware/broadcastradio/1.0/BsTuner.h",
+ "android/hardware/broadcastradio/1.0/ITunerCallback.h",
+ "android/hardware/broadcastradio/1.0/IHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.0/BnHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.0/BpHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.0/BsTunerCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.broadcastradio@1.0",
+ generated_sources: ["android.hardware.broadcastradio@1.0_genc++"],
+ generated_headers: ["android.hardware.broadcastradio@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.broadcastradio@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/broadcastradio/1.0/Android.mk b/broadcastradio/1.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/broadcastradio/1.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.0/IBroadcastRadio.hal b/broadcastradio/1.0/IBroadcastRadio.hal
new file mode 100644
index 0000000..c7fe62d
--- /dev/null
+++ b/broadcastradio/1.0/IBroadcastRadio.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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.broadcastradio@1.0;
+
+import ITunerCallback;
+import ITuner;
+
+interface IBroadcastRadio {
+
+ /*
+ * Retrieve implementation properties.
+ * @return result Operation completion status: OK in case of success,
+ * NOT_INITIALIZED in case of initialization error.
+ * @return properties A Properties structure containing implementation
+ * description and capabilities.
+ */
+ getProperties() generates (Result result, Properties properties);
+
+ /*
+ * Open a tuner interface for the requested configuration.
+ * If no other tuner is opened, this will power on the radio hardware.
+ * The hardware must be powered down when all tuner interface are released.
+ * @param config A BandConfig struct containing the band configuration to apply
+ * @param audio True if this tuner must be used for live radio listening and
+ * should be connected to the radio audio source.
+ * @param callback the callback interface
+ * @return result Operation completion status: OK in case of success,
+ * INVALID_ARGUMENTS if configuration requested is invalid,
+ * INVALID_STATE if called out of sequence
+ * @return tuner The interface to control the tuner
+ *
+ * Callback ITunerCallback.ConfigChanged MUST be called once the
+ * configuration is applied or a failure occurs or after a time out.
+ */
+ openTuner(BandConfig config, bool audio, ITunerCallback callback)
+ generates (Result result, ITuner tuner);
+};
diff --git a/broadcastradio/1.0/IBroadcastRadioFactory.hal b/broadcastradio/1.0/IBroadcastRadioFactory.hal
new file mode 100644
index 0000000..82a97c4
--- /dev/null
+++ b/broadcastradio/1.0/IBroadcastRadioFactory.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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.broadcastradio@1.0;
+
+import IBroadcastRadio;
+
+interface IBroadcastRadioFactory {
+
+ /*
+ * Connects to a broadcast radio HAL module for a given class
+ * (AM/FM, Satellite, DAB).
+ *
+ * @param classId Class of the module to connect to .
+ * @return retval operation completion status. Returns INVALID_ARGUMENTS
+ * if there is no corresponding hardware module found,
+ * NOT_INITIALIZED if an error occurred while opening the hardware
+ * module.
+ * @return result the interface for the created module.
+ */
+ connectModule(Class classId)
+ generates (Result retval, IBroadcastRadio result);
+};
diff --git a/broadcastradio/1.0/ITuner.hal b/broadcastradio/1.0/ITuner.hal
new file mode 100644
index 0000000..ae4b284
--- /dev/null
+++ b/broadcastradio/1.0/ITuner.hal
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 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.broadcastradio@1.0;
+
+import ITunerCallback;
+
+interface ITuner {
+
+ /*
+ * Apply current radio band configuration (band, range, channel spacing...).
+ * Automatically cancels pending scan, step or tune.
+ * ITunerCallback.configChange() method MUST be called once the
+ * configuration is applied or a failure occurs or after a time out.
+ * @param config The band configuration to apply.
+ * @return result OK if configuration could be applied
+ * NOT_INITIALIZED in case of initialization error.
+ * INVALID_ARGUMENTS if configuration requested is invalid
+ *
+ */
+ setConfiguration(BandConfig config) generates(Result result);
+
+ /*
+ * Retrieve current radio band configuration.
+ * @return result OK if valid configuration is returned,
+ * NOT_INITIALIZED in case of initialization error.
+ * @param config Current band configuration
+ */
+ getConfiguration() generates(Result result, BandConfig config);
+
+ /*
+ * Start scanning up to next valid station.
+ * Shall be called only when a valid configuration has been applied.
+ * Automatically cancels pending scan, step or tune.
+ * ITunerCallback.tuneComplete() MUST be called once locked on a station
+ * or after a time out or full band scan if no station found.
+ * The status should indicate if a valid station is tuned or not.
+ * @param direction UP or DOWN.
+ * @param skipSubChannel valid for HD radio or digital radios only:
+ * ignore sub channels (e.g SPS for HD radio).
+ * @return result OK if scan successfully started
+ * INVALID_STATE if called out of sequence
+ * NOT_INITIALIZED if another error occurs
+ */
+ scan(Direction direction, bool skipSubChannel) generates(Result result);
+
+ /*
+ * Move one channel spacing up or down.
+ * Must be called when a valid configuration has been applied.
+ * Automatically cancels pending scan, step or tune.
+ * ITunerCallback.tuneComplete() MUST be called once locked on a station
+ * or after a time out or full band scan if no station found.
+ * The status should indicate if a valid station is tuned or not.
+ * @param direction UP or DOWN.
+ * @param skipSubChannel valid for HD radio or digital radios only:
+ * ignore sub channels (e.g SPS for HD radio).
+ * @return result OK if scan successfully started
+ * INVALID_STATE if called out of sequence
+ * NOT_INITIALIZED if another error occurs
+ */
+ step(Direction direction, bool skipSubChannel) generates(Result result);
+
+ /*
+ * Tune to specified channel.
+ * Must be called when a valid configuration has been applied.
+ * Automatically cancels pending scan, step or tune.
+ * ITunerCallback.tuneComplete() MUST be called once locked on a station
+ * or after a time out or full band scan if no station found.
+ * The status should indicate if a valid station is tuned or not.
+ * @param channel Channel to tune to. A frequency in kHz for AM/FM/HD Radio
+ * bands.
+ * @param subChannel Valid for HD radio or digital radios only
+ * (e.g SPS number for HD radio)..
+ * @return result OK if scan successfully started
+ * INVALID_ARGUMENTS if invalid arguments are passed
+ * INVALID_STATE if called out of sequence
+ * NOT_INITIALIZED if another error occurs
+ */
+ tune(uint32_t channel, uint32_t subChannel) generates(Result result);
+
+ /*
+ * Cancel a scan, step or tune operation.
+ * Shall be called only while a scan, step or tune operation is pending.
+ * ITunerCallback.tuneComplete() MUST NOT be sent by the HAL.
+ * @return result OK if scan successfully started
+ * INVALID_STATE if called out of sequence
+ * NOT_INITIALIZED if another error occurs
+ */
+ cancel() generates(Result result);
+
+ /*
+ * Retrieve current station information.
+ * @return result OK if scan successfully started
+ * NOT_INITIALIZED if another error occurs
+ * @return info Current program information.
+ */
+ getProgramInformation() generates(Result result, ProgramInfo info);
+};
diff --git a/broadcastradio/1.0/ITunerCallback.hal b/broadcastradio/1.0/ITunerCallback.hal
new file mode 100644
index 0000000..a7e1260
--- /dev/null
+++ b/broadcastradio/1.0/ITunerCallback.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.broadcastradio@1.0;
+
+
+interface ITunerCallback {
+
+ /*
+ * Method called by the HAL when a HW failure occurs.
+ * The framework MUST close the ITuner interface and open a new one.
+ */
+ oneway hardwareFailure();
+
+ /*
+ * Method called by the HAL when a new configuration is applied
+ * in response to IDevice.openTuner() or ITuner.setConfiguration().
+ * @param result OK if the configuration has been applied,
+ * INVALID_ARGUMENTS if not or TIMEOUT in case of time out.
+ * @param config A BandConfig structure describing the new configuration
+ * applied.
+ */
+ oneway configChange(Result result, BandConfig config);
+
+ /*
+ * Method called by the HAL when a tuning operation completes
+ * following a step(), scan() or tune() command.
+ * @param result OK if tune succeeded or TIMEOUT in case of time out.
+ * @param info A ProgramInfo structure describing the tuned station.
+ */
+ oneway tuneComplete(Result result, ProgramInfo info);
+
+ /*
+ * Method called by the HAL when a frequency switch occurs.
+ * @param info A ProgramInfo structure describing the new tuned station.
+ */
+ oneway afSwitch(ProgramInfo info);
+
+ /*
+ * Method called by the HAL when the antenna connection state changes.
+ * @param connected True if the antenna is connected, false otherwise.
+ */
+ oneway antennaStateChange(bool connected);
+
+ /*
+ * Method called by the HAL when a traffic announcement starts or
+ * stops.
+ * @param active True if the announcement starts, false if it stops.
+ */
+ oneway trafficAnnouncement(bool active);
+
+ /*
+ * Method called by the HAL when an emergency announcement starts
+ * or stops.
+ * @param active True if the announcement starts, false if it stops.
+ */
+ oneway emergencyAnnouncement(bool active);
+
+ /*
+ * Method called by the HAL when metadata for current station
+ * are updated.
+ * @param channel The channel the metadata is associated with.
+ * @param subChannel The sub channel the metadata is associated with.
+ * @param metadata A list of all updated metada.
+ */
+ oneway newMetadata(uint32_t channel, uint32_t subChannel, vec<MetaData> metadata);
+};
\ No newline at end of file
diff --git a/broadcastradio/1.0/default/Android.mk b/broadcastradio/1.0/default/Android.mk
new file mode 100644
index 0000000..bb32595
--- /dev/null
+++ b/broadcastradio/1.0/default/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.broadcastradio@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ BroadcastRadio.cpp \
+ BroadcastRadioFactory.cpp \
+ Tuner.cpp \
+ Utils.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ liblog \
+ libhardware \
+ android.hardware.broadcastradio@1.0 \
+ libradio_metadata
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/broadcastradio/1.0/default/BroadcastRadio.cpp b/broadcastradio/1.0/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..45ffdb2
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadio.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "BroadcastRadio"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+
+#include <hardware/radio.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+BroadcastRadio::BroadcastRadio(Class classId)
+ : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL)
+{
+}
+
+BroadcastRadio::~BroadcastRadio()
+{
+ if (mHwDevice != NULL) {
+ radio_hw_device_close(mHwDevice);
+ }
+}
+
+void BroadcastRadio::onFirstRef()
+{
+ const hw_module_t *mod;
+ int rc;
+ ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
+
+ mHwDevice = NULL;
+ const char *classString = Utils::getClassString(mClassId);
+ if (classString == NULL) {
+ ALOGE("invalid class ID %d", mClassId);
+ mStatus = Result::INVALID_ARGUMENTS;
+ return;
+ }
+
+ ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
+ __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString);
+
+ rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load radio module %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc));
+ return;
+ }
+ rc = radio_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open radio hw device in %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
+ radio_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ } else {
+ mStatus = Result::OK;
+ }
+}
+
+int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
+{
+ ALOGV("%s", __FUNCTION__);
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ if (halTuner == 0) {
+ return -EINVAL;
+ }
+ return mHwDevice->close_tuner(mHwDevice, halTuner);
+}
+
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb)
+{
+ int rc;
+ radio_hal_properties_t halProperties;
+ Properties properties;
+
+ if (mHwDevice == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ rc = mHwDevice->get_properties(mHwDevice, &halProperties);
+ if (rc == 0) {
+ Utils::convertPropertiesFromHal(&properties, &halProperties);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), properties);
+ return Void();
+}
+
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio,
+ const sp<ITunerCallback>& callback, openTuner_cb _hidl_cb)
+{
+ sp<Tuner> tunerImpl = new Tuner(callback, this);
+
+ radio_hal_band_config_t halConfig;
+ const struct radio_tuner *halTuner;
+ Utils::convertBandConfigToHal(&halConfig, &config);
+ int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio,
+ Tuner::callback, tunerImpl.get(),
+ &halTuner);
+ if (rc == 0) {
+ tunerImpl->setHalTuner(halTuner);
+ }
+
+ _hidl_cb(Utils::convertHalResult(rc), tunerImpl);
+ return Void();
+}
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadio.h b/broadcastradio/1.0/default/BroadcastRadio.h
new file mode 100644
index 0000000..6764d82
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadio.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <hidl/Status.h>
+#include <hardware/radio.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadio : public IBroadcastRadio {
+
+ BroadcastRadio(Class classId);
+
+ // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> openTuner(const BandConfig& config, bool audio,
+ const sp<ITunerCallback>& callback,
+ openTuner_cb _hidl_cb) override;
+
+
+ // RefBase
+ virtual void onFirstRef();
+
+ Result initCheck() { return mStatus; }
+ int closeHalTuner(const struct radio_tuner *halTuner);
+
+private:
+ virtual ~BroadcastRadio();
+
+ static const char * sClassModuleNames[];
+
+ Result convertHalResult(int rc);
+ void convertBandConfigFromHal(BandConfig *config,
+ const radio_hal_band_config_t *halConfig);
+ void convertPropertiesFromHal(Properties *properties,
+ const radio_hal_properties_t *halProperties);
+ void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+ const BandConfig *config);
+
+ Result mStatus;
+ Class mClassId;
+ struct radio_hw_device *mHwDevice;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.cpp b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp
new file mode 100644
index 0000000..d5d214c
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include "BroadcastRadioFactory.h"
+#include "BroadcastRadio.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
+ sp<BroadcastRadio> impl = new BroadcastRadio(classId);
+ Result retval = Result::NOT_INITIALIZED;
+ if (impl != 0) {
+ retval = impl->initCheck();
+ }
+ _hidl_cb(retval, impl);
+ return Void();
+}
+
+
+IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) {
+ return new BroadcastRadioFactory();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.h b/broadcastradio/1.0/default/BroadcastRadioFactory.h
new file mode 100644
index 0000000..97f7f55
--- /dev/null
+++ b/broadcastradio/1.0/default/BroadcastRadioFactory.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadioFactory : public IBroadcastRadioFactory {
+ // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+ Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override;
+
+};
+
+extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.0/default/Tuner.cpp b/broadcastradio/1.0/default/Tuner.cpp
new file mode 100644
index 0000000..ff643b8
--- /dev/null
+++ b/broadcastradio/1.0/default/Tuner.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "Tuner"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+#include <system/RadioMetadataWrapper.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+void Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+ BandConfig config;
+ ProgramInfo info;
+ hidl_vec<MetaData> metadata;
+
+ if (mCallback != 0) {
+ switch(halEvent->type) {
+ case RADIO_EVENT_CONFIG:
+ Utils::convertBandConfigFromHal(&config, &halEvent->config);
+ mCallback->configChange(Utils::convertHalResult(halEvent->status), config);
+ break;
+ case RADIO_EVENT_ANTENNA:
+ mCallback->antennaStateChange(halEvent->on);
+ break;
+ case RADIO_EVENT_TUNED:
+ Utils::convertProgramInfoFromHal(&info, &halEvent->info);
+ mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info);
+ break;
+ case RADIO_EVENT_METADATA: {
+ uint32_t channel;
+ uint32_t sub_channel;
+ if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) {
+ Utils::convertMetaDataFromHal(metadata, halEvent->metadata);
+ mCallback->newMetadata(channel, sub_channel, metadata);
+ }
+ } break;
+ case RADIO_EVENT_TA:
+ mCallback->trafficAnnouncement(halEvent->on);
+ break;
+ case RADIO_EVENT_AF_SWITCH:
+ Utils::convertProgramInfoFromHal(&info, &halEvent->info);
+ mCallback->afSwitch(info);
+ break;
+ case RADIO_EVENT_EA:
+ mCallback->emergencyAnnouncement(halEvent->on);
+ break;
+ case RADIO_EVENT_HW_FAILURE:
+ default:
+ mCallback->hardwareFailure();
+ break;
+ }
+ }
+}
+
+//static
+void Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
+{
+ wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie));
+ sp<Tuner> tuner = weak.promote();
+ if (tuner == 0) return;
+ tuner->onCallback(halEvent);
+}
+
+Tuner::Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice)
+ : mHalTuner(NULL), mCallback(callback), mParentDevice(parentDevice)
+{
+ ALOGV("%s", __FUNCTION__);
+}
+
+
+Tuner::~Tuner()
+{
+ ALOGV("%s", __FUNCTION__);
+ const sp<BroadcastRadio> parentDevice = mParentDevice.promote();
+ if (parentDevice != 0) {
+ parentDevice->closeHalTuner(mHalTuner);
+ }
+}
+
+// Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow.
+Return<Result> Tuner::setConfiguration(const BandConfig& config) {
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ radio_hal_band_config_t halConfig;
+ Utils::convertBandConfigToHal(&halConfig, &config);
+ int rc = mHalTuner->set_configuration(mHalTuner, &halConfig);
+ return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
+ int rc;
+ radio_hal_band_config_t halConfig;
+ BandConfig config;
+
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ rc = mHalTuner->get_configuration(mHalTuner, &halConfig);
+ if (rc == 0) {
+ Utils::convertBandConfigFromHal(&config, &halConfig);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), config);
+ return Void();
+}
+
+Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->tune(mHalTuner, channel, subChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::cancel() {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->cancel(mHalTuner);
+ return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
+ int rc;
+ radio_program_info_t halInfo;
+ RadioMetadataWrapper metadataWrapper(&halInfo.metadata);
+ ProgramInfo info;
+
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ rc = mHalTuner->get_program_information(mHalTuner, &halInfo);
+ if (rc == 0) {
+ Utils::convertProgramInfoFromHal(&info, &halInfo);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), info);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.0/default/Tuner.h b/broadcastradio/1.0/default/Tuner.h
new file mode 100644
index 0000000..bfdd4f4
--- /dev/null
+++ b/broadcastradio/1.0/default/Tuner.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H
+
+#include <android/hardware/broadcastradio/1.0/ITuner.h>
+#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
+#include <hidl/Status.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+struct BroadcastRadio;
+
+struct Tuner : public ITuner {
+
+ Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice);
+
+ // Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow.
+ Return<Result> setConfiguration(const BandConfig& config) override;
+ Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override;
+ Return<Result> scan(Direction direction, bool skipSubChannel) override;
+ Return<Result> step(Direction direction, bool skipSubChannel) override;
+ Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
+ Return<Result> cancel() override;
+ Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
+
+ static void callback(radio_hal_event_t *halEvent, void *cookie);
+ void onCallback(radio_hal_event_t *halEvent);
+
+ void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
+ const struct radio_tuner *getHalTuner() { return mHalTuner; }
+
+ private:
+ ~Tuner();
+
+ const struct radio_tuner *mHalTuner;
+ const sp<ITunerCallback> mCallback;
+ const wp<BroadcastRadio> mParentDevice;
+};
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H
diff --git a/broadcastradio/1.0/default/Utils.cpp b/broadcastradio/1.0/default/Utils.cpp
new file mode 100644
index 0000000..8776222
--- /dev/null
+++ b/broadcastradio/1.0/default/Utils.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "BroadcastRadioHalUtils"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+const char *Utils::sClassModuleNames[] = {
+ RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
+ RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */
+ RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */
+};
+
+// make sure HIDL enum values are aligned with legacy values
+static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM),
+ "AM/FM class mismatch with legacy");
+static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT),
+ "SAT class mismatch with legacy");
+static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT),
+ "DT class mismatch with legacy");
+
+static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM),
+ "AM band mismatch with legacy");
+static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM),
+ "FM band mismatch with legacy");
+static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD),
+ "AM HD band mismatch with legacy");
+static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD),
+ "FM HD band mismatch with legacy");
+
+static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE),
+ "RDS NONE mismatch with legacy");
+static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD),
+ "RDS WORLD mismatch with legacy");
+static_assert(RADIO_RDS_US == static_cast<int>(Rds::US),
+ "RDS US mismatch with legacy");
+
+static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50),
+ "De-emphasis 50 mismatch with legacy");
+static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75),
+ "De-emphasis 75 mismatch with legacy");
+
+static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP),
+ "Direction Up mismatch with legacy");
+static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN),
+ "Direction Up mismatch with legacy");
+
+static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID),
+ "Metadata type INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT),
+ "Metadata type INT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT),
+ "Metadata type TEXT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW),
+ "Metadata type RAW mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK),
+ "Metadata type CLOCK mismatch with legacy");
+
+static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID),
+ "Metadata key INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI),
+ "Metadata key RDS_PI mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS),
+ "Metadata key RDS_PS mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY),
+ "Metadata key RDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY),
+ "Metadata key RBDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT),
+ "Metadata key RDS_RT mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE),
+ "Metadata key TITLE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST),
+ "Metadata key ARTIST mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM),
+ "Metadata key ALBUM mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE),
+ "Metadata key GENRE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON),
+ "Metadata key ICON mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART),
+ "Metadata key ART mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK),
+ "Metadata key CLOCK mismatch with legacy");
+
+
+//static
+const char * Utils::getClassString(Class ClassId)
+{
+ int id = static_cast<int>(ClassId);
+
+ if ((id < 0) ||
+ (id >= NELEM(sClassModuleNames))) {
+ ALOGE("invalid class ID %d", id);
+ return NULL;
+ }
+ return sClassModuleNames[id];
+}
+
+//static
+Result Utils::convertHalResult(int rc)
+{
+ switch (rc) {
+ case 0:
+ return Result::OK;
+ case -EINVAL:
+ return Result::INVALID_ARGUMENTS;
+ case -ENOSYS:
+ return Result::INVALID_STATE;
+ case -ETIMEDOUT:
+ return Result::TIMEOUT;
+ case -ENODEV:
+ default:
+ return Result::NOT_INITIALIZED;
+ }
+}
+
+//static
+void Utils::convertBandConfigFromHal(
+ BandConfig *config,
+ const radio_hal_band_config_t *halConfig)
+{
+
+ config->type = static_cast<Band>(halConfig->type);
+ config->antennaConnected = halConfig->antenna_connected;
+ config->lowerLimit = halConfig->lower_limit;
+ config->upperLimit = halConfig->upper_limit;
+ config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]),
+ halConfig->num_spacings * sizeof(uint32_t));
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ config->spacings.resize(halConfig->num_spacings);
+
+ if (config->type == Band::FM) {
+ config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis);
+ config->ext.fm.stereo = halConfig->fm.stereo;
+ config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds);
+ config->ext.fm.ta = halConfig->fm.ta;
+ config->ext.fm.af = halConfig->fm.af;
+ config->ext.fm.ea = halConfig->fm.ea;
+ } else {
+ config->ext.am.stereo = halConfig->am.stereo;
+ }
+}
+
+//static
+void Utils::convertPropertiesFromHal(
+ Properties *properties,
+ const radio_hal_properties_t *halProperties)
+{
+ properties->classId = static_cast<Class>(halProperties->class_id);
+ properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor));
+ properties->product.setToExternal(halProperties->product, strlen(halProperties->product));
+ properties->version.setToExternal(halProperties->version, strlen(halProperties->version));
+ properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial));
+ properties->numTuners = halProperties->num_tuners;
+ properties->numAudioSources = halProperties->num_audio_sources;
+ properties->supportsCapture = halProperties->supports_capture;
+
+ BandConfig *bands =
+ new BandConfig[halProperties->num_bands];
+ for (size_t i = 0; i < halProperties->num_bands; i++) {
+ convertBandConfigFromHal(&bands[i], &halProperties->bands[i]);
+ }
+ properties->bands.setToExternal(bands, halProperties->num_bands);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ properties->bands.resize(halProperties->num_bands);
+ delete[] bands;
+}
+
+//static
+void Utils::convertBandConfigToHal(
+ radio_hal_band_config_t *halConfig,
+ const BandConfig *config)
+{
+
+ halConfig->type = static_cast<radio_band_t>(config->type);
+ halConfig->antenna_connected = config->antennaConnected;
+ halConfig->lower_limit = config->lowerLimit;
+ halConfig->upper_limit = config->upperLimit;
+ halConfig->num_spacings = config->spacings.size();
+ if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) {
+ halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX;
+ }
+ memcpy(halConfig->spacings, config->spacings.data(),
+ sizeof(uint32_t) * halConfig->num_spacings);
+
+ if (config->type == Band::FM) {
+ halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis);
+ halConfig->fm.stereo = config->ext.fm.stereo;
+ halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds);
+ halConfig->fm.ta = config->ext.fm.ta;
+ halConfig->fm.af = config->ext.fm.af;
+ halConfig->fm.ea = config->ext.fm.ea;
+ } else {
+ halConfig->am.stereo = config->ext.am.stereo;
+ }
+}
+
+
+//static
+void Utils::convertProgramInfoFromHal(ProgramInfo *info,
+ radio_program_info_t *halInfo)
+{
+ info->channel = halInfo->channel;
+ info->subChannel = halInfo->sub_channel;
+ info->tuned = halInfo->tuned;
+ info->stereo = halInfo->stereo;
+ info->digital = halInfo->digital;
+ info->signalStrength = halInfo->signal_strength;
+ convertMetaDataFromHal(info->metadata, halInfo->metadata);
+}
+
+//static
+int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
+ radio_metadata_t *halMetadata)
+{
+ if (halMetadata == NULL) {
+ ALOGE("Invalid argument: halMetadata is NULL");
+ return 0;
+ }
+
+ int count = radio_metadata_get_count(halMetadata);
+ if (count <= 0) {
+ return count;
+ }
+ MetaData *newMetadata =
+ new MetaData[count];
+ int outCount = 0;
+ for (int i = 0; i < count; i++) {
+ radio_metadata_key_t key;
+ radio_metadata_type_t type;
+ void *value;
+ size_t size;
+ if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 ||
+ size == 0) {
+ continue;
+ }
+ switch (type) {
+ case RADIO_METADATA_TYPE_INT: {
+ newMetadata[outCount].intValue = *(static_cast<int32_t *>(value));
+ } break;
+ case RADIO_METADATA_TYPE_TEXT: {
+ newMetadata[outCount].stringValue = static_cast<char *>(value);
+ } break;
+ case RADIO_METADATA_TYPE_RAW: {
+ newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ newMetadata[outCount].rawValue.resize(size);
+ } break;
+ case RADIO_METADATA_TYPE_CLOCK: {
+ radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value);
+ newMetadata[outCount].clockValue.utcSecondsSinceEpoch =
+ clock->utc_seconds_since_epoch;
+ newMetadata[outCount].clockValue.timezoneOffsetInMinutes =
+ clock->timezone_offset_in_minutes;
+ } break;
+ }
+ newMetadata[outCount].type = static_cast<MetadataType>(type);
+ newMetadata[outCount].key = static_cast<MetadataKey>(key);
+ outCount++;
+ }
+ metadata.setToExternal(newMetadata, outCount);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ metadata.resize(outCount);
+ return outCount;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.0/default/Utils.h b/broadcastradio/1.0/default/Utils.h
new file mode 100644
index 0000000..4ef22a5
--- /dev/null
+++ b/broadcastradio/1.0/default/Utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
+
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+namespace implementation {
+
+class Utils {
+public:
+ static const char * getClassString(Class ClassId);
+ static Result convertHalResult(int rc);
+ static void convertBandConfigFromHal(BandConfig *config,
+ const radio_hal_band_config_t *halConfig);
+ static void convertPropertiesFromHal(Properties *properties,
+ const radio_hal_properties_t *halProperties);
+ static void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+ const BandConfig *config);
+ static void convertProgramInfoFromHal(ProgramInfo *info,
+ radio_program_info_t *halInfo);
+ static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
+ radio_metadata_t *halMetadata);
+private:
+ static const char * sClassModuleNames[];
+
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
diff --git a/broadcastradio/1.0/types.hal b/broadcastradio/1.0/types.hal
new file mode 100644
index 0000000..d8b2da3
--- /dev/null
+++ b/broadcastradio/1.0/types.hal
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2016 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.broadcastradio@1.0;
+
+enum Result : int32_t {
+ OK,
+ NOT_INITIALIZED,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+ TIMEOUT,
+};
+
+/*
+ * Radio hardware module class. A given radio hardware module HAL is of one
+ * class only. The platform can not have more than one hardware module of
+ * each class. Current version of the framework only supports RADIO_CLASS_AM_FM.
+ */
+enum Class : uint32_t {
+ /* FM (including HD radio) and AM */
+ AM_FM = 0,
+ /* Satellite Radio */
+ SAT = 1,
+ /* Digital Radio (DAB) */
+ DT = 2,
+};
+
+/* value for field "type" of radio band described in struct radio_hal_band_config */
+enum Band : uint32_t {
+ /* Amplitude Modulation band: LW, MW, SW */
+ AM = 0,
+ /* Frequency Modulation band: FM */
+ FM = 1,
+ /* FM HD Radio / DRM (IBOC) */
+ FM_HD = 2,
+ /* AM HD Radio / DRM (IBOC) */
+ AM_HD = 3,
+};
+
+/* RDS variant implemented. A struct FmBandConfig can list none or several. */
+enum Rds : uint32_t {
+ NONE = 0,
+ WORLD = (1<<0),
+ US = (1<<1),
+};
+
+
+/* FM deemphasis variant implemented.
+ * A struct FmBandConfig can list one or more. */
+enum Deemphasis : uint32_t {
+ D50 = (1<<0),
+ D75 = (1<<1),
+};
+
+/* Scanning direction for scan() and step() tuner APIs */
+enum Direction : uint32_t {
+ UP,
+ DOWN
+};
+
+/* Unique handle allocated to a radio module */
+typedef uint32_t Handle;
+
+
+/* Additional attributes for an FM band configuration */
+struct FmBandConfig {
+ /* deemphasis variant */
+ Deemphasis deemphasis;
+ /* stereo supported */
+ bool stereo;
+ /* RDS variants supported */
+ Rds rds;
+ /* Traffic Announcement supported */
+ bool ta;
+ /* Alternate Frequency supported */
+ bool af;
+ /* Emergency announcements supported */
+ bool ea;
+};
+
+/* Additional attributes for an AM band configuration */
+struct AmBandConfig {
+ /* Stereo supported */
+ bool stereo;
+};
+
+/* Radio band configuration. Describes a given band supported by the radio
+ * module. The HAL can expose only one band per type with the the maximum range
+ * supported and all options. The framework will derive the actual regions were
+ * this module can operate and expose separate band configurations for
+ * applications to chose from. */
+struct BandConfig {
+ Band type;
+ bool antennaConnected;
+ uint32_t lowerLimit;
+ uint32_t upperLimit;
+ vec<uint32_t> spacings;
+ union Ext {
+ FmBandConfig fm;
+ AmBandConfig am;
+ } ext;
+};
+
+/* Exposes properties of a given hardware radio module.
+ * NOTE: current framework implementation supports only one audio source
+ * (num_audio_sources = 1). The source corresponds to AUDIO_DEVICE_IN_FM_TUNER.
+ * If more than one tuner is supported (num_tuners > 1), only one can be
+ * connected to the audio source. */
+struct Properties {
+ /* Class of this module. E.g AM_FM */
+ Class classId;
+ /* implementor name */
+ string implementor;
+ /* product name */
+ string product;
+ /* product version */
+ string version;
+ /* serial number (for subscription services) */
+ string serial;
+ /* number of tuners controllable independently */
+ uint32_t numTuners;
+ /* number of audio sources driven simultaneously */
+ uint32_t numAudioSources;
+ /* the hardware supports capture of audio source from audio HAL */
+ bool supportsCapture;
+ vec<BandConfig> bands; /* band descriptors */
+};
+
+enum MetadataType : int32_t {
+ INVALID = -1,
+ /* Signed 32 bit integer */
+ INT = 0,
+ /* String */
+ TEXT = 1,
+ /* Raw binary data (icon or art)
+ This data must be transparent to the android framework */
+ RAW = 2,
+ /* clock data, see MetaDataClock */
+ CLOCK = 3,
+};
+
+enum MetadataKey : int32_t {
+ INVALID = -1,
+ /* RDS PI - string */
+ RDS_PI = 0,
+ /* RDS PS - string */
+ RDS_PS = 1,
+ /* RDS PTY - int32_t */
+ RDS_PTY = 2,
+ /* RBDS PTY - int32_t */
+ RBDS_PTY = 3,
+ /* RDS RT - string */
+ RDS_RT = 4,
+ /* Song title - string */
+ TITLE = 5,
+ /* Artist name - string */
+ ARTIST = 6,
+ /* Album name - string */
+ ALBUM = 7,
+ /* Musical genre - string */
+ GENRE = 8,
+ /* Station icon - raw */
+ ICON = 9,
+ /* Album art - raw */
+ ART = 10,
+ /* Clock - MetaDataClock */
+ CLOCK = 11,
+};
+
+struct MetaDataClock {
+ /* Seconds since epoch at GMT + 0. */
+ uint64_t utcSecondsSinceEpoch;
+ /* Minutes offset from the GMT. */
+ int32_t timezoneOffsetInMinutes;
+};
+
+struct MetaData {
+ MetadataType type;
+ MetadataKey key;
+ /* Value used for type MetadataType.INT */
+ int32_t intValue;
+ /* Value used for type MetadataType.CLOCK */
+ MetaDataClock clockValue;
+ /* Value used for type MetadataType.TEXT */
+ string stringValue;
+ /* Value used for type MetadataType.RAW */
+ vec<uint8_t> rawValue;
+};
+
+
+/* Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
+ * Contains information on currently tuned channel.
+ */
+struct ProgramInfo {
+ uint32_t channel; /* current channel. (e.g kHz for band type AM_FM) */
+ uint32_t subChannel; /* current sub channel. (FM_HD) */
+ bool tuned; /* tuned to a program or not */
+ bool stereo; /* program is stereo or not */
+ bool digital; /* digital program or not (e.g HD Radio program) */
+ uint32_t signalStrength; /* signal strength from 0 to 100 */
+ vec<MetaData> metadata; /* non empty if meta data are present (e.g PTY, song title ...) */
+};
+
diff --git a/broadcastradio/1.0/vts/Android.mk b/broadcastradio/1.0/vts/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/broadcastradio/1.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..cf52f49
--- /dev/null
+++ b/broadcastradio/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalBroadcastradioV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalBroadcastradioV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.broadcastradio@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
new file mode 100644
index 0000000..4ec19c7
--- /dev/null
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "BroadcastRadioHidlHalTest"
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/threads.h>
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.0/ITuner.h>
+#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.0/types.h>
+
+
+using ::android::sp;
+using ::android::Mutex;
+using ::android::Condition;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using ::android::hardware::broadcastradio::V1_0::ITuner;
+using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
+using ::android::hardware::broadcastradio::V1_0::Result;
+using ::android::hardware::broadcastradio::V1_0::Class;
+using ::android::hardware::broadcastradio::V1_0::Properties;
+using ::android::hardware::broadcastradio::V1_0::Band;
+using ::android::hardware::broadcastradio::V1_0::BandConfig;
+using ::android::hardware::broadcastradio::V1_0::Direction;
+using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
+using ::android::hardware::broadcastradio::V1_0::MetaData;
+
+
+// The main test class for Broadcast Radio HIDL HAL.
+
+class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override {
+ sp<IBroadcastRadioFactory> factory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
+ if (factory != 0) {
+ factory->connectModule(Class::AM_FM,
+ [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
+ if (retval == Result::OK) {
+ mRadio = result;
+ }
+ });
+ }
+ mTunerCallback = new MyCallback(this);
+ ASSERT_NE(nullptr, mRadio.get());
+ ASSERT_NE(nullptr, mTunerCallback.get());
+ }
+
+ virtual void TearDown() override {
+ mTuner.clear();
+ mRadio.clear();
+ }
+
+ class MyCallback : public ITunerCallback {
+ public:
+
+ // ITunerCallback methods (see doc in ITunerCallback.hal)
+ virtual Return<void> hardwareFailure() {
+ ALOGI("%s", __FUNCTION__);
+ mParentTest->onHwFailureCallback();
+ return Void();
+ }
+
+ virtual Return<void> configChange(Result result, const BandConfig& config) {
+ ALOGI("%s result %d", __FUNCTION__, result);
+ mParentTest->onConfigChangeCallback(result, config);
+ return Void();
+ }
+
+ virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) {
+ ALOGI("%s result %d", __FUNCTION__, result);
+ mParentTest->onTuneCompleteCallback(result, info);
+ return Void();
+ }
+
+ virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
+ return Void();
+ }
+
+ virtual Return<void> antennaStateChange(bool connected) {
+ ALOGI("%s connected %d", __FUNCTION__, connected);
+ return Void();
+ }
+
+ virtual Return<void> trafficAnnouncement(bool active) {
+ ALOGI("%s active %d", __FUNCTION__, active);
+ return Void();
+ }
+
+ virtual Return<void> emergencyAnnouncement(bool active) {
+ ALOGI("%s active %d", __FUNCTION__, active);
+ return Void();
+ }
+
+ virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
+ const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
+
+ private:
+ // BroadcastRadioHidlTest instance to which callbacks will be notified.
+ BroadcastRadioHidlTest *mParentTest;
+ };
+
+
+ /**
+ * Method called by MyCallback when a callback with no status or boolean value is received
+ */
+ void onCallback() {
+ Mutex::Autolock _l(mLock);
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when hardwareFailure() callback is received
+ */
+ void onHwFailureCallback() {
+ Mutex::Autolock _l(mLock);
+ mHwFailure = true;
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when configChange() callback is received.
+ */
+ void onConfigChangeCallback(Result result, const BandConfig& config) {
+ Mutex::Autolock _l(mLock);
+ mResultCallbackData = result;
+ mBandConfigCallbackData = config;
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when tuneComplete() callback is received.
+ */
+ void onTuneCompleteCallback(Result result, const ProgramInfo& info) {
+ Mutex::Autolock _l(mLock);
+ mResultCallbackData = result;
+ mProgramInfoCallbackData = info;
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when a boolean indication is received
+ */
+ void onBoolCallback(bool result) {
+ Mutex::Autolock _l(mLock);
+ mBoolCallbackData = result;
+ onCallback_l();
+ }
+
+
+ BroadcastRadioHidlTest() :
+ mCallbackCalled(false), mBoolCallbackData(false),
+ mResultCallbackData(Result::OK), mHwFailure(false) {}
+
+ void onCallback_l() {
+ if (!mCallbackCalled) {
+ mCallbackCalled = true;
+ mCallbackCond.broadcast();
+ }
+ }
+
+
+ bool waitForCallback(nsecs_t reltime = 0) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t endTime = systemTime() + reltime;
+ while (!mCallbackCalled) {
+ if (reltime == 0) {
+ mCallbackCond.wait(mLock);
+ } else {
+ nsecs_t now = systemTime();
+ if (now > endTime) {
+ return false;
+ }
+ mCallbackCond.waitRelative(mLock, endTime - now);
+ }
+ }
+ return true;
+ }
+
+ bool getProperties();
+ bool openTuner();
+ bool checkAntenna();
+
+ static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
+ static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
+
+ sp<IBroadcastRadio> mRadio;
+ Properties mHalProperties;
+ sp<ITuner> mTuner;
+ sp<MyCallback> mTunerCallback;
+ Mutex mLock;
+ Condition mCallbackCond;
+ bool mCallbackCalled;
+ bool mBoolCallbackData;
+ Result mResultCallbackData;
+ ProgramInfo mProgramInfoCallbackData;
+ BandConfig mBandConfigCallbackData;
+ bool mHwFailure;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class BroadcastRadioHidlEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+};
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_0 {
+
+/**
+ * Compares two BandConfig objects for testing purposes.
+ */
+static bool operator==(const BandConfig& l, const BandConfig& r) {
+ if (l.type != r.type) return false;
+ if (l.antennaConnected != r.antennaConnected) return false;
+ if (l.lowerLimit != r.lowerLimit) return false;
+ if (l.upperLimit != r.upperLimit) return false;
+ if (l.spacings != r.spacings) return false;
+ if (l.type == Band::AM || l.type == Band::AM_HD) {
+ return l.ext.am == r.ext.am;
+ } else if (l.type == Band::FM || l.type == Band::FM_HD) {
+ return l.ext.fm == r.ext.fm;
+ } else {
+ // unsupported type
+ return false;
+ }
+}
+
+} // V1_0
+} // broadcastradio
+} // hardware
+} // android
+
+bool BroadcastRadioHidlTest::getProperties()
+{
+ if (mHalProperties.bands.size() == 0) {
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mRadio->getProperties([&](Result result, const Properties& properties) {
+ halResult = result;
+ if (result == Result::OK) {
+ mHalProperties = properties;
+ }
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
+ EXPECT_GT(mHalProperties.numTuners, 0u);
+ EXPECT_GT(mHalProperties.bands.size(), 0u);
+ }
+ return mHalProperties.bands.size() > 0;
+}
+
+bool BroadcastRadioHidlTest::openTuner()
+{
+ if (!getProperties()) {
+ return false;
+ }
+ if (mTuner.get() == nullptr) {
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
+ [&](Result result, const sp<ITuner>& tuner) {
+ halResult = result;
+ if (result == Result::OK) {
+ mTuner = tuner;
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+ }
+ EXPECT_NE(nullptr, mTuner.get());
+ return nullptr != mTuner.get();
+}
+
+bool BroadcastRadioHidlTest::checkAntenna()
+{
+ BandConfig halConfig;
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ if (result == Result::OK) {
+ halConfig = config;
+ }
+ });
+
+ return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
+}
+
+
+/**
+ * Test IBroadcastRadio::getProperties() method
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the implementation class is AM_FM
+ * - the implementation supports at least one tuner
+ * - the implementation supports at one band
+ */
+TEST_F(BroadcastRadioHidlTest, GetProperties) {
+ EXPECT_EQ(true, getProperties());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() method
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error) and a valid ITuner interface
+ */
+TEST_F(BroadcastRadioHidlTest, OpenTuner) {
+ EXPECT_EQ(true, openTuner());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() after ITuner disposal.
+ *
+ * Verifies that:
+ * - ITuner destruction gets propagated through HAL
+ * - the openTuner method works well when called for the second time
+ */
+TEST_F(BroadcastRadioHidlTest, ReopenTuner) {
+ EXPECT_TRUE(openTuner());
+ mTuner.clear();
+ EXPECT_TRUE(openTuner());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() method called twice.
+ *
+ * Verifies that:
+ * - the openTuner method fails when called for the second time without deleting previous
+ * ITuner instance
+ */
+TEST_F(BroadcastRadioHidlTest, OpenTunerTwice) {
+ EXPECT_TRUE(openTuner());
+
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
+ [&](Result result, const sp<ITuner>&) {
+ halResult = result;
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::INVALID_STATE, halResult);
+ EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::setConfiguration() and getConfiguration methods
+ *
+ * Verifies that:
+ * - the HAL implements both methods
+ * - the methods return 0 (no error)
+ * - the configuration callback is received within kConfigCallbacktimeoutNs ns
+ * - the configuration read back from HAl has the same class Id
+ */
+TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
+ ASSERT_EQ(true, openTuner());
+ // test setConfiguration
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[1]);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+ EXPECT_EQ(Result::OK, mResultCallbackData);
+ EXPECT_EQ(mHalProperties.bands[1], mBandConfigCallbackData);
+
+ // test getConfiguration
+ BandConfig halConfig;
+ Result halResult;
+ Return<void> hidlReturn =
+ mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ if (result == Result::OK) {
+ halConfig = config;
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_EQ(mHalProperties.bands[1], halConfig);
+}
+
+/**
+ * Test ITuner::setConfiguration() with invalid arguments.
+ *
+ * Verifies that:
+ * - the methods returns INVALID_ARGUMENTS on invalid arguments
+ * - the method recovers and succeeds after passing correct arguments
+ */
+TEST_F(BroadcastRadioHidlTest, SetConfigurationFails) {
+ ASSERT_EQ(true, openTuner());
+
+ // Let's define a config that's bad for sure.
+ BandConfig badConfig = {};
+ badConfig.type = Band::FM;
+ badConfig.lowerLimit = 0xFFFFFFFF;
+ badConfig.upperLimit = 0;
+ badConfig.spacings = (std::vector<uint32_t>){ 0 };
+
+ // Test setConfiguration failing on bad data.
+ mCallbackCalled = false;
+ auto setResult = mTuner->setConfiguration(badConfig);
+ EXPECT_TRUE(setResult.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult);
+
+ // Test setConfiguration recovering after passing good data.
+ mCallbackCalled = false;
+ setResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+ EXPECT_TRUE(setResult.isOk());
+ EXPECT_EQ(Result::OK, setResult);
+ EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+ EXPECT_EQ(Result::OK, mResultCallbackData);
+}
+
+/**
+ * Test ITuner::scan
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ * - skipping sub-channel or not does not fail the call
+ */
+TEST_F(BroadcastRadioHidlTest, Scan) {
+ ASSERT_EQ(true, openTuner());
+ ASSERT_TRUE(checkAntenna());
+ // test scan UP
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+
+ // test scan DOWN
+ mCallbackCalled = false;
+ hidlResult = mTuner->scan(Direction::DOWN, false);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::step
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ * - skipping sub-channel or not does not fail the call
+ */
+TEST_F(BroadcastRadioHidlTest, Step) {
+ ASSERT_EQ(true, openTuner());
+ ASSERT_TRUE(checkAntenna());
+ // test step UP
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->step(Direction::UP, false);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+
+ // test step DOWN
+ mCallbackCalled = false;
+ hidlResult = mTuner->step(Direction::DOWN, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::tune, getProgramInformation and cancel methods
+ *
+ * Verifies that:
+ * - the HAL implements the methods
+ * - the methods return 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
+ */
+TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
+ ASSERT_EQ(true, openTuner());
+ ASSERT_TRUE(checkAntenna());
+
+ // test tune
+ ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
+ ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
+
+ // test scan UP
+ uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
+ uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
+ uint32_t spacing = mHalProperties.bands[0].spacings[0];
+
+ uint32_t channel =
+ lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
+ mCallbackCalled = false;
+ mResultCallbackData = Result::NOT_INITIALIZED;
+ Return<Result> hidlResult = mTuner->tune(channel, 0);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+ EXPECT_EQ(channel, mProgramInfoCallbackData.channel);
+
+ // test getProgramInformation
+ ProgramInfo halInfo;
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn = mTuner->getProgramInformation(
+ [&](Result result, const ProgramInfo& info) {
+ halResult = result;
+ if (result == Result::OK) {
+ halInfo = info;
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ if (mResultCallbackData == Result::OK) {
+ EXPECT_EQ(true, halInfo.tuned);
+ EXPECT_LE(halInfo.channel, upperLimit);
+ EXPECT_GE(halInfo.channel, lowerLimit);
+ } else {
+ EXPECT_EQ(false, halInfo.tuned);
+ }
+
+ // test cancel
+ mTuner->tune(lowerLimit, 0);
+ hidlResult = mTuner->cancel();
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+}
+
+/**
+ * Test ITuner::tune failing when channel out of the range is provided.
+ *
+ * Verifies that:
+ * - the method returns INVALID_ARGUMENTS when applicable
+ * - the method recovers and succeeds after passing correct arguments
+ */
+TEST_F(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
+ ASSERT_TRUE(openTuner());
+ ASSERT_TRUE(checkAntenna());
+
+ // get current channel bounds
+ BandConfig halConfig;
+ Result halResult;
+ auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ halConfig = config;
+ });
+ ASSERT_TRUE(configResult.isOk());
+ ASSERT_EQ(Result::OK, halResult);
+
+ // try to tune slightly above the limit and expect to fail
+ auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
+ auto tuneResult = mTuner->tune(badChannel, 0);
+ EXPECT_TRUE(tuneResult.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+ // tuning exactly at the limit should succeed
+ auto goodChannel = halConfig.upperLimit;
+ tuneResult = mTuner->tune(goodChannel, 0);
+ EXPECT_TRUE(tuneResult.isOk());
+ EXPECT_EQ(Result::OK, tuneResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/broadcastradio/1.1/Android.bp b/broadcastradio/1.1/Android.bp
new file mode 100644
index 0000000..570d1ae
--- /dev/null
+++ b/broadcastradio/1.1/Android.bp
@@ -0,0 +1,78 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.broadcastradio@1.1_hal",
+ srcs: [
+ "types.hal",
+ "IBroadcastRadioFactory.hal",
+ "ITuner.hal",
+ "ITunerCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.broadcastradio@1.1_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.1",
+ srcs: [
+ ":android.hardware.broadcastradio@1.1_hal",
+ ],
+ out: [
+ "android/hardware/broadcastradio/1.1/types.cpp",
+ "android/hardware/broadcastradio/1.1/BroadcastRadioFactoryAll.cpp",
+ "android/hardware/broadcastradio/1.1/TunerAll.cpp",
+ "android/hardware/broadcastradio/1.1/TunerCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.broadcastradio@1.1_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.1",
+ srcs: [
+ ":android.hardware.broadcastradio@1.1_hal",
+ ],
+ out: [
+ "android/hardware/broadcastradio/1.1/types.h",
+ "android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.1/IHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.1/BnHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.1/BpHwBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.1/BsBroadcastRadioFactory.h",
+ "android/hardware/broadcastradio/1.1/ITuner.h",
+ "android/hardware/broadcastradio/1.1/IHwTuner.h",
+ "android/hardware/broadcastradio/1.1/BnHwTuner.h",
+ "android/hardware/broadcastradio/1.1/BpHwTuner.h",
+ "android/hardware/broadcastradio/1.1/BsTuner.h",
+ "android/hardware/broadcastradio/1.1/ITunerCallback.h",
+ "android/hardware/broadcastradio/1.1/IHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.1/BnHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.1/BpHwTunerCallback.h",
+ "android/hardware/broadcastradio/1.1/BsTunerCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.broadcastradio@1.1",
+ generated_sources: ["android.hardware.broadcastradio@1.1_genc++"],
+ generated_headers: ["android.hardware.broadcastradio@1.1_genc++_headers"],
+ export_generated_headers: ["android.hardware.broadcastradio@1.1_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.broadcastradio@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.broadcastradio@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/broadcastradio/1.1/Android.mk b/broadcastradio/1.1/Android.mk
new file mode 100644
index 0000000..0c4c55d
--- /dev/null
+++ b/broadcastradio/1.1/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.1/IBroadcastRadioFactory.hal b/broadcastradio/1.1/IBroadcastRadioFactory.hal
new file mode 100644
index 0000000..fce1cc0
--- /dev/null
+++ b/broadcastradio/1.1/IBroadcastRadioFactory.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.broadcastradio@1.1;
+
+import @1.0::IBroadcastRadioFactory;
+
+/**
+ * To use 1.1 features you must cast specific interfaces after being returned from 1.0 HAL,
+ * for example V1_1::ITuner::castFrom() after retrieving it from IBroadcastRadio::openTuner().
+ * The 1.1 server must always return the 1.1 version of specific interface.
+ */
+interface IBroadcastRadioFactory extends @1.0::IBroadcastRadioFactory {
+};
diff --git a/broadcastradio/1.1/ITuner.hal b/broadcastradio/1.1/ITuner.hal
new file mode 100644
index 0000000..4f34019
--- /dev/null
+++ b/broadcastradio/1.1/ITuner.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.broadcastradio@1.1;
+
+import @1.0::ITuner;
+
+interface ITuner extends @1.0::ITuner {
+
+ /**
+ * Retrieve current station information.
+ * @return result OK if scan successfully started
+ * NOT_INITIALIZED if another error occurs
+ * @return info Current program information.
+ */
+ getProgramInformation_1_1() generates(Result result, ProgramInfo info);
+
+ /**
+ * Retrieve station list.
+ *
+ * This call does not trigger actual scan, but operates on the list cached
+ * internally at the driver level.
+ *
+ * @param filter vendor-specific filter for the stations to be retrieved.
+ * An empty string MUST result in full list.
+ * Client application MUST verify vendor/product name
+ * before setting this parameter to anything else.
+ * @return result OK if the list was successfully retrieved.
+ * NOT_READY if the scan is in progress.
+ * NOT_STARTED if the scan has not been started.
+ * NOT_INITIALIZED if any other error occurs.
+ * @return programList List of stations available for user.
+ */
+ getProgramList(string filter)
+ generates(ProgramListResult result, vec<ProgramInfo> programList);
+
+};
diff --git a/broadcastradio/1.1/ITunerCallback.hal b/broadcastradio/1.1/ITunerCallback.hal
new file mode 100644
index 0000000..4af6b1f
--- /dev/null
+++ b/broadcastradio/1.1/ITunerCallback.hal
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.broadcastradio@1.1;
+
+import @1.0::ITunerCallback;
+
+/**
+ * Some methods of @1.1::ITunerCallback are updated versions of those from @1.0:ITunerCallback.
+ * All 1.1 drivers should call both (eg. tuneComplete and tuneComplete_1_1), while 1.1 clients
+ * should ignore 1.0 ones, to avoid receiving a callback twice.
+ */
+interface ITunerCallback extends @1.0::ITunerCallback {
+ /*
+ * Method called by the HAL when a tuning operation completes
+ * following a step(), scan() or tune() command.
+ * @param result OK if tune succeeded or TIMEOUT in case of time out.
+ * @param info A ProgramInfo structure describing the tuned station.
+ */
+ oneway tuneComplete_1_1(Result result, ProgramInfo info);
+
+ /*
+ * Method called by the HAL when a frequency switch occurs.
+ * @param info A ProgramInfo structure describing the new tuned station.
+ */
+ oneway afSwitch_1_1(ProgramInfo info);
+};
diff --git a/broadcastradio/1.1/WARNING b/broadcastradio/1.1/WARNING
new file mode 100644
index 0000000..e867cfa
--- /dev/null
+++ b/broadcastradio/1.1/WARNING
@@ -0,0 +1 @@
+This is experimental interface, do not use it yet.
diff --git a/broadcastradio/1.1/default/Android.mk b/broadcastradio/1.1/default/Android.mk
new file mode 100644
index 0000000..bb32d50
--- /dev/null
+++ b/broadcastradio/1.1/default/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.broadcastradio@1.1-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_CFLAGS += -Werror -Wall -Wextra
+LOCAL_SRC_FILES := \
+ BroadcastRadio.cpp \
+ BroadcastRadioFactory.cpp \
+ Tuner.cpp \
+ Utils.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ liblog \
+ libhardware \
+ android.hardware.broadcastradio@1.0 \
+ android.hardware.broadcastradio@1.1 \
+ libradio_metadata
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..611267b
--- /dev/null
+++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#define LOG_TAG "BroadcastRadio"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+BroadcastRadio::BroadcastRadio(Class classId)
+ : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL)
+{
+}
+
+BroadcastRadio::~BroadcastRadio()
+{
+ if (mHwDevice != NULL) {
+ radio_hw_device_close(mHwDevice);
+ }
+}
+
+void BroadcastRadio::onFirstRef()
+{
+ const hw_module_t *mod;
+ int rc;
+ ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
+
+ mHwDevice = NULL;
+ const char *classString = Utils::getClassString(mClassId);
+ if (classString == NULL) {
+ ALOGE("invalid class ID %d", mClassId);
+ mStatus = Result::INVALID_ARGUMENTS;
+ return;
+ }
+
+ ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
+ __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString);
+
+ rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load radio module %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc));
+ return;
+ }
+ rc = radio_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open radio hw device in %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
+ radio_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ } else {
+ mStatus = Result::OK;
+ }
+}
+
+int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
+{
+ ALOGV("%s", __FUNCTION__);
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ if (halTuner == 0) {
+ return -EINVAL;
+ }
+ return mHwDevice->close_tuner(mHwDevice, halTuner);
+}
+
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb)
+{
+ int rc;
+ radio_hal_properties_t halProperties;
+ Properties properties;
+
+ if (mHwDevice == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ rc = mHwDevice->get_properties(mHwDevice, &halProperties);
+ if (rc == 0) {
+ Utils::convertPropertiesFromHal(&properties, &halProperties);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), properties);
+ return Void();
+}
+
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio,
+ const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb)
+{
+ sp<Tuner> tunerImpl = new Tuner(callback, this);
+
+ radio_hal_band_config_t halConfig;
+ const struct radio_tuner *halTuner;
+ Utils::convertBandConfigToHal(&halConfig, &config);
+ int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, Tuner::callback,
+ tunerImpl.get(), &halTuner);
+ if (rc == 0) {
+ tunerImpl->setHalTuner(halTuner);
+ }
+
+ _hidl_cb(Utils::convertHalResult(rc), tunerImpl);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadio.h b/broadcastradio/1.1/default/BroadcastRadio.h
new file mode 100644
index 0000000..068979d
--- /dev/null
+++ b/broadcastradio/1.1/default/BroadcastRadio.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
+
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.1/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Class;
+using V1_0::BandConfig;
+using V1_0::Properties;
+
+struct BroadcastRadio : public V1_0::IBroadcastRadio {
+
+ BroadcastRadio(Class classId);
+
+ // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> openTuner(const BandConfig& config, bool audio,
+ const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) override;
+
+ // RefBase
+ virtual void onFirstRef() override;
+
+ Result initCheck() { return mStatus; }
+ int closeHalTuner(const struct radio_tuner *halTuner);
+
+private:
+ virtual ~BroadcastRadio();
+
+ static const char * sClassModuleNames[];
+
+ Result convertHalResult(int rc);
+ void convertBandConfigFromHal(BandConfig *config,
+ const radio_hal_band_config_t *halConfig);
+ void convertPropertiesFromHal(Properties *properties,
+ const radio_hal_properties_t *halProperties);
+ void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+ const BandConfig *config);
+
+ Result mStatus;
+ Class mClassId;
+ struct radio_hw_device *mHwDevice;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
new file mode 100644
index 0000000..c8b6c39
--- /dev/null
+++ b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#include "BroadcastRadioFactory.h"
+#include "BroadcastRadio.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
+ sp<BroadcastRadio> impl = new BroadcastRadio(classId);
+ Result retval = Result::NOT_INITIALIZED;
+ if (impl != 0) {
+ retval = impl->initCheck();
+ }
+ _hidl_cb(retval, impl);
+ return Void();
+}
+
+
+IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) {
+ return new BroadcastRadioFactory();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.h b/broadcastradio/1.1/default/BroadcastRadioFactory.h
new file mode 100644
index 0000000..8eb8514
--- /dev/null
+++ b/broadcastradio/1.1/default/BroadcastRadioFactory.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Class;
+
+struct BroadcastRadioFactory : public IBroadcastRadioFactory {
+ // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
+ Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override;
+};
+
+extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
new file mode 100644
index 0000000..b4eb184
--- /dev/null
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "Tuner"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+#include "Utils.h"
+#include <system/RadioMetadataWrapper.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+void Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+ BandConfig config;
+ ProgramInfo info;
+ hidl_vec<MetaData> metadata;
+
+ if (mCallback != 0) {
+ switch(halEvent->type) {
+ case RADIO_EVENT_CONFIG:
+ Utils::convertBandConfigFromHal(&config, &halEvent->config);
+ mCallback->configChange(Utils::convertHalResult(halEvent->status), config);
+ break;
+ case RADIO_EVENT_ANTENNA:
+ mCallback->antennaStateChange(halEvent->on);
+ break;
+ case RADIO_EVENT_TUNED:
+ Utils::convertProgramInfoFromHal(&info, &halEvent->info);
+ if (mCallback1_1 != nullptr) {
+ mCallback1_1->tuneComplete_1_1(Utils::convertHalResult(halEvent->status), info);
+ }
+ mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info.base);
+ break;
+ case RADIO_EVENT_METADATA: {
+ uint32_t channel;
+ uint32_t sub_channel;
+ if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) {
+ Utils::convertMetaDataFromHal(metadata, halEvent->metadata);
+ mCallback->newMetadata(channel, sub_channel, metadata);
+ }
+ } break;
+ case RADIO_EVENT_TA:
+ mCallback->trafficAnnouncement(halEvent->on);
+ break;
+ case RADIO_EVENT_AF_SWITCH:
+ Utils::convertProgramInfoFromHal(&info, &halEvent->info);
+ if (mCallback1_1 != nullptr) {
+ mCallback1_1->afSwitch_1_1(info);
+ }
+ mCallback->afSwitch(info.base);
+ break;
+ case RADIO_EVENT_EA:
+ mCallback->emergencyAnnouncement(halEvent->on);
+ break;
+ case RADIO_EVENT_HW_FAILURE:
+ default:
+ mCallback->hardwareFailure();
+ break;
+ }
+ }
+}
+
+//static
+void Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
+{
+ wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie));
+ sp<Tuner> tuner = weak.promote();
+ if (tuner == 0) return;
+ tuner->onCallback(halEvent);
+}
+
+Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice)
+ : mHalTuner(NULL), mCallback(callback), mCallback1_1(ITunerCallback::castFrom(callback)),
+ mParentDevice(parentDevice)
+{
+ ALOGV("%s", __FUNCTION__);
+}
+
+
+Tuner::~Tuner()
+{
+ ALOGV("%s", __FUNCTION__);
+ const sp<BroadcastRadio> parentDevice = mParentDevice.promote();
+ if (parentDevice != 0) {
+ parentDevice->closeHalTuner(mHalTuner);
+ }
+}
+
+// Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow.
+Return<Result> Tuner::setConfiguration(const BandConfig& config) {
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ radio_hal_band_config_t halConfig;
+ Utils::convertBandConfigToHal(&halConfig, &config);
+ int rc = mHalTuner->set_configuration(mHalTuner, &halConfig);
+ return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
+ int rc;
+ radio_hal_band_config_t halConfig;
+ BandConfig config;
+
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+ rc = mHalTuner->get_configuration(mHalTuner, &halConfig);
+ if (rc == 0) {
+ Utils::convertBandConfigFromHal(&config, &halConfig);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), config);
+ return Void();
+}
+
+Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->tune(mHalTuner, channel, subChannel);
+ return Utils::convertHalResult(rc);
+}
+
+Return<Result> Tuner::cancel() {
+ if (mHalTuner == NULL) {
+ return Utils::convertHalResult(-ENODEV);
+ }
+ int rc = mHalTuner->cancel(mHalTuner);
+ return Utils::convertHalResult(rc);
+}
+
+Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+ return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
+ _hidl_cb(result, info.base);
+ });
+}
+
+Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
+ int rc;
+ radio_program_info_t halInfo;
+ RadioMetadataWrapper metadataWrapper(&halInfo.metadata);
+ ProgramInfo info;
+
+ ALOGV("%s", __FUNCTION__);
+ if (mHalTuner == NULL) {
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ rc = mHalTuner->get_program_information(mHalTuner, &halInfo);
+ if (rc == 0) {
+ Utils::convertProgramInfoFromHal(&info, &halInfo);
+ }
+
+exit:
+ _hidl_cb(Utils::convertHalResult(rc), info);
+ return Void();
+}
+
+Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) {
+ hidl_vec<ProgramInfo> pList;
+ // TODO(b/34054813): do the actual implementation.
+ _hidl_cb(ProgramListResult::NOT_INITIALIZED, pList);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
new file mode 100644
index 0000000..fcf053a
--- /dev/null
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
+
+#include <android/hardware/broadcastradio/1.1/ITuner.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Direction;
+
+struct BroadcastRadio;
+
+struct Tuner : public ITuner {
+
+ Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice);
+
+ // Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow.
+ Return<Result> setConfiguration(const BandConfig& config) override;
+ Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override;
+ Return<Result> scan(Direction direction, bool skipSubChannel) override;
+ Return<Result> step(Direction direction, bool skipSubChannel) override;
+ Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
+ Return<Result> cancel() override;
+ Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
+ Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
+ Return<void> getProgramList(const hidl_string& filter, getProgramList_cb _hidl_cb) override;
+
+ static void callback(radio_hal_event_t *halEvent, void *cookie);
+ void onCallback(radio_hal_event_t *halEvent);
+
+ void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
+ const struct radio_tuner *getHalTuner() { return mHalTuner; }
+
+private:
+ ~Tuner();
+
+ const struct radio_tuner *mHalTuner;
+ const sp<V1_0::ITunerCallback> mCallback;
+ const sp<V1_1::ITunerCallback> mCallback1_1;
+ const wp<BroadcastRadio> mParentDevice;
+};
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
diff --git a/broadcastradio/1.1/default/Utils.cpp b/broadcastradio/1.1/default/Utils.cpp
new file mode 100644
index 0000000..e21344e
--- /dev/null
+++ b/broadcastradio/1.1/default/Utils.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#define LOG_TAG "BroadcastRadioHalUtils"
+//#define LOG_NDEBUG 0
+
+#include <log/log.h>
+#include <system/radio_metadata.h>
+
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Band;
+using V1_0::Deemphasis;
+using V1_0::Direction;
+using V1_0::MetadataKey;
+using V1_0::MetadataType;
+using V1_0::Rds;
+
+const char *Utils::sClassModuleNames[] = {
+ RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
+ RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */
+ RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */
+};
+
+// make sure HIDL enum values are aligned with legacy values
+static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM),
+ "AM/FM class mismatch with legacy");
+static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT),
+ "SAT class mismatch with legacy");
+static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT),
+ "DT class mismatch with legacy");
+
+static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM),
+ "AM band mismatch with legacy");
+static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM),
+ "FM band mismatch with legacy");
+static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD),
+ "AM HD band mismatch with legacy");
+static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD),
+ "FM HD band mismatch with legacy");
+
+static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE),
+ "RDS NONE mismatch with legacy");
+static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD),
+ "RDS WORLD mismatch with legacy");
+static_assert(RADIO_RDS_US == static_cast<int>(Rds::US),
+ "RDS US mismatch with legacy");
+
+static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50),
+ "De-emphasis 50 mismatch with legacy");
+static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75),
+ "De-emphasis 75 mismatch with legacy");
+
+static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP),
+ "Direction Up mismatch with legacy");
+static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN),
+ "Direction Up mismatch with legacy");
+
+static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID),
+ "Metadata type INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT),
+ "Metadata type INT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT),
+ "Metadata type TEXT mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW),
+ "Metadata type RAW mismatch with legacy");
+static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK),
+ "Metadata type CLOCK mismatch with legacy");
+
+static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID),
+ "Metadata key INVALID mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI),
+ "Metadata key RDS_PI mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS),
+ "Metadata key RDS_PS mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY),
+ "Metadata key RDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY),
+ "Metadata key RBDS_PTY mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT),
+ "Metadata key RDS_RT mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE),
+ "Metadata key TITLE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST),
+ "Metadata key ARTIST mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM),
+ "Metadata key ALBUM mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE),
+ "Metadata key GENRE mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON),
+ "Metadata key ICON mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART),
+ "Metadata key ART mismatch with legacy");
+static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK),
+ "Metadata key CLOCK mismatch with legacy");
+
+
+//static
+const char * Utils::getClassString(Class ClassId)
+{
+ int id = static_cast<int>(ClassId);
+
+ if ((id < 0) ||
+ (id >= NELEM(sClassModuleNames))) {
+ ALOGE("invalid class ID %d", id);
+ return NULL;
+ }
+ return sClassModuleNames[id];
+}
+
+//static
+Result Utils::convertHalResult(int rc)
+{
+ switch (rc) {
+ case 0:
+ return Result::OK;
+ case -EINVAL:
+ return Result::INVALID_ARGUMENTS;
+ case -ENOSYS:
+ return Result::INVALID_STATE;
+ case -ETIMEDOUT:
+ return Result::TIMEOUT;
+ case -ENODEV:
+ default:
+ return Result::NOT_INITIALIZED;
+ }
+}
+
+//static
+void Utils::convertBandConfigFromHal(
+ BandConfig *config,
+ const radio_hal_band_config_t *halConfig)
+{
+
+ config->type = static_cast<Band>(halConfig->type);
+ config->antennaConnected = halConfig->antenna_connected;
+ config->lowerLimit = halConfig->lower_limit;
+ config->upperLimit = halConfig->upper_limit;
+ config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]),
+ halConfig->num_spacings * sizeof(uint32_t));
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ config->spacings.resize(halConfig->num_spacings);
+
+ if (config->type == Band::FM) {
+ config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis);
+ config->ext.fm.stereo = halConfig->fm.stereo;
+ config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds);
+ config->ext.fm.ta = halConfig->fm.ta;
+ config->ext.fm.af = halConfig->fm.af;
+ config->ext.fm.ea = halConfig->fm.ea;
+ } else {
+ config->ext.am.stereo = halConfig->am.stereo;
+ }
+}
+
+//static
+void Utils::convertPropertiesFromHal(Properties *properties,
+ const radio_hal_properties_t *halProperties)
+{
+ properties->classId = static_cast<Class>(halProperties->class_id);
+ properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor));
+ properties->product.setToExternal(halProperties->product, strlen(halProperties->product));
+ properties->version.setToExternal(halProperties->version, strlen(halProperties->version));
+ properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial));
+ properties->numTuners = halProperties->num_tuners;
+ properties->numAudioSources = halProperties->num_audio_sources;
+ properties->supportsCapture = halProperties->supports_capture;
+
+ BandConfig *bands =
+ new BandConfig[halProperties->num_bands];
+ for (size_t i = 0; i < halProperties->num_bands; i++) {
+ convertBandConfigFromHal(&bands[i], &halProperties->bands[i]);
+ }
+ properties->bands.setToExternal(bands, halProperties->num_bands);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ properties->bands.resize(halProperties->num_bands);
+ delete[] bands;
+}
+
+//static
+void Utils::convertBandConfigToHal(radio_hal_band_config_t *halConfig, const BandConfig *config)
+{
+ halConfig->type = static_cast<radio_band_t>(config->type);
+ halConfig->antenna_connected = config->antennaConnected;
+ halConfig->lower_limit = config->lowerLimit;
+ halConfig->upper_limit = config->upperLimit;
+ halConfig->num_spacings = config->spacings.size();
+ if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) {
+ halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX;
+ }
+ memcpy(halConfig->spacings, config->spacings.data(),
+ sizeof(uint32_t) * halConfig->num_spacings);
+
+ if (config->type == Band::FM) {
+ halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis);
+ halConfig->fm.stereo = config->ext.fm.stereo;
+ halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds);
+ halConfig->fm.ta = config->ext.fm.ta;
+ halConfig->fm.af = config->ext.fm.af;
+ halConfig->fm.ea = config->ext.fm.ea;
+ } else {
+ halConfig->am.stereo = config->ext.am.stereo;
+ }
+}
+
+
+//static
+void Utils::convertProgramInfoFromHal(ProgramInfo *info, radio_program_info_t *halInfo)
+{
+ auto &info_1_1 = *info;
+ auto &info_1_0 = info->base;
+
+ info_1_0.channel = halInfo->channel;
+ info_1_0.subChannel = halInfo->sub_channel;
+ info_1_0.tuned = halInfo->tuned;
+ info_1_0.stereo = halInfo->stereo;
+ info_1_0.digital = halInfo->digital;
+ info_1_0.signalStrength = halInfo->signal_strength;
+ convertMetaDataFromHal(info_1_0.metadata, halInfo->metadata);
+ // TODO(b/34348946): add support for HAL 1.1 fields
+ info_1_1.flags = 0;
+}
+
+//static
+int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, radio_metadata_t *halMetadata)
+{
+ if (halMetadata == NULL) {
+ ALOGE("Invalid argument: halMetadata is NULL");
+ return 0;
+ }
+
+ int count = radio_metadata_get_count(halMetadata);
+ if (count <= 0) {
+ return count;
+ }
+ MetaData *newMetadata = new MetaData[count];
+ int outCount = 0;
+ for (int i = 0; i < count; i++) {
+ radio_metadata_key_t key;
+ radio_metadata_type_t type;
+ void *value;
+ size_t size;
+ if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 ||
+ size == 0) {
+ continue;
+ }
+ switch (type) {
+ case RADIO_METADATA_TYPE_INT: {
+ newMetadata[outCount].intValue = *(static_cast<int32_t *>(value));
+ } break;
+ case RADIO_METADATA_TYPE_TEXT: {
+ newMetadata[outCount].stringValue = static_cast<char *>(value);
+ } break;
+ case RADIO_METADATA_TYPE_RAW: {
+ newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ newMetadata[outCount].rawValue.resize(size);
+ } break;
+ case RADIO_METADATA_TYPE_CLOCK: {
+ radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value);
+ newMetadata[outCount].clockValue.utcSecondsSinceEpoch =
+ clock->utc_seconds_since_epoch;
+ newMetadata[outCount].clockValue.timezoneOffsetInMinutes =
+ clock->timezone_offset_in_minutes;
+ } break;
+ }
+ newMetadata[outCount].type = static_cast<MetadataType>(type);
+ newMetadata[outCount].key = static_cast<MetadataKey>(key);
+ outCount++;
+ }
+ metadata.setToExternal(newMetadata, outCount);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ metadata.resize(outCount);
+ return outCount;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
diff --git a/broadcastradio/1.1/default/Utils.h b/broadcastradio/1.1/default/Utils.h
new file mode 100644
index 0000000..22902ba
--- /dev/null
+++ b/broadcastradio/1.1/default/Utils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Class;
+using V1_0::BandConfig;
+using V1_0::MetaData;
+using V1_0::Properties;
+
+class Utils {
+public:
+ static const char * getClassString(Class ClassId);
+ static Result convertHalResult(int rc);
+ static void convertBandConfigFromHal(BandConfig *config,
+ const radio_hal_band_config_t *halConfig);
+ static void convertPropertiesFromHal(Properties *properties,
+ const radio_hal_properties_t *halProperties);
+ static void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
+ const BandConfig *config);
+ static void convertProgramInfoFromHal(ProgramInfo *info,
+ radio_program_info_t *halInfo);
+ static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
+ radio_metadata_t *halMetadata);
+private:
+ static const char * sClassModuleNames[];
+
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace broadcastradio
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
diff --git a/broadcastradio/1.1/types.hal b/broadcastradio/1.1/types.hal
new file mode 100644
index 0000000..b6f72d2
--- /dev/null
+++ b/broadcastradio/1.1/types.hal
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2017 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.broadcastradio@1.1;
+
+import @1.0::types;
+
+typedef @1.0::Result Result;
+
+enum ProgramListResult : Result {
+ NOT_READY,
+ NOT_STARTED,
+ TEMPORARILY_UNAVAILABLE,
+};
+
+/**
+ * Extra flags for program information.
+ */
+enum ProgramInfoFlags : uint32_t {
+ /**
+ * Set when the program is currently playing live stream.
+ * This may result in a slightly altered reception parameters,
+ * usually targetted at reduced latency.
+ */
+ LIVE = 1 << 0,
+
+ /**
+ * Radio stream is not playing, ie. due to bad reception conditions or
+ * buffering. In this state volume knob MAY be disabled to prevent user
+ * increasing volume too much.
+ */
+ MUTED = 1 << 1,
+};
+
+/**
+ * Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
+ * Contains information on currently tuned channel.
+ */
+struct ProgramInfo {
+ @1.0::ProgramInfo base;
+ bitfield<ProgramInfoFlags> flags;
+
+ /**
+ * Vendors are allowed to define their own set of flags and store it in this
+ * field. They MUST verify vendor/product name from Properties struct
+ * (IBroadcastRadio::getProperties) before doing any interpretation
+ * of such values.
+ */
+ uint32_t vendorFlags;
+};
diff --git a/broadcastradio/1.1/vts/Android.mk b/broadcastradio/1.1/vts/Android.mk
new file mode 100644
index 0000000..0c4c55d
--- /dev/null
+++ b/broadcastradio/1.1/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..a4c0849
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalBroadcastradioV1_1TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.broadcastradio@1.0",
+ "android.hardware.broadcastradio@1.1",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
new file mode 100644
index 0000000..a29f6dc
--- /dev/null
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "BroadcastRadioHidlHalTest"
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/threads.h>
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.1/ITuner.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+
+namespace V1_0 = ::android::hardware::broadcastradio::V1_0;
+
+using ::android::sp;
+using ::android::Mutex;
+using ::android::Condition;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::broadcastradio::V1_0::BandConfig;
+using ::android::hardware::broadcastradio::V1_0::Class;
+using ::android::hardware::broadcastradio::V1_0::Direction;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using ::android::hardware::broadcastradio::V1_0::MetaData;
+using ::android::hardware::broadcastradio::V1_0::Properties;
+using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
+using ::android::hardware::broadcastradio::V1_1::ITuner;
+using ::android::hardware::broadcastradio::V1_1::ITunerCallback;
+using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
+using ::android::hardware::broadcastradio::V1_1::Result;
+
+
+// The main test class for Broadcast Radio HIDL HAL.
+
+class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ virtual void SetUp() override {
+ auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
+ if (factory != 0) {
+ factory->connectModule(Class::AM_FM,
+ [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
+ if (retval == Result::OK) {
+ mRadio = IBroadcastRadio::castFrom(result);
+ }
+ });
+ }
+ mTunerCallback = new MyCallback(this);
+ ASSERT_NE(nullptr, mRadio.get());
+ ASSERT_NE(nullptr, mTunerCallback.get());
+ }
+
+ virtual void TearDown() override {
+ mTuner.clear();
+ mRadio.clear();
+ }
+
+ class MyCallback : public ITunerCallback {
+ public:
+
+ // ITunerCallback methods (see doc in ITunerCallback.hal)
+ virtual Return<void> hardwareFailure() {
+ ALOGI("%s", __FUNCTION__);
+ mParentTest->onHwFailureCallback();
+ return Void();
+ }
+
+ virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
+ ALOGI("%s result %d", __FUNCTION__, result);
+ mParentTest->onResultCallback(result);
+ return Void();
+ }
+
+ virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) {
+ return Void();
+ }
+
+ virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
+ ALOGI("%s result %d", __FUNCTION__, result);
+ mParentTest->onResultCallback(result);
+ return Void();
+ }
+
+ virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
+ return Void();
+ }
+
+ virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
+ return Void();
+ }
+
+ virtual Return<void> antennaStateChange(bool connected) {
+ ALOGI("%s connected %d", __FUNCTION__, connected);
+ return Void();
+ }
+
+ virtual Return<void> trafficAnnouncement(bool active) {
+ ALOGI("%s active %d", __FUNCTION__, active);
+ return Void();
+ }
+
+ virtual Return<void> emergencyAnnouncement(bool active) {
+ ALOGI("%s active %d", __FUNCTION__, active);
+ return Void();
+ }
+
+ virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
+ const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
+
+ private:
+ // BroadcastRadioHidlTest instance to which callbacks will be notified.
+ BroadcastRadioHidlTest *mParentTest;
+ };
+
+
+ /**
+ * Method called by MyCallback when a callback with no status or boolean value is received
+ */
+ void onCallback() {
+ Mutex::Autolock _l(mLock);
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when hardwareFailure() callback is received
+ */
+ void onHwFailureCallback() {
+ Mutex::Autolock _l(mLock);
+ mHwFailure = true;
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when a callback with status is received
+ */
+ void onResultCallback(Result result) {
+ Mutex::Autolock _l(mLock);
+ mResultCallbackData = result;
+ onCallback_l();
+ }
+
+ /**
+ * Method called by MyCallback when a boolean indication is received
+ */
+ void onBoolCallback(bool result) {
+ Mutex::Autolock _l(mLock);
+ mBoolCallbackData = result;
+ onCallback_l();
+ }
+
+
+ BroadcastRadioHidlTest() :
+ mCallbackCalled(false), mBoolCallbackData(false),
+ mResultCallbackData(Result::OK), mHwFailure(false) {}
+
+ void onCallback_l() {
+ if (!mCallbackCalled) {
+ mCallbackCalled = true;
+ mCallbackCond.broadcast();
+ }
+ }
+
+
+ bool waitForCallback(nsecs_t reltime = 0) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t endTime = systemTime() + reltime;
+ while (!mCallbackCalled) {
+ if (reltime == 0) {
+ mCallbackCond.wait(mLock);
+ } else {
+ nsecs_t now = systemTime();
+ if (now > endTime) {
+ return false;
+ }
+ mCallbackCond.waitRelative(mLock, endTime - now);
+ }
+ }
+ return true;
+ }
+
+ bool getProperties();
+ bool openTuner();
+ bool checkAntenna();
+
+ static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
+ static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
+
+ sp<IBroadcastRadio> mRadio;
+ Properties mHalProperties;
+ sp<ITuner> mTuner;
+ sp<MyCallback> mTunerCallback;
+ Mutex mLock;
+ Condition mCallbackCond;
+ bool mCallbackCalled;
+ bool mBoolCallbackData;
+ Result mResultCallbackData;
+ bool mHwFailure;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class BroadcastRadioHidlEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+};
+
+bool BroadcastRadioHidlTest::getProperties()
+{
+ if (mHalProperties.bands.size() == 0) {
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mRadio->getProperties([&](Result result, const Properties& properties) {
+ halResult = result;
+ if (result == Result::OK) {
+ mHalProperties = properties;
+ }
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
+ EXPECT_GT(mHalProperties.numTuners, 0u);
+ EXPECT_GT(mHalProperties.bands.size(), 0u);
+ }
+ return mHalProperties.bands.size() > 0;
+}
+
+bool BroadcastRadioHidlTest::openTuner()
+{
+ if (!getProperties()) {
+ return false;
+ }
+ if (mTuner.get() == nullptr) {
+ Result halResult = Result::NOT_INITIALIZED;
+ auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
+ [&](Result result, const sp<V1_0::ITuner>& tuner) {
+ halResult = result;
+ if (result == Result::OK) {
+ mTuner = ITuner::castFrom(tuner);
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+ }
+ EXPECT_NE(nullptr, mTuner.get());
+ return nullptr != mTuner.get();
+}
+
+bool BroadcastRadioHidlTest::checkAntenna()
+{
+ BandConfig halConfig;
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn =
+ mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ if (result == Result::OK) {
+ halConfig = config;
+ }
+ });
+
+ return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
+}
+
+
+/**
+ * Test IBroadcastRadio::getProperties() method
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the implementation class is AM_FM
+ * - the implementation supports at least one tuner
+ * - the implementation supports at one band
+ */
+TEST_F(BroadcastRadioHidlTest, GetProperties) {
+ EXPECT_TRUE(getProperties());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() method
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error) and a valid ITuner interface
+ */
+TEST_F(BroadcastRadioHidlTest, OpenTuner) {
+ EXPECT_TRUE(openTuner());
+}
+
+/**
+ * Test ITuner::setConfiguration() and getConfiguration methods
+ *
+ * Verifies that:
+ * - the HAL implements both methods
+ * - the methods return 0 (no error)
+ * - the configuration callback is received within kConfigCallbacktimeoutNs ns
+ * - the configuration read back from HAl has the same class Id
+ */
+TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
+ ASSERT_TRUE(openTuner());
+ // test setConfiguration
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+ EXPECT_EQ(Result::OK, mResultCallbackData);
+
+ // test getConfiguration
+ BandConfig halConfig;
+ Result halResult;
+ Return<void> hidlReturn =
+ mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ if (result == Result::OK) {
+ halConfig = config;
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
+}
+
+/**
+ * Test ITuner::scan
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ */
+TEST_F(BroadcastRadioHidlTest, Scan) {
+ ASSERT_TRUE(openTuner());
+ ASSERT_TRUE(checkAntenna());
+ // test scan UP
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+ // test scan DOWN
+ mCallbackCalled = false;
+ hidlResult = mTuner->scan(Direction::DOWN, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::step
+ *
+ * Verifies that:
+ * - the HAL implements the method
+ * - the method returns 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns
+ */
+TEST_F(BroadcastRadioHidlTest, Step) {
+ ASSERT_TRUE(openTuner());
+ ASSERT_TRUE(checkAntenna());
+ // test step UP
+ mCallbackCalled = false;
+ Return<Result> hidlResult = mTuner->step(Direction::UP, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+ // test step DOWN
+ mCallbackCalled = false;
+ hidlResult = mTuner->step(Direction::DOWN, true);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+}
+
+/**
+ * Test ITuner::tune, getProgramInformation and cancel methods
+ *
+ * Verifies that:
+ * - the HAL implements the methods
+ * - the methods return 0 (no error)
+ * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
+ */
+TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
+ ASSERT_TRUE(openTuner());
+ ASSERT_TRUE(checkAntenna());
+
+ // test tune
+ ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
+ ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
+
+ // test scan UP
+ uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
+ uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
+ uint32_t spacing = mHalProperties.bands[0].spacings[0];
+
+ uint32_t channel =
+ lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
+ mCallbackCalled = false;
+ mResultCallbackData = Result::NOT_INITIALIZED;
+ Return<Result> hidlResult = mTuner->tune(channel, 0);
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+ EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
+
+ // test getProgramInformation
+ ProgramInfo halInfo;
+ Result halResult = Result::NOT_INITIALIZED;
+ Return<void> hidlReturn = mTuner->getProgramInformation_1_1(
+ [&](Result result, const ProgramInfo& info) {
+ halResult = result;
+ if (result == Result::OK) {
+ halInfo = info;
+ }
+ });
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(Result::OK, halResult);
+ auto &halInfo_1_1 = halInfo.base;
+ if (mResultCallbackData == Result::OK) {
+ EXPECT_TRUE(halInfo_1_1.tuned);
+ EXPECT_LE(halInfo_1_1.channel, upperLimit);
+ EXPECT_GE(halInfo_1_1.channel, lowerLimit);
+ } else {
+ EXPECT_EQ(false, halInfo_1_1.tuned);
+ }
+
+ // test cancel
+ mTuner->tune(lowerLimit, 0);
+ hidlResult = mTuner->cancel();
+ EXPECT_TRUE(hidlResult.isOk());
+ EXPECT_EQ(Result::OK, hidlResult);
+}
+
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/broadcastradio/Android.bp b/broadcastradio/Android.bp
new file mode 100644
index 0000000..5cacbf3
--- /dev/null
+++ b/broadcastradio/Android.bp
@@ -0,0 +1,7 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/vts/functional",
+ "1.1",
+ "1.1/vts/functional",
+]
diff --git a/camera/Android.bp b/camera/Android.bp
new file mode 100644
index 0000000..3869766
--- /dev/null
+++ b/camera/Android.bp
@@ -0,0 +1,13 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "common/1.0",
+ "common/1.0/default",
+ "device/1.0",
+ "device/1.0/default",
+ "device/3.2",
+ "device/3.2/default",
+ "metadata/3.2",
+ "provider/2.4",
+ "provider/2.4/default",
+ "provider/2.4/vts/functional",
+]
diff --git a/camera/README.md b/camera/README.md
new file mode 100644
index 0000000..8ce3352
--- /dev/null
+++ b/camera/README.md
@@ -0,0 +1,12 @@
+## Camera HALs ##
+---
+
+## Overview: ##
+
+The camera.* HAL tree is used by the Android camera service to discover and
+operate camera devices available on the device.
+
+More details and versioning information can be found within each particular HAL.
+
+More complete information about the Android camera HAL and subsystem can be found at
+[source.android.com](http://source.android.com/devices/camera/index.html).
diff --git a/camera/common/1.0/Android.bp b/camera/common/1.0/Android.bp
new file mode 100644
index 0000000..aea6e76
--- /dev/null
+++ b/camera/common/1.0/Android.bp
@@ -0,0 +1,53 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.camera.common@1.0_hal",
+ srcs: [
+ "types.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.common@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.common@1.0",
+ srcs: [
+ ":android.hardware.camera.common@1.0_hal",
+ ],
+ out: [
+ "android/hardware/camera/common/1.0/types.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.common@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.common@1.0",
+ srcs: [
+ ":android.hardware.camera.common@1.0_hal",
+ ],
+ out: [
+ "android/hardware/camera/common/1.0/types.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.common@1.0",
+ generated_sources: ["android.hardware.camera.common@1.0_genc++"],
+ generated_headers: ["android.hardware.camera.common@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.camera.common@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+}
diff --git a/camera/common/1.0/Android.mk b/camera/common/1.0/Android.mk
new file mode 100644
index 0000000..9e05172
--- /dev/null
+++ b/camera/common/1.0/Android.mk
@@ -0,0 +1,372 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.camera.common@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (CameraDeviceStatus)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraDeviceStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraDeviceStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataType)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraMetadataType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraMetadataType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraResourceCost)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraResourceCost.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraResourceCost
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TagBoundaryId)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TagBoundaryId.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TagBoundaryId
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TorchMode)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TorchMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TorchModeStatus)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchModeStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TorchModeStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VendorTag)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.VendorTag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VendorTagSection)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTagSection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.VendorTagSection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.camera.common@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (CameraDeviceStatus)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraDeviceStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraDeviceStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataType)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraMetadataType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraMetadataType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraResourceCost)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraResourceCost.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.CameraResourceCost
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TagBoundaryId)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TagBoundaryId.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TagBoundaryId
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TorchMode)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TorchMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TorchModeStatus)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchModeStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.TorchModeStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VendorTag)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.VendorTag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VendorTagSection)
+#
+GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTagSection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.common@1.0::types.VendorTagSection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
new file mode 100644
index 0000000..6437480
--- /dev/null
+++ b/camera/common/1.0/default/Android.bp
@@ -0,0 +1,21 @@
+cc_library_static {
+ name: "android.hardware.camera.common@1.0-helper",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "CameraModule.cpp",
+ "CameraMetadata.cpp",
+ "VendorTagDescriptor.cpp",
+ "HandleImporter.cpp"],
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ "-Wall",
+ ],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"],
+ include_dirs: ["system/media/private/camera/include"],
+ export_include_dirs : ["include"]
+}
+
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp
new file mode 100644
index 0000000..44c2040
--- /dev/null
+++ b/camera/common/1.0/default/CameraMetadata.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// #define LOG_NDEBUG 0
+
+#define LOG_TAG "CamComm1.0-MD"
+#include <utils/Log.h>
+#include <utils/Errors.h>
+
+#include "CameraMetadata.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+#define ALIGN_TO(val, alignment) \
+ (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+
+CameraMetadata::CameraMetadata() :
+ mBuffer(NULL), mLocked(false) {
+}
+
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
+ mLocked(false)
+{
+ mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
+}
+
+CameraMetadata::CameraMetadata(const CameraMetadata &other) :
+ mLocked(false) {
+ mBuffer = clone_camera_metadata(other.mBuffer);
+}
+
+CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
+ mBuffer(NULL), mLocked(false) {
+ acquire(buffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
+ return operator=(other.mBuffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
+ return *this;
+ }
+
+ if (CC_LIKELY(buffer != mBuffer)) {
+ camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
+ clear();
+ mBuffer = newBuffer;
+ }
+ return *this;
+}
+
+CameraMetadata::~CameraMetadata() {
+ mLocked = false;
+ clear();
+}
+
+const camera_metadata_t* CameraMetadata::getAndLock() const {
+ mLocked = true;
+ return mBuffer;
+}
+
+status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
+ if (!mLocked) {
+ ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (buffer != mBuffer) {
+ ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ mLocked = false;
+ return OK;
+}
+
+camera_metadata_t* CameraMetadata::release() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return NULL;
+ }
+ camera_metadata_t *released = mBuffer;
+ mBuffer = NULL;
+ return released;
+}
+
+void CameraMetadata::clear() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ if (mBuffer) {
+ free_camera_metadata(mBuffer);
+ mBuffer = NULL;
+ }
+}
+
+void CameraMetadata::acquire(camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ clear();
+ mBuffer = buffer;
+
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
+ "%s: Failed to validate metadata structure %p",
+ __FUNCTION__, buffer);
+}
+
+void CameraMetadata::acquire(CameraMetadata &other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ acquire(other.release());
+}
+
+status_t CameraMetadata::append(const CameraMetadata &other) {
+ return append(other.mBuffer);
+}
+
+status_t CameraMetadata::append(const camera_metadata_t* other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ size_t extraEntries = get_camera_metadata_entry_count(other);
+ size_t extraData = get_camera_metadata_data_count(other);
+ resizeIfNeeded(extraEntries, extraData);
+
+ return append_camera_metadata(mBuffer, other);
+}
+
+size_t CameraMetadata::entryCount() const {
+ return (mBuffer == NULL) ? 0 :
+ get_camera_metadata_entry_count(mBuffer);
+}
+
+bool CameraMetadata::isEmpty() const {
+ return entryCount() == 0;
+}
+
+status_t CameraMetadata::sort() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ return sort_camera_metadata(mBuffer);
+}
+
+status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
+ int tagType = get_camera_metadata_tag_type(tag);
+ if ( CC_UNLIKELY(tagType == -1)) {
+ ALOGE("Update metadata entry: Unknown tag %d", tag);
+ return INVALID_OPERATION;
+ }
+ if ( CC_UNLIKELY(tagType != expectedType) ) {
+ ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
+ "got type %s data instead ",
+ get_camera_metadata_tag_name(tag), tag,
+ camera_metadata_type_names[tagType],
+ camera_metadata_type_names[expectedType]);
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const int32_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_INT32)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const uint8_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const float *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const int64_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_INT64)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const double *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const camera_metadata_rational_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const String8 &string) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ return res;
+ }
+ // string.size() doesn't count the null termination character.
+ return updateImpl(tag, (const void*)string.string(), string.size() + 1);
+}
+
+status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(entry.tag, entry.type)) != OK) {
+ return res;
+ }
+ return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
+}
+
+status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
+ size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ int type = get_camera_metadata_tag_type(tag);
+ if (type == -1) {
+ ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ // Safety check - ensure that data isn't pointing to this metadata, since
+ // that would get invalidated if a resize is needed
+ size_t bufferSize = get_camera_metadata_size(mBuffer);
+ uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
+ uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
+ if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
+ ALOGE("%s: Update attempted with data from the same metadata buffer!",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ size_t data_size = calculate_camera_metadata_entry_data_size(type,
+ data_count);
+
+ res = resizeIfNeeded(1, data_size);
+
+ if (res == OK) {
+ camera_metadata_entry_t entry;
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ res = add_camera_metadata_entry(mBuffer,
+ tag, data, data_count);
+ } else if (res == OK) {
+ res = update_camera_metadata_entry(mBuffer,
+ entry.index, data, data_count, NULL);
+ }
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+ __FUNCTION__, get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ }
+
+ IF_ALOGV() {
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
+ OK,
+
+ "%s: Failed to validate metadata structure after update %p",
+ __FUNCTION__, mBuffer);
+ }
+
+ return res;
+}
+
+bool CameraMetadata::exists(uint32_t tag) const {
+ camera_metadata_ro_entry entry;
+ return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
+}
+
+camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+ status_t res;
+ camera_metadata_entry entry;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ entry.count = 0;
+ return entry;
+ }
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (CC_UNLIKELY( res != OK )) {
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ }
+ return entry;
+}
+
+camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+ status_t res;
+ camera_metadata_ro_entry entry;
+ res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
+ if (CC_UNLIKELY( res != OK )) {
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ }
+ return entry;
+}
+
+status_t CameraMetadata::erase(uint32_t tag) {
+ camera_metadata_entry_t entry;
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ return OK;
+ } else if (res != OK) {
+ ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ return res;
+ }
+ res = delete_camera_metadata_entry(mBuffer, entry.index);
+ if (res != OK) {
+ ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ }
+ return res;
+}
+
+void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
+ dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
+}
+
+status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+ if (mBuffer == NULL) {
+ mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
+ if (mBuffer == NULL) {
+ ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+ return NO_MEMORY;
+ }
+ } else {
+ size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
+ size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
+ size_t newEntryCount = currentEntryCount +
+ extraEntries;
+ newEntryCount = (newEntryCount > currentEntryCap) ?
+ newEntryCount * 2 : currentEntryCap;
+
+ size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
+ size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
+ size_t newDataCount = currentDataCount +
+ extraData;
+ newDataCount = (newDataCount > currentDataCap) ?
+ newDataCount * 2 : currentDataCap;
+
+ if (newEntryCount > currentEntryCap ||
+ newDataCount > currentDataCap) {
+ camera_metadata_t *oldBuffer = mBuffer;
+ mBuffer = allocate_camera_metadata(newEntryCount,
+ newDataCount);
+ if (mBuffer == NULL) {
+ ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+ return NO_MEMORY;
+ }
+ append_camera_metadata(mBuffer, oldBuffer);
+ free_camera_metadata(oldBuffer);
+ }
+ }
+ return OK;
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ } else if (other.mLocked) {
+ ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+
+ camera_metadata* thisBuf = mBuffer;
+ camera_metadata* otherBuf = other.mBuffer;
+
+ other.mBuffer = thisBuf;
+ mBuffer = otherBuf;
+}
+
+status_t CameraMetadata::getTagFromName(const char *name,
+ const VendorTagDescriptor* vTags, uint32_t *tag) {
+
+ if (name == nullptr || tag == nullptr) return BAD_VALUE;
+
+ size_t nameLength = strlen(name);
+
+ const SortedVector<String8> *vendorSections;
+ size_t vendorSectionCount = 0;
+
+ if (vTags != NULL) {
+ vendorSections = vTags->getAllSectionNames();
+ vendorSectionCount = vendorSections->size();
+ }
+
+ // First, find the section by the longest string match
+ const char *section = NULL;
+ size_t sectionIndex = 0;
+ size_t sectionLength = 0;
+ size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+ for (size_t i = 0; i < totalSectionCount; ++i) {
+
+ const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+ (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+
+ ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+
+ if (strstr(name, str) == name) { // name begins with the section name
+ size_t strLength = strlen(str);
+
+ ALOGV("%s: Name begins with section name", __FUNCTION__);
+
+ // section name is the longest we've found so far
+ if (section == NULL || sectionLength < strLength) {
+ section = str;
+ sectionIndex = i;
+ sectionLength = strLength;
+
+ ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+ }
+ }
+ }
+
+ // TODO: Make above get_camera_metadata_section_from_name ?
+
+ if (section == NULL) {
+ return NAME_NOT_FOUND;
+ } else {
+ ALOGV("%s: Found matched section '%s' (%zu)",
+ __FUNCTION__, section, sectionIndex);
+ }
+
+ // Get the tag name component of the name
+ const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
+ if (sectionLength + 1 >= nameLength) {
+ return BAD_VALUE;
+ }
+
+ // Match rest of name against the tag names in that section only
+ uint32_t candidateTag = 0;
+ if (sectionIndex < ANDROID_SECTION_COUNT) {
+ // Match built-in tags (typically android.*)
+ uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+ tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+ tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+ for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
+ const char *tagName = get_camera_metadata_tag_name(candidateTag);
+
+ if (strcmp(nameTagName, tagName) == 0) {
+ ALOGV("%s: Found matched tag '%s' (%d)",
+ __FUNCTION__, tagName, candidateTag);
+ break;
+ }
+ }
+
+ if (candidateTag == tagEnd) {
+ return NAME_NOT_FOUND;
+ }
+ } else if (vTags != NULL) {
+ // Match vendor tags (typically com.*)
+ const String8 sectionName(section);
+ const String8 tagName(nameTagName);
+
+ status_t res = OK;
+ if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ *tag = candidateTag;
+ return OK;
+}
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
new file mode 100644
index 0000000..3a4bc9c
--- /dev/null
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "CamComm1.0-CamModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Trace.h>
+
+#include "CameraModule.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+void CameraModule::deriveCameraCharacteristicsKeys(
+ uint32_t deviceVersion, CameraMetadata &chars) {
+ ATRACE_CALL();
+
+ Vector<int32_t> derivedCharKeys;
+ Vector<int32_t> derivedRequestKeys;
+ Vector<int32_t> derivedResultKeys;
+ // Keys added in HAL3.3
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
+ Vector<uint8_t> controlModes;
+ uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
+ data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
+ controlModes.push(ANDROID_CONTROL_MODE_AUTO);
+ camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
+ controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+ }
+
+ // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+ bool isManualAeSupported = false;
+ bool isManualAfSupported = false;
+ bool isManualAwbSupported = false;
+ entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+ isManualAeSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+ isManualAfSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+ isManualAwbSupported = true;
+ break;
+ }
+ }
+ }
+ if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+ controlModes.push(ANDROID_CONTROL_MODE_OFF);
+ }
+
+ chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
+
+ entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map
+ bool lensShadingModeSupported = false;
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.i32[i] == ANDROID_SHADING_MODE) {
+ lensShadingModeSupported = true;
+ break;
+ }
+ }
+ }
+ Vector<uint8_t> lscModes;
+ Vector<uint8_t> lscMapModes;
+ lscModes.push(ANDROID_SHADING_MODE_FAST);
+ lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY);
+ lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
+ if (lensShadingModeSupported) {
+ lscModes.push(ANDROID_SHADING_MODE_OFF);
+ lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON);
+ }
+ chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
+ chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
+
+ derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
+
+ // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
+ // adds batch size to this array.
+ entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+ if (entry.count > 0) {
+ Vector<int32_t> highSpeedConfig;
+ for (size_t i = 0; i < entry.count; i += 4) {
+ highSpeedConfig.add(entry.data.i32[i]); // width
+ highSpeedConfig.add(entry.data.i32[i + 1]); // height
+ highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
+ highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
+ highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
+ }
+ chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
+ highSpeedConfig);
+ }
+ }
+
+ // Keys added in HAL3.4
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+ // Check if HAL supports RAW_OPAQUE output
+ camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ bool supportRawOpaque = false;
+ bool supportAnyRaw = false;
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ Vector<int32_t> rawOpaqueSizes;
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ supportRawOpaque = true;
+ rawOpaqueSizes.push(width);
+ rawOpaqueSizes.push(height);
+ // 2 bytes per pixel. This rough estimation is only used when
+ // HAL does not fill in the opaque raw size
+ rawOpaqueSizes.push(width * height *2);
+ }
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ (format == HAL_PIXEL_FORMAT_RAW16 ||
+ format == HAL_PIXEL_FORMAT_RAW10 ||
+ format == HAL_PIXEL_FORMAT_RAW12 ||
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+ supportAnyRaw = true;
+ }
+ }
+
+ if (supportRawOpaque) {
+ entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ if (entry.count == 0) {
+ // Fill in estimated value if HAL does not list it
+ chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+ derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ }
+ }
+
+ // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+ if (supportAnyRaw) {
+ int32_t defaultRange[2] = {100, 100};
+ entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ if (entry.count == 0) {
+ // Fill in default value (100, 100)
+ chars.update(
+ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+ defaultRange, 2);
+ derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ // Actual request/results will be derived by camera device.
+ derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+ derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+ }
+ }
+ }
+
+ // Always add a default for the pre-correction active array if the vendor chooses to omit this
+ camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ if (entry.count == 0) {
+ Vector<int32_t> preCorrectionArray;
+ entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ preCorrectionArray.appendArray(entry.data.i32, entry.count);
+ chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+ derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ }
+
+ // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+ // This has to be done at this end of this function.
+ if (derivedCharKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
+ }
+ if (derivedRequestKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
+ }
+ if (derivedResultKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
+ }
+ return;
+}
+
+void CameraModule::appendAvailableKeys(CameraMetadata &chars,
+ int32_t keyTag, const Vector<int32_t>& appendKeys) {
+ camera_metadata_entry entry = chars.find(keyTag);
+ Vector<int32_t> availableKeys;
+ availableKeys.setCapacity(entry.count + appendKeys.size());
+ for (size_t i = 0; i < entry.count; i++) {
+ availableKeys.push(entry.data.i32[i]);
+ }
+ for (size_t i = 0; i < appendKeys.size(); i++) {
+ availableKeys.push(appendKeys[i]);
+ }
+ chars.update(keyTag, availableKeys);
+}
+
+CameraModule::CameraModule(camera_module_t *module) {
+ if (module == NULL) {
+ ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
+ assert(0);
+ }
+ mModule = module;
+}
+
+CameraModule::~CameraModule()
+{
+ while (mCameraInfoMap.size() > 0) {
+ camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
+ if (cameraInfo.static_camera_characteristics != NULL) {
+ free_camera_metadata(
+ const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics));
+ }
+ mCameraInfoMap.removeItemsAt(0);
+ }
+}
+
+int CameraModule::init() {
+ ATRACE_CALL();
+ int res = OK;
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
+ mModule->init != NULL) {
+ ATRACE_BEGIN("camera_module->init");
+ res = mModule->init();
+ ATRACE_END();
+ }
+ mCameraInfoMap.setCapacity(getNumberOfCameras());
+ return res;
+}
+
+int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCameraInfoLock);
+ if (cameraId < 0) {
+ ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+ return -EINVAL;
+ }
+
+ // Only override static_camera_characteristics for API2 devices
+ int apiVersion = mModule->common.module_api_version;
+ if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+ int ret;
+ ATRACE_BEGIN("camera_module->get_camera_info");
+ ret = mModule->get_camera_info(cameraId, info);
+ // Fill in this so CameraService won't be confused by
+ // possibly 0 device_version
+ info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
+ ATRACE_END();
+ return ret;
+ }
+
+ ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ // Get camera info from raw module and cache it
+ camera_info rawInfo, cameraInfo;
+ ATRACE_BEGIN("camera_module->get_camera_info");
+ int ret = mModule->get_camera_info(cameraId, &rawInfo);
+ ATRACE_END();
+ if (ret != 0) {
+ return ret;
+ }
+ int deviceVersion = rawInfo.device_version;
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
+ // static_camera_characteristics is invalid
+ *info = rawInfo;
+ return ret;
+ }
+ CameraMetadata m;
+ m = rawInfo.static_camera_characteristics;
+ deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
+ cameraInfo = rawInfo;
+ cameraInfo.static_camera_characteristics = m.release();
+ index = mCameraInfoMap.add(cameraId, cameraInfo);
+ }
+
+ assert(index != NAME_NOT_FOUND);
+ // return the cached camera info
+ *info = mCameraInfoMap[index];
+ return OK;
+}
+
+int CameraModule::getDeviceVersion(int cameraId) {
+ ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ int deviceVersion;
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+ struct camera_info info;
+ getCameraInfo(cameraId, &info);
+ deviceVersion = info.device_version;
+ } else {
+ deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ index = mDeviceVersionMap.add(cameraId, deviceVersion);
+ }
+ assert(index != NAME_NOT_FOUND);
+ return mDeviceVersionMap[index];
+}
+
+int CameraModule::open(const char* id, struct hw_device_t** device) {
+ int res;
+ ATRACE_BEGIN("camera_module->open");
+ res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+ ATRACE_END();
+ return res;
+}
+
+bool CameraModule::isOpenLegacyDefined() const {
+ if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) {
+ return false;
+ }
+ return mModule->open_legacy != NULL;
+}
+
+int CameraModule::openLegacy(
+ const char* id, uint32_t halVersion, struct hw_device_t** device) {
+ int res;
+ ATRACE_BEGIN("camera_module->open_legacy");
+ res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+ ATRACE_END();
+ return res;
+}
+
+int CameraModule::getNumberOfCameras() {
+ int numCameras;
+ ATRACE_BEGIN("camera_module->get_number_of_cameras");
+ numCameras = mModule->get_number_of_cameras();
+ ATRACE_END();
+ return numCameras;
+}
+
+int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
+ int res = OK;
+ ATRACE_BEGIN("camera_module->set_callbacks");
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
+ res = mModule->set_callbacks(callbacks);
+ }
+ ATRACE_END();
+ return res;
+}
+
+bool CameraModule::isVendorTagDefined() const {
+ return mModule->get_vendor_tag_ops != NULL;
+}
+
+void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
+ if (mModule->get_vendor_tag_ops) {
+ ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
+ mModule->get_vendor_tag_ops(ops);
+ ATRACE_END();
+ }
+}
+
+bool CameraModule::isSetTorchModeSupported() const {
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+ if (mModule->set_torch_mode == NULL) {
+ ALOGE("%s: Module 2.4 device must support set torch API!",
+ __FUNCTION__);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+ int res = INVALID_OPERATION;
+ if (mModule->set_torch_mode != NULL) {
+ ATRACE_BEGIN("camera_module->set_torch_mode");
+ res = mModule->set_torch_mode(camera_id, enable);
+ ATRACE_END();
+ }
+ return res;
+}
+
+status_t CameraModule::filterOpenErrorCode(status_t err) {
+ switch(err) {
+ case NO_ERROR:
+ case -EBUSY:
+ case -EINVAL:
+ case -EUSERS:
+ return err;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
+
+uint16_t CameraModule::getModuleApiVersion() const {
+ return mModule->common.module_api_version;
+}
+
+const char* CameraModule::getModuleName() const {
+ return mModule->common.name;
+}
+
+uint16_t CameraModule::getHalApiVersion() const {
+ return mModule->common.hal_api_version;
+}
+
+const char* CameraModule::getModuleAuthor() const {
+ return mModule->common.author;
+}
+
+void* CameraModule::getDso() {
+ return mModule->common.dso;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
new file mode 100644
index 0000000..dee2973
--- /dev/null
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "HandleImporter"
+#include <utils/Log.h>
+#include "HandleImporter.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+HandleImporter HandleImporter::sHandleImporter;
+
+HandleImporter& HandleImporter::getInstance() {
+ sHandleImporter.initialize();
+ return sHandleImporter;
+}
+
+bool HandleImporter::initialize() {
+ // allow only one client
+ if (mInitialized) {
+ return false;
+ }
+
+ if (!openGralloc()) {
+ return false;
+ }
+
+ mInitialized = true;
+ return true;
+}
+
+void HandleImporter::cleanup() {
+ if (!mInitialized) {
+ return;
+ }
+
+ closeGralloc();
+ mInitialized = false;
+}
+
+// In IComposer, any buffer_handle_t is owned by the caller and we need to
+// make a clone for hwcomposer2. We also need to translate empty handle
+// to nullptr. This function does that, in-place.
+bool HandleImporter::importBuffer(buffer_handle_t& handle) {
+ if (!handle->numFds && !handle->numInts) {
+ handle = nullptr;
+ return true;
+ }
+
+ buffer_handle_t clone = cloneBuffer(handle);
+ if (!clone) {
+ return false;
+ }
+
+ handle = clone;
+ return true;
+}
+
+void HandleImporter::freeBuffer(buffer_handle_t handle) {
+ if (!handle) {
+ return;
+ }
+
+ releaseBuffer(handle);
+}
+
+bool HandleImporter::importFence(const native_handle_t* handle, int& fd) {
+ if (handle == nullptr || handle->numFds == 0) {
+ fd = -1;
+ } else if (handle->numFds == 1) {
+ fd = dup(handle->data[0]);
+ if (fd < 0) {
+ ALOGE("failed to dup fence fd %d", handle->data[0]);
+ return false;
+ }
+ } else {
+ ALOGE("invalid fence handle with %d file descriptors",
+ handle->numFds);
+ return false;
+ }
+
+ return true;
+}
+
+void HandleImporter::closeFence(int fd) {
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
+bool HandleImporter::openGralloc() {
+ const hw_module_t* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return false;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major > 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return false;
+ }
+
+ if (major == 1) {
+ err = gralloc1_open(module, &mDevice);
+ if (err) {
+ ALOGE("failed to open gralloc1 device");
+ return false;
+ }
+
+ mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN));
+ mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE));
+ if (!mRetain || !mRelease) {
+ ALOGE("invalid gralloc1 device");
+ gralloc1_close(mDevice);
+ return false;
+ }
+ } else {
+ mModule = reinterpret_cast<const gralloc_module_t*>(module);
+ }
+
+ return true;
+}
+
+void HandleImporter::closeGralloc() {
+ if (mDevice) {
+ gralloc1_close(mDevice);
+ }
+}
+
+buffer_handle_t HandleImporter::cloneBuffer(buffer_handle_t handle) {
+ native_handle_t* clone = native_handle_clone(handle);
+ if (!clone) {
+ ALOGE("failed to clone buffer %p", handle);
+ return nullptr;
+ }
+
+ bool err;
+ if (mDevice) {
+ err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE);
+ } else {
+ err = (mModule->registerBuffer(mModule, clone) != 0);
+ }
+
+ if (err) {
+ ALOGE("failed to retain/register buffer %p", clone);
+ native_handle_close(clone);
+ native_handle_delete(clone);
+ return nullptr;
+ }
+
+ return clone;
+}
+
+void HandleImporter::releaseBuffer(buffer_handle_t handle) {
+ if (mDevice) {
+ mRelease(mDevice, handle);
+ } else {
+ mModule->unregisterBuffer(mModule, handle);
+ }
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..db884a8
--- /dev/null
+++ b/camera/common/1.0/default/VendorTagDescriptor.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "CamComm1.0-VTDesc"
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "VendorTagDescriptor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+VendorTagDescriptor::~VendorTagDescriptor() {
+ size_t len = mReverseMapping.size();
+ for (size_t i = 0; i < len; ++i) {
+ delete mReverseMapping[i];
+ }
+}
+
+VendorTagDescriptor::VendorTagDescriptor() :
+ mTagCount(0),
+ mVendorOps() {
+}
+
+VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
+ copyFrom(src);
+}
+
+VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) {
+ copyFrom(rhs);
+ return *this;
+}
+
+void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) {
+ if (this == &src) return;
+
+ size_t len = mReverseMapping.size();
+ for (size_t i = 0; i < len; ++i) {
+ delete mReverseMapping[i];
+ }
+ mReverseMapping.clear();
+
+ len = src.mReverseMapping.size();
+ // Have to copy KeyedVectors inside mReverseMapping
+ for (size_t i = 0; i < len; ++i) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ *nameMapper = *(src.mReverseMapping.valueAt(i));
+ mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper);
+ }
+ // Everything else is simple
+ mTagToNameMap = src.mTagToNameMap;
+ mTagToSectionMap = src.mTagToSectionMap;
+ mTagToTypeMap = src.mTagToTypeMap;
+ mSections = src.mSections;
+ mTagCount = src.mTagCount;
+ mVendorOps = src.mVendorOps;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+ size_t size = mTagToNameMap.size();
+ if (size == 0) {
+ return VENDOR_TAG_COUNT_ERR;
+ }
+ return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+ size_t size = mTagToNameMap.size();
+ for (size_t i = 0; i < size; ++i) {
+ tagArray[i] = mTagToNameMap.keyAt(i);
+ }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+ ssize_t index = mTagToSectionMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_SECTION_NAME_ERR;
+ }
+ return mSections[mTagToSectionMap.valueAt(index)].string();
+}
+
+ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
+ return mTagToSectionMap.valueFor(tag);
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+ ssize_t index = mTagToNameMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_TAG_NAME_ERR;
+ }
+ return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+ ssize_t index = mTagToNameMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_TAG_TYPE_ERR;
+ }
+ return mTagToTypeMap.valueFor(tag);
+}
+
+const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
+ return &mSections;
+}
+
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
+ ssize_t index = mReverseMapping.indexOfKey(section);
+ if (index < 0) {
+ ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+ return BAD_VALUE;
+ }
+
+ ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
+ if (nameIndex < 0) {
+ ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+ return BAD_VALUE;
+ }
+
+ if (tag != NULL) {
+ *tag = mReverseMapping[index]->valueAt(nameIndex);
+ }
+ return OK;
+}
+
+void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
+
+ size_t size = mTagToNameMap.size();
+ if (size == 0) {
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+ indentation, "");
+ return;
+ }
+
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+ indentation, "", size);
+ for (size_t i = 0; i < size; ++i) {
+ uint32_t tag = mTagToNameMap.keyAt(i);
+
+ if (verbosity < 1) {
+ dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+ continue;
+ }
+ String8 name = mTagToNameMap.valueAt(i);
+ uint32_t sectionId = mTagToSectionMap.valueFor(tag);
+ String8 sectionName = mSections[sectionId];
+ int type = mTagToTypeMap.valueFor(tag);
+ const char* typeName = (type >= 0 && type < NUM_TYPES) ?
+ camera_metadata_type_names[type] : "UNKNOWN";
+ dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+ "", tag, name.string(), type, typeName, sectionName.string());
+ }
+
+}
+
+} // namespace params
+} // namespace camera2
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+} /* extern "C" */
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor) {
+ if (vOps == NULL) {
+ ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ int tagCount = vOps->get_tag_count(vOps);
+ if (tagCount < 0 || tagCount > INT32_MAX) {
+ ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+ return BAD_VALUE;
+ }
+
+ Vector<uint32_t> tagArray;
+ LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+ vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+
+ sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+ desc->mTagCount = tagCount;
+
+ SortedVector<String8> sections;
+ KeyedVector<uint32_t, String8> tagToSectionMap;
+
+ for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+ uint32_t tag = tagArray[i];
+ if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+ ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ const char *tagName = vOps->get_tag_name(vOps, tag);
+ if (tagName == NULL) {
+ ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ desc->mTagToNameMap.add(tag, String8(tagName));
+ const char *sectionName = vOps->get_section_name(vOps, tag);
+ if (sectionName == NULL) {
+ ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+
+ String8 sectionString(sectionName);
+
+ sections.add(sectionString);
+ tagToSectionMap.add(tag, sectionString);
+
+ int tagType = vOps->get_tag_type(vOps, tag);
+ if (tagType < 0 || tagType >= NUM_TYPES) {
+ ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+ return BAD_VALUE;
+ }
+ desc->mTagToTypeMap.add(tag, tagType);
+ }
+
+ desc->mSections = sections;
+
+ for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+ uint32_t tag = tagArray[i];
+ String8 sectionString = tagToSectionMap.valueFor(tag);
+
+ // Set up tag to section index map
+ ssize_t index = sections.indexOf(sectionString);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+ desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+ // Set up reverse mapping
+ ssize_t reverseIndex = -1;
+ if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+ }
+ desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+ }
+
+ descriptor = desc;
+ return OK;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+ status_t res = OK;
+ Mutex::Autolock al(sLock);
+ sGlobalVendorTagDescriptor = desc;
+
+ vendor_tag_ops_t* opsPtr = NULL;
+ if (desc != NULL) {
+ opsPtr = &(desc->mVendorOps);
+ opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+ opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+ opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+ opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+ opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+ }
+ if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+ ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
+ , __FUNCTION__, strerror(-res), res);
+ }
+ return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+ Mutex::Autolock al(sLock);
+ set_camera_metadata_vendor_ops(NULL);
+ sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+ Mutex::Autolock al(sLock);
+ return sGlobalVendorTagDescriptor;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_COUNT_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return;
+ }
+ sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_SECTION_NAME_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_NAME_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_TYPE_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+} /* extern "C" */
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/1.0/default/include/CameraMetadata.h
new file mode 100644
index 0000000..d5e4d56
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraMetadata.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMETADATA_H
+#define CAMERA_COMMON_1_0_CAMERAMETADATA_H
+
+#include "system/camera_metadata.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+class VendorTagDescriptor;
+
+/**
+ * A convenience wrapper around the C-based camera_metadata_t library.
+ */
+class CameraMetadata {
+ public:
+ /** Creates an empty object; best used when expecting to acquire contents
+ * from elsewhere */
+ CameraMetadata();
+ /** Creates an object with space for entryCapacity entries, with
+ * dataCapacity extra storage */
+ CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+
+ ~CameraMetadata();
+
+ /** Takes ownership of passed-in buffer */
+ CameraMetadata(camera_metadata_t *buffer);
+ /** Clones the metadata */
+ CameraMetadata(const CameraMetadata &other);
+
+ /**
+ * Assignment clones metadata buffer.
+ */
+ CameraMetadata &operator=(const CameraMetadata &other);
+ CameraMetadata &operator=(const camera_metadata_t *buffer);
+
+ /**
+ * Get reference to the underlying metadata buffer. Ownership remains with
+ * the CameraMetadata object, but non-const CameraMetadata methods will not
+ * work until unlock() is called. Note that the lock has nothing to do with
+ * thread-safety, it simply prevents the camera_metadata_t pointer returned
+ * here from being accidentally invalidated by CameraMetadata operations.
+ */
+ const camera_metadata_t* getAndLock() const;
+
+ /**
+ * Unlock the CameraMetadata for use again. After this unlock, the pointer
+ * given from getAndLock() may no longer be used. The pointer passed out
+ * from getAndLock must be provided to guarantee that the right object is
+ * being unlocked.
+ */
+ status_t unlock(const camera_metadata_t *buffer) const;
+
+ /**
+ * Release a raw metadata buffer to the caller. After this call,
+ * CameraMetadata no longer references the buffer, and the caller takes
+ * responsibility for freeing the raw metadata buffer (using
+ * free_camera_metadata()), or for handing it to another CameraMetadata
+ * instance.
+ */
+ camera_metadata_t* release();
+
+ /**
+ * Clear the metadata buffer and free all storage used by it
+ */
+ void clear();
+
+ /**
+ * Acquire a raw metadata buffer from the caller. After this call,
+ * the caller no longer owns the raw buffer, and must not free or manipulate it.
+ * If CameraMetadata already contains metadata, it is freed.
+ */
+ void acquire(camera_metadata_t* buffer);
+
+ /**
+ * Acquires raw buffer from other CameraMetadata object. After the call, the argument
+ * object no longer has any metadata.
+ */
+ void acquire(CameraMetadata &other);
+
+ /**
+ * Append metadata from another CameraMetadata object.
+ */
+ status_t append(const CameraMetadata &other);
+
+ /**
+ * Append metadata from a raw camera_metadata buffer
+ */
+ status_t append(const camera_metadata* other);
+
+ /**
+ * Number of metadata entries.
+ */
+ size_t entryCount() const;
+
+ /**
+ * Is the buffer empty (no entires)
+ */
+ bool isEmpty() const;
+
+ /**
+ * Sort metadata buffer for faster find
+ */
+ status_t sort();
+
+ /**
+ * Update metadata entry. Will create entry if it doesn't exist already, and
+ * will reallocate the buffer if insufficient space exists. Overloaded for
+ * the various types of valid data.
+ */
+ status_t update(uint32_t tag,
+ const uint8_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const int32_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const float *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const int64_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const double *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const camera_metadata_rational_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const String8 &string);
+ status_t update(const camera_metadata_ro_entry &entry);
+
+
+ template<typename T>
+ status_t update(uint32_t tag, Vector<T> data) {
+ return update(tag, data.array(), data.size());
+ }
+
+ /**
+ * Check if a metadata entry exists for a given tag id
+ *
+ */
+ bool exists(uint32_t tag) const;
+
+ /**
+ * Get metadata entry by tag id
+ */
+ camera_metadata_entry find(uint32_t tag);
+
+ /**
+ * Get metadata entry by tag id, with no editing
+ */
+ camera_metadata_ro_entry find(uint32_t tag) const;
+
+ /**
+ * Delete metadata entry by tag
+ */
+ status_t erase(uint32_t tag);
+
+ /**
+ * Swap the underlying camera metadata between this and the other
+ * metadata object.
+ */
+ void swap(CameraMetadata &other);
+
+ /**
+ * Dump contents into FD for debugging. The verbosity levels are
+ * 0: Tag entry information only, no data values
+ * 1: Level 0 plus at most 16 data values per entry
+ * 2: All information
+ *
+ * The indentation parameter sets the number of spaces to add to the start
+ * each line of output.
+ */
+ void dump(int fd, int verbosity = 1, int indentation = 0) const;
+
+ /**
+ * Find tag id for a given tag name, also checking vendor tags if available.
+ * On success, returns OK and writes the tag id into tag.
+ *
+ * This is a slow method.
+ */
+ static status_t getTagFromName(const char *name,
+ const VendorTagDescriptor* vTags, uint32_t *tag);
+
+ private:
+ camera_metadata_t *mBuffer;
+ mutable bool mLocked;
+
+ /**
+ * Check if tag has a given type
+ */
+ status_t checkType(uint32_t tag, uint8_t expectedType);
+
+ /**
+ * Base update entry method
+ */
+ status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
+
+ /**
+ * Resize metadata buffer if needed by reallocating it and copying it over.
+ */
+ status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
new file mode 100644
index 0000000..9fbfbd5
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H
+#define CAMERA_COMMON_1_0_CAMERAMODULE_H
+
+#include <hardware/camera.h>
+#include <utils/Mutex.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+/**
+ * A wrapper class for HAL camera module.
+ *
+ * This class wraps camera_module_t returned from HAL to provide a wrapped
+ * get_camera_info implementation which CameraService generates some
+ * camera characteristics keys defined in newer HAL version on an older HAL.
+ */
+class CameraModule : public RefBase {
+public:
+ explicit CameraModule(camera_module_t *module);
+ virtual ~CameraModule();
+
+ // Must be called after construction
+ // Returns OK on success, NO_INIT on failure
+ int init();
+
+ int getCameraInfo(int cameraId, struct camera_info *info);
+ int getDeviceVersion(int cameraId);
+ int getNumberOfCameras(void);
+ int open(const char* id, struct hw_device_t** device);
+ bool isOpenLegacyDefined() const;
+ int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+ int setCallbacks(const camera_module_callbacks_t *callbacks);
+ bool isVendorTagDefined() const;
+ void getVendorTagOps(vendor_tag_ops_t* ops);
+ bool isSetTorchModeSupported() const;
+ int setTorchMode(const char* camera_id, bool enable);
+ uint16_t getModuleApiVersion() const;
+ const char* getModuleName() const;
+ uint16_t getHalApiVersion() const;
+ const char* getModuleAuthor() const;
+ // Only used by CameraModuleFixture native test. Do NOT use elsewhere.
+ void *getDso();
+
+private:
+ // Derive camera characteristics keys defined after HAL device version
+ static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
+ // Helper function to append available[request|result|chars]Keys
+ static void appendAvailableKeys(CameraMetadata &chars,
+ int32_t keyTag, const Vector<int32_t>& appendKeys);
+ status_t filterOpenErrorCode(status_t err);
+ camera_module_t *mModule;
+ KeyedVector<int, camera_info> mCameraInfoMap;
+ KeyedVector<int, int> mDeviceVersionMap;
+ Mutex mCameraInfoLock;
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
new file mode 100644
index 0000000..def8982
--- /dev/null
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
+#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
+
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <system/window.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+// Borrowed from graphics HAL. Use this until gralloc mapper HAL is working
+class HandleImporter {
+public:
+ static HandleImporter& getInstance();
+
+ // In IComposer, any buffer_handle_t is owned by the caller and we need to
+ // make a clone for hwcomposer2. We also need to translate empty handle
+ // to nullptr. This function does that, in-place.
+ bool importBuffer(buffer_handle_t& handle);
+ void freeBuffer(buffer_handle_t handle);
+ bool importFence(const native_handle_t* handle, int& fd);
+ void closeFence(int fd);
+
+private:
+
+ HandleImporter() : mInitialized(false) {}
+ bool initialize();
+ void cleanup();
+ bool openGralloc();
+ void closeGralloc();
+ buffer_handle_t cloneBuffer(buffer_handle_t handle);
+ void releaseBuffer(buffer_handle_t handle);
+
+ static HandleImporter sHandleImporter;
+ bool mInitialized;
+
+ // gralloc1
+ gralloc1_device_t* mDevice;
+ GRALLOC1_PFN_RETAIN mRetain;
+ GRALLOC1_PFN_RELEASE mRelease;
+
+ // gralloc0
+ const gralloc_module_t* mModule;
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
\ No newline at end of file
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h
new file mode 100644
index 0000000..8d8ded9
--- /dev/null
+++ b/camera/common/1.0/default/include/VendorTagDescriptor.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+#include <system/camera_vendor_tags.h>
+
+#include <stdint.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+/**
+ * VendorTagDescriptor objects are containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor {
+ public:
+ virtual ~VendorTagDescriptor();
+
+ VendorTagDescriptor();
+ VendorTagDescriptor(const VendorTagDescriptor& src);
+ VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
+
+ void copyFrom(const VendorTagDescriptor& src);
+
+ /**
+ * The following 'get*' methods implement the corresponding
+ * functions defined in
+ * system/media/camera/include/system/camera_vendor_tags.h
+ */
+
+ // Returns the number of vendor tags defined.
+ int getTagCount() const;
+
+ // Returns an array containing the id's of vendor tags defined.
+ void getTagArray(uint32_t* tagArray) const;
+
+ // Returns the section name string for a given vendor tag id.
+ const char* getSectionName(uint32_t tag) const;
+
+ // Returns the index in section vectors returned in getAllSectionNames()
+ // for a given vendor tag id. -1 if input tag does not exist.
+ ssize_t getSectionIndex(uint32_t tag) const;
+
+ // Returns the tag name string for a given vendor tag id.
+ const char* getTagName(uint32_t tag) const;
+
+ // Returns the tag type for a given vendor tag id.
+ int getTagType(uint32_t tag) const;
+
+ /**
+ * Convenience method to get a vector containing all vendor tag
+ * sections, or an empty vector if none are defined.
+ * The pointer is valid for the lifetime of the VendorTagDescriptor,
+ * or until copyFrom is invoked.
+ */
+ const SortedVector<String8>* getAllSectionNames() const;
+
+ /**
+ * Lookup the tag id for a given tag name and section.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
+
+ /**
+ * Dump the currently configured vendor tags to a file descriptor.
+ */
+ void dump(int fd, int verbosity, int indentation) const;
+
+ protected:
+ KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+ KeyedVector<uint32_t, String8> mTagToNameMap;
+ KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
+ KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+ SortedVector<String8> mSections;
+ // must be int32_t to be compatible with Parcel::writeInt32
+ int32_t mTagCount;
+
+ vendor_tag_ops mVendorOps;
+};
+} /* namespace params */
+} /* namespace camera2 */
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+/**
+ * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it
+ * as a global tag descriptor.
+ *
+ * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic
+ * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
+ * interface implementations.
+ */
+class VendorTagDescriptor :
+ public ::android::hardware::camera2::params::VendorTagDescriptor,
+ public LightRefBase<VendorTagDescriptor> {
+
+ public:
+
+ /**
+ * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+ * struct.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor);
+
+ /**
+ * Sets the global vendor tag descriptor to use for this process.
+ * Camera metadata operations that access vendor tags will use the
+ * vendor tag definitions set this way.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+ /**
+ * Returns the global vendor tag descriptor used by this process.
+ * This will contain NULL if no vendor tags are defined.
+ */
+ static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+
+ /**
+ * Clears the global vendor tag descriptor used by this process.
+ */
+ static void clearGlobalVendorTagDescriptor();
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/common/1.0/types.hal b/camera/common/1.0/types.hal
new file mode 100644
index 0000000..0393107
--- /dev/null
+++ b/camera/common/1.0/types.hal
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2016 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.camera.common@1.0;
+
+/**
+ * Common enumeration and structure definitions for all HALs under
+ * android.hardware.camera
+ */
+
+/**
+ * Status codes for camera HAL method calls.
+ *
+ */
+enum Status : uint32_t {
+ /**
+ * Method call succeeded
+ */
+ OK = 0,
+
+ /**
+ * One of the arguments to the method call is invalid. For example,
+ * the camera ID is unknown.
+ */
+ ILLEGAL_ARGUMENT = 1,
+
+ /**
+ * The specified camera device is already in use
+ */
+ CAMERA_IN_USE = 2,
+
+ /**
+ * The HAL cannot support more simultaneous cameras in use.
+ */
+ MAX_CAMERAS_IN_USE = 3,
+
+ /**
+ * This HAL does not support this method.
+ */
+ METHOD_NOT_SUPPORTED = 4,
+
+ /**
+ * The specified camera device does not support this operation.
+ */
+ OPERATION_NOT_SUPPORTED = 5,
+
+ /**
+ * This camera device is no longer connected or otherwise available for use
+ */
+ CAMERA_DISCONNECTED = 6,
+
+ /**
+ * The HAL has encountered an internal error and cannot complete the
+ * request.
+ */
+ INTERNAL_ERROR = 7
+};
+
+/**
+ * Possible states that the flash unit on a closed camera device can be set to
+ * via the ICameraProvider::setTorchMode() method.
+ */
+enum TorchMode : uint32_t {
+ OFF = 0, // Turn off the flash
+ ON = 1 // Turn on the flash to torch mode
+};
+
+/**
+ * Camera metadata type - duplicated from VNDK libcamera_metadata for vendor tag
+ * definitions.
+ */
+enum CameraMetadataType : uint32_t {
+ // Unsigned 8-bit integer (uint8_t)
+ BYTE = 0,
+ // Signed 32-bit integer (int32_t)
+ INT32 = 1,
+ // 32-bit float (float)
+ FLOAT = 2,
+ // Signed 64-bit integer (int64_t)
+ INT64 = 3,
+ // 64-bit float (double)
+ DOUBLE = 4,
+ // A 64-bit fraction (camera_metadata_rational_t)
+ RATIONAL = 5
+};
+
+/**
+ * A single vendor-unique metadata tag.
+ * The full name of the tag is <sectionName>.<tagName>
+ */
+struct VendorTag {
+ uint32_t tagId; // Tag identifier, must be >= TagBoundaryId::VENDOR
+ string tagName; // Name of tag, not including section name
+ CameraMetadataType tagType;
+};
+
+/**
+ * A set of related vendor tags.
+ */
+struct VendorTagSection {
+ string sectionName; // Section name; must be namespaced within vendor's name
+ vec<VendorTag> tags; // List of tags in this section
+};
+
+enum TagBoundaryId : uint32_t {
+ AOSP = 0x0, // First valid tag id for android-defined tags
+ VENDOR = 0x80000000u // First valid tag id for vendor extension tags
+};
+
+/**
+ * CameraDeviceStatus
+ *
+ * The current status of a camera device, as sent by a camera provider HAL
+ * through the ICameraProviderCallback::cameraDeviceStatusChange() call.
+ *
+ * At startup, the camera service must assume all internal camera devices listed
+ * by ICameraProvider::getCameraIdList() are in the PRESENT state. The provider
+ * must invoke ICameraProviderCallback::cameraDeviceStatusChange to inform the
+ * service of any initially NOT_PRESENT internal devices, and of any PRESENT
+ * external camera devices, as soon as the camera service has called
+ * ICameraProvider::setCallback().
+ *
+ * Allowed state transitions:
+ * PRESENT -> NOT_PRESENT
+ * NOT_PRESENT -> ENUMERATING
+ * NOT_PRESENT -> PRESENT
+ * ENUMERATING -> PRESENT
+ * ENUMERATING -> NOT_PRESENT
+ */
+enum CameraDeviceStatus : uint32_t {
+ /**
+ * The camera device is not currently connected, and trying to reference it
+ * in provider method calls must return status code ILLEGAL_ARGUMENT.
+ *
+ */
+ NOT_PRESENT = 0,
+
+ /**
+ * The camera device is connected, and opening it is possible, as long as
+ * sufficient resources are available.
+ *
+ * By default, the framework must assume all devices returned by
+ * ICameraProvider::getCameraIdList() are in this state.
+ */
+ PRESENT = 1,
+
+ /**
+ * The camera device is connected, but it is undergoing enumeration and
+ * startup, and so opening the device must return CAMERA_IN_USE.
+ *
+ * Attempting to call ICameraProvider::getCameraCharacteristics() must
+ * succeed, however.
+ */
+ ENUMERATING = 2,
+
+};
+
+/**
+ * TorchModeStatus:
+ *
+ * The current status of the torch mode on a given camera device, sent by a
+ * camera provider HAL via the ICameraProviderCallback::TorchModeStatusChange()
+ * call.
+ *
+ * The torch mode status of a camera device is applicable only when the camera
+ * device is present. The camera service must not call
+ * ICameraProvider::setTorchMode() to turn on torch mode of a camera device if
+ * the camera device is not present. At camera service startup time, the
+ * framework must assume torch modes are in the AVAILABLE_OFF state if the
+ * camera device is present and the camera characteristics entry
+ * android.flash.info.available is reported as true via
+ * ICameraProvider::getCameraCharacteristics() call. The same is assumed for
+ * external camera devices when they are initially connected.
+ *
+ * The camera service requires the following behaviors from the camera provider
+ * HAL when a camera device's status changes:
+ *
+ * 1. A previously-disconnected camera device becomes connected. After
+ * ICameraProviderCallback::CameraDeviceStatusChange() is invoked to inform
+ * the camera service that the camera device is present, the framework must
+ * assume the camera device's torch mode is in AVAILABLE_OFF state if it
+ * has a flash unit. The camera provider HAL does not need to invoke
+ * ICameraProviderCallback::TorchModeStatusChange() unless the flash unit
+ * is unavailable to use by ICameraProvider::setTorchMode().
+ *
+ * 2. A previously-connected camera becomes disconnected. After
+ * ICameraProviderCallback::CameraDeviceStatusChange() is invoked to inform
+ * the camera service that the camera device is not present, the framework
+ * must not call ICameraProvider::setTorchMode() for the disconnected camera
+ * device until it is connected again. The camera provider HAL does not
+ * need to invoke ICameraProviderCallback::TorchModeStatusChange()
+ * separately to inform that the flash unit has become NOT_AVAILABLE.
+ *
+ * 3. openCameraDevice() or openCameraDeviceVersion() is called to open a
+ * camera device. The camera provider HAL must invoke
+ * ICameraProviderCallback::TorchModeStatusChange() for all flash units
+ * that have entered NOT_AVAILABLE state and can not be turned on by
+ * calling ICameraProvider::setTorchMode() due to this open() call.
+ * openCameraDevice() must not trigger AVAILABLE_OFF before NOT_AVAILABLE
+ * for all flash units that have become unavailable.
+ *
+ * 4. ICameraDevice.close() is called to close a camera device. The camera
+ * provider HAL must call ICameraProviderCallback::torchModeStatusChange()
+ * for all flash units that have now entered the AVAILABLE_OFF state and
+ * can be turned on by calling ICameraProvider::setTorchMode() again because
+ * of sufficient new camera resources being freed up by this close() call.
+ *
+ * Note that the camera service calling ICameraProvider::setTorchMode()
+ * successfully must trigger AVAILABLE_OFF or AVAILABLE_ON callback for the
+ * given camera device. Additionally it must trigger AVAILABLE_OFF callbacks
+ * for other previously-on torch modes if HAL cannot keep multiple devices'
+ * flashlights on simultaneously.
+ */
+enum TorchModeStatus : uint32_t {
+ /**
+ * The flash unit is no longer available and the torch mode can not be
+ * turned on by calling setTorchMode(). If the torch mode was AVAILABLE_ON,
+ * the flashlight must be turned off by the provider HAL before the provider
+ * HAL calls torchModeStatusChange().
+ */
+ NOT_AVAILABLE = 0,
+
+ /**
+ * A torch mode has become off and is available to be turned on via
+ * ICameraProvider::setTorchMode(). This may happen in the following
+ * cases:
+ * 1. After the resources to turn on the torch mode have become available.
+ * 2. After ICameraProvider::setTorchMode() is called to turn off the torch
+ * mode.
+ * 3. After the camera service turned on the torch mode for some other
+ * camera device and the provider HAL had to turn off the torch modes
+ * of other camera device(s) that were previously on, due to lack of
+ * resources to keep them all on.
+ */
+ AVAILABLE_OFF = 1,
+
+ /**
+ * A torch mode has become on and is available to be turned off via
+ * ICameraProvider::setTorchMode(). This can happen only after
+ * ICameraProvider::setTorchMode() has been called to turn on the torch mode.
+ */
+ AVAILABLE_ON = 2,
+
+};
+
+/**
+ * CameraResourceCost:
+ *
+ * Structure defining the abstract resource cost of opening a camera device,
+ * and any usage conflicts between multiple camera devices.
+ *
+ * Obtainable via ICameraDevice::getResourceCost()
+ */
+struct CameraResourceCost {
+ /**
+ * The total resource "cost" of using this camera, represented as an integer
+ * value in the range [0, 100] where 100 represents total usage of the
+ * shared resource that is the limiting bottleneck of the camera subsystem.
+ * This may be a very rough estimate, and is used as a hint to the camera
+ * service to determine when to disallow multiple applications from
+ * simultaneously opening different cameras advertised by the camera
+ * service.
+ *
+ * The camera service must be able to simultaneously open and use any
+ * combination of camera devices exposed by the HAL where the sum of
+ * the resource costs of these cameras is <= 100. For determining cost,
+ * each camera device must be assumed to be configured and operating at
+ * the maximally resource-consuming framerate and stream size settings
+ * available in the configuration settings exposed for that device through
+ * the camera metadata.
+ *
+ * The camera service may still attempt to simultaneously open combinations
+ * of camera devices with a total resource cost > 100. This may succeed or
+ * fail. If this succeeds, combinations of configurations that are not
+ * supported due to resource constraints from having multiple open devices
+ * must fail during the configure calls. If the total resource cost is <=
+ * 100, open and configure must never fail for any stream configuration
+ * settings or other device capabilities that would normally succeed for a
+ * device when it is the only open camera device.
+ *
+ * This field may be used to determine whether background applications are
+ * allowed to use this camera device while other applications are using
+ * other camera devices. Note: multiple applications must never be allowed
+ * by the camera service to simultaneously open the same camera device.
+ *
+ * Example use cases:
+ *
+ * Ex. 1: Camera Device 0 = Back Camera
+ * Camera Device 1 = Front Camera
+ * - Using both camera devices causes a large framerate slowdown due to
+ * limited ISP bandwidth.
+ *
+ * Configuration:
+ *
+ * Camera Device 0 - resourceCost = 51
+ * conflicting_devices = empty
+ * Camera Device 1 - resourceCost = 51
+ * conflicting_devices = empty
+ *
+ * Result:
+ *
+ * Since the sum of the resource costs is > 100, if a higher-priority
+ * application has either device open, no lower-priority applications must
+ * be allowed by the camera service to open either device. If a
+ * lower-priority application is using a device that a higher-priority
+ * subsequently attempts to open, the lower-priority application must be
+ * forced to disconnect the the device.
+ *
+ * If the highest-priority application chooses, it may still attempt to
+ * open both devices (since these devices are not listed as conflicting in
+ * the conflicting_devices fields), but usage of these devices may fail in
+ * the open or configure calls.
+ *
+ * Ex. 2: Camera Device 0 = Left Back Camera
+ * Camera Device 1 = Right Back Camera
+ * Camera Device 2 = Combined stereo camera using both right and left
+ * back camera sensors used by devices 0, and 1
+ * Camera Device 3 = Front Camera
+ * - Due to do hardware constraints, up to two cameras may be open at
+ * once. The combined stereo camera may never be used at the same time
+ * as either of the two back camera devices (device 0, 1), and typically
+ * requires too much bandwidth to use at the same time as the front
+ * camera (device 3).
+ *
+ * Configuration:
+ *
+ * Camera Device 0 - resourceCost = 50
+ * conflicting_devices = { 2 }
+ * Camera Device 1 - resourceCost = 50
+ * conflicting_devices = { 2 }
+ * Camera Device 2 - resourceCost = 100
+ * conflicting_devices = { 0, 1 }
+ * Camera Device 3 - resourceCost = 50
+ * conflicting_devices = empty
+ *
+ * Result:
+ *
+ * Based on the conflicting_devices fields, the camera service guarantees
+ * that the following sets of open devices must never be allowed: { 1, 2
+ * }, { 0, 2 }.
+ *
+ * Based on the resourceCost fields, if a high-priority foreground
+ * application is using camera device 0, a background application would be
+ * allowed to open camera device 1 or 3 (but would be forced to disconnect
+ * it again if the foreground application opened another device).
+ *
+ * The highest priority application may still attempt to simultaneously
+ * open devices 0, 2, and 3, but the HAL may fail in open or configure
+ * calls for this combination.
+ *
+ * Ex. 3: Camera Device 0 = Back Camera
+ * Camera Device 1 = Front Camera
+ * Camera Device 2 = Low-power Front Camera that uses the same sensor
+ * as device 1, but only exposes image stream
+ * resolutions that can be used in low-power mode
+ * - Using both front cameras (device 1, 2) at the same time is impossible
+ * due a shared physical sensor. Using the back and "high-power" front
+ * camera (device 1) may be impossible for some stream configurations due
+ * to hardware limitations, but the "low-power" front camera option may
+ * always be used as it has special dedicated hardware.
+ *
+ * Configuration:
+ *
+ * Camera Device 0 - resourceCost = 100
+ * conflicting_devices = empty
+ * Camera Device 1 - resourceCost = 100
+ * conflicting_devices = { 2 }
+ * Camera Device 2 - resourceCost = 0
+ * conflicting_devices = { 1 }
+ * Result:
+ *
+ * Based on the conflicting_devices fields, the camera service guarantees
+ * that the following sets of open devices must never be allowed:
+ * { 1, 2 }.
+ *
+ * Based on the resourceCost fields, only the highest priority application
+ * may attempt to open both device 0 and 1 at the same time. If a
+ * higher-priority application is not using device 1 or 2, a low-priority
+ * background application may open device 2 (but must be forced to
+ * disconnect it if a higher-priority application subsequently opens
+ * device 1 or 2).
+ */
+ uint32_t resourceCost;
+
+ /**
+ * An array of camera device IDs indicating other devices that cannot be
+ * simultaneously opened while this camera device is in use.
+ *
+ * This field is intended to be used to indicate that this camera device
+ * is a composite of several other camera devices, or otherwise has
+ * hardware dependencies that prohibit simultaneous usage. If there are no
+ * dependencies, an empty list may be returned to indicate this.
+ *
+ * The camera service must never simultaneously open any of the devices
+ * in this list while this camera device is open.
+ *
+ */
+ vec<string> conflictingDevices;
+
+};
diff --git a/camera/common/README.md b/camera/common/README.md
new file mode 100644
index 0000000..c177ad8
--- /dev/null
+++ b/camera/common/README.md
@@ -0,0 +1,21 @@
+## Camera common HAL definitions ##
+---
+
+## Overview: ##
+
+The camera.common namesapce is used by the Android camera HALs for common
+enumeration and structure definitions.
+
+This includes standard status codes returned by most camera HAL methods.
+
+More complete information about the Android camera HAL and subsystem can be found at
+[source.android.com](http://source.android.com/devices/camera/index.html).
+
+## Version history: ##
+
+## types.hal: ##
+
+### @1.0:
+
+Common enum and struct definitions for all camera HAL interfaces. Does not
+define any interfaces of its own.
diff --git a/camera/device/1.0/Android.bp b/camera/device/1.0/Android.bp
new file mode 100644
index 0000000..b8560c7
--- /dev/null
+++ b/camera/device/1.0/Android.bp
@@ -0,0 +1,82 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.camera.device@1.0_hal",
+ srcs: [
+ "types.hal",
+ "ICameraDevice.hal",
+ "ICameraDeviceCallback.hal",
+ "ICameraDevicePreviewCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.device@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@1.0",
+ srcs: [
+ ":android.hardware.camera.device@1.0_hal",
+ ],
+ out: [
+ "android/hardware/camera/device/1.0/types.cpp",
+ "android/hardware/camera/device/1.0/CameraDeviceAll.cpp",
+ "android/hardware/camera/device/1.0/CameraDeviceCallbackAll.cpp",
+ "android/hardware/camera/device/1.0/CameraDevicePreviewCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.device@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@1.0",
+ srcs: [
+ ":android.hardware.camera.device@1.0_hal",
+ ],
+ out: [
+ "android/hardware/camera/device/1.0/types.h",
+ "android/hardware/camera/device/1.0/ICameraDevice.h",
+ "android/hardware/camera/device/1.0/IHwCameraDevice.h",
+ "android/hardware/camera/device/1.0/BnHwCameraDevice.h",
+ "android/hardware/camera/device/1.0/BpHwCameraDevice.h",
+ "android/hardware/camera/device/1.0/BsCameraDevice.h",
+ "android/hardware/camera/device/1.0/ICameraDeviceCallback.h",
+ "android/hardware/camera/device/1.0/IHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/1.0/BnHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/1.0/BpHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/1.0/BsCameraDeviceCallback.h",
+ "android/hardware/camera/device/1.0/ICameraDevicePreviewCallback.h",
+ "android/hardware/camera/device/1.0/IHwCameraDevicePreviewCallback.h",
+ "android/hardware/camera/device/1.0/BnHwCameraDevicePreviewCallback.h",
+ "android/hardware/camera/device/1.0/BpHwCameraDevicePreviewCallback.h",
+ "android/hardware/camera/device/1.0/BsCameraDevicePreviewCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.device@1.0",
+ generated_sources: ["android.hardware.camera.device@1.0_genc++"],
+ generated_headers: ["android.hardware.camera.device@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.camera.device@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/camera/device/1.0/ICameraDevice.hal b/camera/device/1.0/ICameraDevice.hal
new file mode 100644
index 0000000..52d6cf0
--- /dev/null
+++ b/camera/device/1.0/ICameraDevice.hal
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2016 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.camera.device@1.0;
+
+import android.hardware.camera.common@1.0::types;
+import ICameraDeviceCallback;
+import ICameraDevicePreviewCallback;
+
+/**
+ * Camera device HAL, legacy version
+ *
+ * DEPRECATED. New devices are strongly recommended to use Camera HAL v3.2 or
+ * newer.
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API in LEGACY mode only.
+ *
+ * Will be removed in the Android P release.
+ */
+interface ICameraDevice {
+
+ /**
+ * Get camera device resource cost information.
+ *
+ * This method may be called at any time, including before open()
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On success.
+ * INTERNAL_ERROR:
+ * An unexpected internal camera HAL error occurred, and the
+ * resource cost is not available.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ * @return resourceCost
+ * The resources required to open this camera device, or unspecified
+ * values if status is not OK.
+ */
+ getResourceCost() generates (Status status, CameraResourceCost resourceCost);
+
+ /**
+ * Get basic camera information.
+ *
+ * This method may be called at any time, including before open()
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On success.
+ * INTERNAL_ERROR:
+ * An unexpected internal camera HAL error occurred, and the
+ * camera information is not available.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ * @return info Basic information about this camera device, or unspecified
+ * values if status is not OK.
+ */
+ getCameraInfo() generates (Status status, CameraInfo info);
+
+ /**
+ * setTorchMode:
+ *
+ * Turn on or off the torch mode of the flash unit associated with a given
+ * camera ID. If the operation is successful, HAL must notify the framework
+ * torch state by invoking
+ * ICameraProviderCallback::torchModeStatusChange() with the new state.
+ *
+ * The camera device has a higher priority accessing the flash unit. When
+ * there are any resource conflicts, such as when open() is called to fully
+ * activate a camera device, the provider must notify the framework through
+ * ICameraProviderCallback::torchModeStatusChange() that the torch mode has
+ * been turned off and the torch mode state has become
+ * TORCH_MODE_STATUS_NOT_AVAILABLE. When resources to turn on torch mode
+ * become available again, the provider must notify the framework through
+ * ICameraProviderCallback::torchModeStatusChange() that the torch mode
+ * state has become TORCH_MODE_STATUS_AVAILABLE_OFF for set_torch_mode() to
+ * be called.
+ *
+ * When the framework calls setTorchMode() to turn on the torch mode of a
+ * flash unit, if HAL cannot keep multiple torch modes on simultaneously,
+ * HAL must turn off the torch mode that was turned on by
+ * a previous setTorchMode() call and notify the framework that the torch
+ * mode state of that flash unit has become TORCH_MODE_STATUS_AVAILABLE_OFF.
+ *
+ * @param torchMode The new mode to set the device flash unit to.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful change to the torch state.
+ * INTERNAL_ERROR:
+ * The flash unit cannot be operated due to an unexpected internal
+ * error.
+ * ILLEGAL_ARGUMENT:
+ * The camera ID is unknown.
+ * CAMERA_IN_USE:
+ * This camera device has been opened, so the torch cannot be
+ * controlled until it is closed.
+ * MAX_CAMERAS_IN_USE:
+ * Due to other camera devices being open, or due to other
+ * resource constraints, the torch cannot be controlled currently.
+ * METHOD_NOT_SUPPORTED:
+ * This provider does not support direct operation of flashlight
+ * torch mode. The framework must open the camera device and turn
+ * the torch on through the device interface.
+ * OPERATION_NOT_SUPPORTED:
+ * This camera device does not have a flash unit. This must
+ * be returned if and only if parameter key flash-mode-values is not present.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ *
+ */
+ setTorchMode(TorchMode mode) generates (Status status);
+
+ /**
+ * Dump state of the camera hardware.
+ *
+ * This must be callable at any time, whether the device is open or not.
+ *
+ * @param fd A native handle with one valid file descriptor. The descriptor
+ * must be able to be used with dprintf() or equivalent to dump the
+ * state of this camera device into the camera service dumpsys output.
+ *
+ * @return status The status code for this operation.
+ */
+ dumpState(handle fd) generates (Status status);
+
+ /**
+ * Open the camera device for active use.
+ *
+ * All methods besides getResourceCost(), getCameraInfo(), setTorchMode(),
+ * and dump() must not be called unless open() has been called successfully,
+ * and close() has not yet been called.
+ *
+ * @param callback Interface to invoke by the HAL for device callbacks.
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful open of the camera device.
+ * INTERNAL_ERROR:
+ * The camera device cannot be opened due to an internal
+ * error.
+ * ILLEGAL_ARGUMENT:
+ * The callback handle is invalid (for example, it is null).
+ * CAMERA_IN_USE:
+ * This camera device is already open.
+ * MAX_CAMERAS_IN_USE:
+ * The maximal number of camera devices that can be
+ * opened concurrently were opened already.
+ * CAMERA_DISCONNECTED:
+ * This external camera device has been disconnected, and is no
+ * longer available. This interface is now stale, and a new instance
+ * must be acquired if the device is reconnected. All subsequent
+ * calls on this interface must return CAMERA_DISCONNECTED.
+ */
+ open(ICameraDeviceCallback callback) generates (Status status);
+
+
+ /*****
+ * All methods below this point must only be called between a successful
+ * open() call and a close() call.
+ */
+
+ /** Set the callback interface through which preview frames are sent */
+ setPreviewWindow(ICameraDevicePreviewCallback window)
+ generates (Status status);
+
+ /**
+ * Enable a message, or set of messages.
+ *
+ * @param msgType The bitfield of messages to enable.
+ */
+ enableMsgType(FrameCallbackFlags msgType);
+
+ /**
+ * Disable a message, or a set of messages.
+ *
+ * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera
+ * HAL must not rely on its client to call releaseRecordingFrame() to
+ * release video recording frames sent out by the cameral HAL before and
+ * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL
+ * clients must not modify/access any video recording frame after calling
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
+ *
+ * @param msgType The bitfield of messages to disable.
+ */
+ disableMsgType(FrameCallbackFlags msgType);
+
+ /**
+ * Query whether a message, or a set of messages, is enabled. Note that
+ * this is operates as an AND, if any of the messages queried are off, this
+ * must return false.
+ *
+ * @param msgType The bitfield of messages to query.
+ * @return enabled Whether all the specified flags are enabled.
+ */
+ msgTypeEnabled(FrameCallbackFlags msgType) generates (bool enabled);
+
+ /**
+ * Start preview mode.
+ *
+ * @return status The status code for this operation.
+ */
+ startPreview() generates (Status status);
+
+ /**
+ * Stop a previously started preview.
+ */
+ stopPreview();
+
+ /**
+ * Returns true if preview is enabled.
+ *
+ * @return enabled Whether preview is currently enabled.
+ */
+ previewEnabled() generates (bool enabled);
+
+ /**
+ * Request the camera HAL to store meta data or real YUV data in the video
+ * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If
+ * it is not called, the default camera HAL behavior is to store real YUV
+ * data in the video buffers.
+ *
+ * This method must be called before startRecording() in order to be
+ * effective.
+ *
+ * If meta data is stored in the video buffers, it is up to the receiver of
+ * the video buffers to interpret the contents and to find the actual frame
+ * data with the help of the meta data in the buffer. How this is done is
+ * outside of the scope of this method.
+ *
+ * Some camera HALs may not support storing meta data in the video buffers,
+ * but all camera HALs must support storing real YUV data in the video
+ * buffers. If the camera HAL does not support storing the meta data in the
+ * video buffers when it is requested to do do, INVALID_OPERATION must be
+ * returned. It is very useful for the camera HAL to pass meta data rather
+ * than the actual frame data directly to the video encoder, since the
+ * amount of the uncompressed frame data can be very large if video size is
+ * large.
+ *
+ * @param enable Set to true to instruct the camera HAL to store meta data
+ * in the video buffers; false to instruct the camera HAL to store real
+ * YUV data in the video buffers.
+ *
+ * @return status OK on success.
+ */
+ storeMetaDataInBuffers(bool enable) generates (Status status);
+
+ /**
+ * Start record mode.
+ *
+ * When a record image is available, a CAMERA_MSG_VIDEO_FRAME message is
+ * sent with the corresponding frame. Every record frame must be released by
+ * a camera HAL client via releaseRecordingFrame() before the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's
+ * responsibility to manage the life-cycle of the video recording frames,
+ * and the client must not modify/access any video recording frames.
+ *
+ * @return status The status code for the operation.
+ */
+ startRecording() generates (Status status);
+
+ /**
+ * Stop a previously started recording.
+ */
+ stopRecording();
+
+ /**
+ * Returns true if recording is enabled.
+ *
+ * @return enabled True if recording is currently active.
+ */
+ recordingEnabled() generates (bool enabled);
+
+ /**
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME in
+ * dataCallbackTimestamp.
+ *
+ * It is camera HAL client's responsibility to release video recording
+ * frames sent out by the camera HAL before the camera HAL receives a call
+ * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's
+ * responsibility to manage the life-cycle of the video recording frames.
+ *
+ * @param memId The memory buffer to release a recording frame from.
+ * @param bufferIndex The specific buffer index to return to the HAL.
+ */
+ releaseRecordingFrame(MemoryId memId, uint32_t bufferIndex);
+
+ /**
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME in
+ * handleCallbackTimestamp.
+ *
+ * It is camera HAL client's responsibility to release video recording
+ * frames sent out by the camera HAL before the camera HAL receives a call
+ * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's
+ * responsibility to manage the life-cycle of the video recording frames.
+ *
+ * @param memId The memory buffer to release a recording frame from.
+ * @param bufferIndex The specific buffer index to return to the HAL.
+ * @param frame The handle for a released video frame
+ */
+ releaseRecordingFrameHandle(MemoryId memId, uint32_t bufferIndex, handle frame);
+
+ /**
+ * Start auto focus.
+ *
+ * The notification callback routine is called with
+ * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() can be
+ * called again after that if another auto focus is needed.
+ *
+ * @return status The status code for this operation.
+ */
+ autoFocus() generates (Status status);
+
+ /**
+ * Cancels auto-focus function.
+ *
+ * If the auto-focus is still in progress, this function must cancel
+ * it. Whether the auto-focus is in progress or not, this function must
+ * return the focus position to the default. If the camera does not support
+ * auto-focus, this is a no-op.
+ *
+ * @return status The status code for this operation.
+ */
+ cancelAutoFocus() generates (Status status);
+
+ /**
+ * Take a picture.
+ *
+ * @return status The status code for this operation.
+ */
+ takePicture() generates (Status status);
+
+ /**
+ * Cancel a picture that was started with takePicture. Calling this method
+ * when no picture is being taken is a no-op.
+ *
+ * @return status The status code for this operation.
+ */
+ cancelPicture() generates (Status status);
+
+ /**
+ * Set the camera parameters.
+ *
+ * @param params The parameter string, consisting of
+ * '<key1>=<value1>; ...;<keyN>=<valueN>'.
+ * @return status The status code for this operation:
+ * OK: Parameter update was successful
+ * ILLEGAL_ARGUMENT: At least one parameter was invalid or not supported
+ *
+ */
+ setParameters(string params) generates (Status status);
+
+ /**
+ * Retrieve the camera parameters.
+ */
+ getParameters() generates (string parms);
+
+ /**
+ * Send command to camera driver.
+ * The meaning of the arguments is defined by the value of cmd, documented
+ * in the CommandType definition.
+ *
+ * @param cmd The command to invoke.
+ * @param arg1 The first argument for the command, if needed.
+ * @param arg2 The second argument for the command, if needed.
+ *
+ * @return status The status code for this operation.
+ */
+ sendCommand(CommandType cmd, int32_t arg1, int32_t arg2)
+ generates (Status status);
+
+ /**
+ * Release the hardware resources owned by this object, shutting down the
+ * camera device.
+ */
+ close();
+
+};
diff --git a/camera/device/1.0/ICameraDeviceCallback.hal b/camera/device/1.0/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..1b0db24
--- /dev/null
+++ b/camera/device/1.0/ICameraDeviceCallback.hal
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 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.camera.device@1.0;
+
+interface ICameraDeviceCallback {
+
+ /**
+ * Notify the camera service of a particular event occurring
+ * The meaning of each parameter is defined by the value of msgType, and
+ * documented in the definition of NotifyCallbackMsg.
+ *
+ * @param msgType The type of the event.
+ * @param ext1 The first parameter for the event, if needed.
+ * @param ext2 The second parameter for the event, if needed.
+ */
+ notifyCallback(NotifyCallbackMsg msgType, int32_t ext1, int32_t ext2);
+
+ /**
+ * Define a memory buffer from the provided handle and size, and return a
+ * unique identifier for the HAL to use to reference it with.
+ *
+ * TODO(b/33269977): Ensure this aligns with design and performance goals.
+ *
+ * @param descriptor A native handle that must have exactly one file
+ * descriptor in it; the file descriptor must be memory mappable to
+ * bufferSize * bufferCount bytes.
+ * @param bufferSize The number of bytes a single buffer consists of.
+ * @param bufferCount The number of contiguous buffers that the descriptor
+ * contains.
+ *
+ * @return memId A positive integer identifier for this memory buffer, for
+ * use with data callbacks and unregistering memory. 0 must be returned
+ * in case of error, such as if the descriptor does not contain exactly
+ * one FD.
+ */
+ registerMemory(handle descriptor, uint32_t bufferSize, uint32_t bufferCount)
+ generates (MemoryId memId);
+
+ /**
+ * Unregister a previously registered memory buffer
+ */
+ unregisterMemory(MemoryId memId);
+
+ /**
+ * Send a buffer of image data to the camera service
+ *
+ * @param msgType The kind of image buffer data this call represents.
+ * @param data A memory handle to the buffer containing the data.
+ * @param bufferIndex The offset into the memory handle where the buffer
+ * starts.
+ *
+ */
+ dataCallback(DataCallbackMsg msgType, MemoryId data, uint32_t bufferIndex,
+ CameraFrameMetadata metadata);
+
+ /**
+ * Send a buffer of image data to the camera service, with a timestamp
+ *
+ * @param msgType The kind of image buffer data this call represents.
+ * @param data A memory handle to the buffer containing the data.
+ * @param bufferIndex The offset into the memory handle where the buffer
+ * starts.
+ * @param timestamp The time this buffer was captured by the camera, in
+ * nanoseconds.
+ *
+ */
+ dataCallbackTimestamp(DataCallbackMsg msgType, MemoryId data, uint32_t bufferIndex,
+ int64_t timestamp);
+
+ /**
+ * Send a buffer of image data to the camera service, with a timestamp
+ *
+ * @param msgType The kind of image buffer data this call represents.
+ * @param handle The handle of image buffer data this call represents.
+ * @param data A memory handle to the buffer containing the data.
+ * @param bufferIndex The offset into the memory handle where the buffer
+ * starts.
+ * @param timestamp The time this buffer was captured by the camera, in
+ * nanoseconds.
+ *
+ * @return frameId a frame ID to be used with releaseRecordingFrameId later
+ *
+ */
+ handleCallbackTimestamp(DataCallbackMsg msgType, handle frameData, MemoryId data,
+ uint32_t bufferIndex, int64_t timestamp);
+
+};
diff --git a/camera/device/1.0/ICameraDevicePreviewCallback.hal b/camera/device/1.0/ICameraDevicePreviewCallback.hal
new file mode 100644
index 0000000..4c9b517
--- /dev/null
+++ b/camera/device/1.0/ICameraDevicePreviewCallback.hal
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 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.camera.device@1.0;
+
+import android.hardware.camera.common@1.0::types;
+import android.hardware.graphics.allocator@2.0::types;
+import android.hardware.graphics.common@1.0::types;
+
+/**
+ * Camera device HAL@1.0 preview stream operation interface.
+ */
+interface ICameraDevicePreviewCallback {
+
+ /**
+ * Acquire a buffer to write a preview buffer into.
+ *
+ * @return status The status code for this operation. If not OK, then
+ * buffer and stride must not be used.
+ * @return bufferId A unique ID for the returned buffer.
+ * @return buffer A handle to the buffer to write into. Must be non-null if the bufferId has not
+ * been seen by HAL before. Must be null if the bufferId is seen before. HAL must keep track
+ * of the bufferId to actual buffer handle mapping.
+ * @return stride The stride between two rows of pixels in this buffer.
+ */
+ dequeueBuffer() generates (Status status, uint64_t bufferId, handle buffer, uint32_t stride);
+
+ /**
+ * Send a filled preview buffer to its consumer.
+ *
+ * @param bufferId The bufferId of the preview buffer
+ * @return status The status code for this operation.
+ */
+ enqueueBuffer(uint64_t bufferId) generates (Status status);
+
+ /**
+ * Return a preview buffer unfilled. This buffer must not be sent on to the
+ * preview consumer as a valid buffer, but may be reused as if it were
+ * empty.
+ *
+ * @param bufferId The bufferId of the preview buffer
+ * @return status The status code for this operation.
+ */
+ cancelBuffer(uint64_t bufferId) generates (Status status);
+
+ /**
+ * Set the number of preview buffers needed by the HAL.
+ *
+ * @param count The maximum number of preview buffers to allocate.
+ * @return status The status code for this operation.
+ */
+ setBufferCount(uint32_t count) generates (Status status);
+
+ /**
+ * Set the dimensions and format of future preview buffers.
+ *
+ * The next buffer that is dequeued must match the requested size and
+ * format.
+ *
+ * @return Status The status code for this operation.
+ */
+ setBuffersGeometry(uint32_t w, uint32_t h,
+ android.hardware.graphics.common@1.0::PixelFormat format)
+ generates (Status status);
+
+ /**
+ * Set the valid region of image data for the next buffer(s) to be enqueued.
+ *
+ * @return Status The status code for this operation.
+ */
+ setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom)
+ generates (Status status);
+
+ /**
+ * Set the producer usage flags for the next buffer(s) to be enqueued.
+ *
+ * @return Status The status code for this operation.
+ */
+ setUsage(ProducerUsage usage) generates (Status status);
+
+ /**
+ * Set the expected buffering mode for the preview output.
+ */
+ setSwapInterval(int32_t interval) generates (Status status);
+
+ /**
+ * Get the minimum number of buffers the preview consumer endpoint needs
+ * to hold for correct operation.
+ *
+ * @return Status The status code for this operation.
+ * @return count The number of buffers the consumer has requested.
+ */
+ getMinUndequeuedBufferCount() generates (Status status, uint32_t count);
+
+ /**
+ * Set the timestamp for the next buffer to enqueue
+ *
+ * Timestamps are measured in nanoseconds, and must be comparable
+ * and monotonically increasing between two frames in the same
+ * preview stream. They do not need to be comparable between
+ * consecutive or parallel preview streams, cameras, or app runs.
+ *
+ * @param timestamp The timestamp to set for future buffers.
+ * @return Status The status code for this operation.
+ */
+ setTimestamp(int64_t timestamp) generates (Status status);
+
+};
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
new file mode 100644
index 0000000..5688fc1
--- /dev/null
+++ b/camera/device/1.0/default/Android.bp
@@ -0,0 +1,29 @@
+cc_library_shared {
+ name: "camera.device@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ srcs: [
+ "CameraDevice.cpp",
+ ],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ "libcutils",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata",
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper"
+ ],
+ export_include_dirs: ["."]
+}
+
diff --git a/camera/device/1.0/default/CameraDevice.cpp b/camera/device/1.0/default/CameraDevice.cpp
new file mode 100644
index 0000000..819525b
--- /dev/null
+++ b/camera/device/1.0/default/CameraDevice.cpp
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "CamDev@1.0-impl"
+#include <utils/Log.h>
+#include <hardware/camera.h>
+#include <hardware/gralloc1.h>
+#include <utils/Trace.h>
+
+#include "CameraDevice_1_0.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+HandleImporter& CameraDevice::sHandleImporter = HandleImporter::getInstance();
+
+Status CameraDevice::getHidlStatus(const int& status) {
+ switch (status) {
+ case 0: return Status::OK;
+ case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED;
+ case -EBUSY : return Status::CAMERA_IN_USE;
+ case -EUSERS: return Status::MAX_CAMERAS_IN_USE;
+ case -ENODEV: return Status::INTERNAL_ERROR;
+ case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+ default:
+ ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+ return Status::INTERNAL_ERROR;
+ }
+}
+
+status_t CameraDevice::getStatusT(const Status& s) {
+ switch(s) {
+ case Status::OK:
+ return OK;
+ case Status::ILLEGAL_ARGUMENT:
+ return BAD_VALUE;
+ case Status::CAMERA_IN_USE:
+ return -EBUSY;
+ case Status::MAX_CAMERAS_IN_USE:
+ return -EUSERS;
+ case Status::METHOD_NOT_SUPPORTED:
+ return UNKNOWN_TRANSACTION;
+ case Status::OPERATION_NOT_SUPPORTED:
+ return INVALID_OPERATION;
+ case Status::CAMERA_DISCONNECTED:
+ return DEAD_OBJECT;
+ case Status::INTERNAL_ERROR:
+ return INVALID_OPERATION;
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return INVALID_OPERATION;
+}
+
+Status CameraDevice::initStatus() const {
+ Mutex::Autolock _l(mLock);
+ Status status = Status::OK;
+ if (mInitFail) {
+ status = Status::INTERNAL_ERROR;
+ } else if (mDisconnected) {
+ status = Status::CAMERA_DISCONNECTED;
+ }
+ return status;
+}
+
+CameraDevice::CameraDevice(
+ sp<CameraModule> module, const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+ mModule(module),
+ mCameraId(cameraId),
+ mDisconnected(false),
+ mCameraDeviceNames(cameraDeviceNames) {
+ mCameraIdInt = atoi(mCameraId.c_str());
+ // Should not reach here as provider also validate ID
+ if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+ ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+
+ mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
+ if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && !mModule->isOpenLegacyDefined()) {
+ ALOGI("%s: Camera id %s does not support HAL1.0",
+ __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+}
+
+CameraDevice::~CameraDevice() {
+ Mutex::Autolock _l(mLock);
+ if (mDevice != nullptr) {
+ ALOGW("%s: camera %s is deleted while open", __FUNCTION__, mCameraId.c_str());
+ close();
+ }
+ mHalPreviewWindow.cleanUpCirculatingBuffers();
+}
+
+
+void CameraDevice::setConnectionStatus(bool connected) {
+ Mutex::Autolock _l(mLock);
+ mDisconnected = !connected;
+ if (mDevice == nullptr) {
+ return;
+ }
+ if (!connected) {
+ ALOGW("%s: camera %s is disconneted. Closing", __FUNCTION__, mCameraId.c_str());
+ close();
+ }
+ return;
+}
+
+void CameraDevice::CameraPreviewWindow::cleanUpCirculatingBuffers() {
+ Mutex::Autolock _l(mLock);
+ for (auto pair : mCirculatingBuffers) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers.clear();
+ mBufferIdMap.clear();
+}
+
+int CameraDevice::sDequeueBuffer(struct preview_stream_ops* w,
+ buffer_handle_t** buffer, int *stride) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (buffer == nullptr || stride == nullptr) {
+ ALOGE("%s: buffer (%p) and stride (%p) must not be null!", __FUNCTION__, buffer, stride);
+ return BAD_VALUE;
+ }
+
+ Status s;
+ object->mPreviewCallback->dequeueBuffer(
+ [&](auto status, uint64_t bufferId, const auto& buf, uint32_t strd) {
+ s = status;
+ if (s == Status::OK) {
+ Mutex::Autolock _l(object->mLock);
+ if (object->mCirculatingBuffers.count(bufferId) == 0) {
+ buffer_handle_t importedBuf = buf.getNativeHandle();
+ sHandleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: preview buffer import failed!", __FUNCTION__);
+ s = Status::INTERNAL_ERROR;
+ return;
+ } else {
+ object->mCirculatingBuffers[bufferId] = importedBuf;
+ object->mBufferIdMap[&(object->mCirculatingBuffers[bufferId])] = bufferId;
+ }
+ }
+ *buffer = &(object->mCirculatingBuffers[bufferId]);
+ *stride = strd;
+ }
+ });
+ return getStatusT(s);
+}
+
+int CameraDevice::sLockBuffer(struct preview_stream_ops*, buffer_handle_t*) {
+ // TODO: make sure lock_buffer is indeed a no-op (and will always be)
+ return 0;
+}
+
+int CameraDevice::sEnqueueBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ uint64_t bufferId = object->mBufferIdMap.at(buffer);
+ return getStatusT(object->mPreviewCallback->enqueueBuffer(bufferId));
+}
+
+int CameraDevice::sCancelBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ uint64_t bufferId = object->mBufferIdMap.at(buffer);
+ return getStatusT(object->mPreviewCallback->cancelBuffer(bufferId));
+}
+
+int CameraDevice::sSetBufferCount(struct preview_stream_ops* w, int count) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ object->cleanUpCirculatingBuffers();
+ return getStatusT(object->mPreviewCallback->setBufferCount(count));
+}
+
+int CameraDevice::sSetBuffersGeometry(struct preview_stream_ops* w,
+ int width, int height, int format) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ object->cleanUpCirculatingBuffers();
+ return getStatusT(
+ object->mPreviewCallback->setBuffersGeometry(width, height, (PixelFormat) format));
+}
+
+int CameraDevice::sSetCrop(struct preview_stream_ops *w,
+ int left, int top, int right, int bottom) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ return getStatusT(object->mPreviewCallback->setCrop(left, top, right, bottom));
+}
+
+int CameraDevice::sSetTimestamp(struct preview_stream_ops *w, int64_t timestamp) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ return getStatusT(object->mPreviewCallback->setTimestamp(timestamp));
+}
+
+int CameraDevice::sSetUsage(struct preview_stream_ops* w, int usage) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ object->cleanUpCirculatingBuffers();
+ return getStatusT(object->mPreviewCallback->setUsage((ProducerUsage) usage));
+}
+
+int CameraDevice::sSetSwapInterval(struct preview_stream_ops *w, int interval) {
+ CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ return getStatusT(object->mPreviewCallback->setSwapInterval(interval));
+}
+
+int CameraDevice::sGetMinUndequeuedBufferCount(
+ const struct preview_stream_ops *w,
+ int *count) {
+ const CameraPreviewWindow* object = static_cast<const CameraPreviewWindow*>(w);
+ if (object->mPreviewCallback == nullptr) {
+ ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (count == nullptr) {
+ ALOGE("%s: count is null!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Status s;
+ object->mPreviewCallback->getMinUndequeuedBufferCount(
+ [&](auto status, uint32_t cnt) {
+ s = status;
+ if (s == Status::OK) {
+ *count = cnt;
+ }
+ });
+ return getStatusT(s);
+}
+
+CameraDevice::CameraHeapMemory::CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers) :
+ mBufSize(buf_size),
+ mNumBufs(num_buffers) {
+ mHeap = new MemoryHeapBase(fd, buf_size * num_buffers);
+ commonInitialization();
+}
+
+CameraDevice::CameraHeapMemory::CameraHeapMemory(size_t buf_size, uint_t num_buffers) :
+ mBufSize(buf_size),
+ mNumBufs(num_buffers) {
+ mHeap = new MemoryHeapBase(buf_size * num_buffers);
+ commonInitialization();
+}
+
+void CameraDevice::CameraHeapMemory::commonInitialization() {
+ handle.data = mHeap->base();
+ handle.size = mBufSize * mNumBufs;
+ handle.handle = this;
+
+ mBuffers = new sp<MemoryBase>[mNumBufs];
+ for (uint_t i = 0; i < mNumBufs; i++) {
+ mBuffers[i] = new MemoryBase(mHeap, i * mBufSize, mBufSize);
+ }
+
+ handle.release = sPutMemory;
+}
+
+CameraDevice::CameraHeapMemory::~CameraHeapMemory() {
+ delete [] mBuffers;
+}
+
+// shared memory methods
+camera_memory_t* CameraDevice::sGetMemory(int fd, size_t buf_size, uint_t num_bufs, void *user) {
+ ALOGV("%s", __FUNCTION__);
+ CameraDevice* object = static_cast<CameraDevice*>(user);
+ if (object->mDeviceCallback == nullptr) {
+ ALOGE("%s: camera HAL request memory while camera is not opened!", __FUNCTION__);
+ return nullptr;
+ }
+
+ CameraHeapMemory* mem;
+ native_handle_t* handle = native_handle_create(1,0);
+
+ if (handle == nullptr) {
+ ALOGE("%s: native_handle_create failed!", __FUNCTION__);
+ return nullptr;
+ }
+
+ if (fd < 0) {
+ mem = new CameraHeapMemory(buf_size, num_bufs);
+ } else {
+ mem = new CameraHeapMemory(fd, buf_size, num_bufs);
+ }
+ handle->data[0] = mem->mHeap->getHeapID();
+ mem->incStrong(mem);
+
+ hidl_handle hidlHandle = handle;
+ MemoryId id = object->mDeviceCallback->registerMemory(hidlHandle, buf_size, num_bufs);
+ mem->handle.mId = id;
+ if (object->mMemoryMap.count(id) != 0) {
+ ALOGE("%s: duplicate MemoryId %d returned by client!", __FUNCTION__, id);
+ }
+ object->mMemoryMap[id] = mem;
+ mem->handle.mDevice = object;
+ native_handle_delete(handle);
+ return &mem->handle;
+}
+
+void CameraDevice::sPutMemory(camera_memory_t *data) {
+ if (!data)
+ return;
+
+ CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle);
+ CameraDevice* device = mem->handle.mDevice;
+ if (device == nullptr) {
+ ALOGE("%s: camera HAL return memory for a null device!", __FUNCTION__);
+ }
+ if (device->mDeviceCallback == nullptr) {
+ ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__);
+ }
+ device->mDeviceCallback->unregisterMemory(mem->handle.mId);
+ device->mMemoryMap.erase(mem->handle.mId);
+ mem->decStrong(mem);
+}
+
+// Callback forwarding methods
+void CameraDevice::sNotifyCb(int32_t msg_type, int32_t ext1, int32_t ext2, void *user) {
+ ALOGV("%s", __FUNCTION__);
+ CameraDevice* object = static_cast<CameraDevice*>(user);
+ if (object->mDeviceCallback != nullptr) {
+ object->mDeviceCallback->notifyCallback((NotifyCallbackMsg) msg_type, ext1, ext2);
+ }
+}
+
+void CameraDevice::sDataCb(int32_t msg_type, const camera_memory_t *data, unsigned int index,
+ camera_frame_metadata_t *metadata, void *user) {
+ ALOGV("%s", __FUNCTION__);
+ CameraDevice* object = static_cast<CameraDevice*>(user);
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle));
+ if (index >= mem->mNumBufs) {
+ ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+ index, mem->mNumBufs);
+ return;
+ }
+ if (object->mDeviceCallback != nullptr) {
+ CameraFrameMetadata hidlMetadata;
+ if (metadata) {
+ hidlMetadata.faces.resize(metadata->number_of_faces);
+ for (size_t i = 0; i < hidlMetadata.faces.size(); i++) {
+ hidlMetadata.faces[i].score = metadata->faces[i].score;
+ hidlMetadata.faces[i].id = metadata->faces[i].id;
+ for (int k = 0; k < 4; k++) {
+ hidlMetadata.faces[i].rect[k] = metadata->faces[i].rect[k];
+ }
+ for (int k = 0; k < 2; k++) {
+ hidlMetadata.faces[i].leftEye[k] = metadata->faces[i].left_eye[k];
+ }
+ for (int k = 0; k < 2; k++) {
+ hidlMetadata.faces[i].rightEye[k] = metadata->faces[i].right_eye[k];
+ }
+ for (int k = 0; k < 2; k++) {
+ hidlMetadata.faces[i].mouth[k] = metadata->faces[i].mouth[k];
+ }
+ }
+ }
+ CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle);
+ object->mDeviceCallback->dataCallback(
+ (DataCallbackMsg) msg_type, mem->handle.mId, index, hidlMetadata);
+ }
+}
+
+void CameraDevice::sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type,
+ const camera_memory_t *data, unsigned index, void *user) {
+ ALOGV("%s", __FUNCTION__);
+ CameraDevice* object = static_cast<CameraDevice*>(user);
+ // Start refcounting the heap object from here on. When the clients
+ // drop all references, it will be destroyed (as well as the enclosed
+ // MemoryHeapBase.
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle));
+ if (index >= mem->mNumBufs) {
+ ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+ index, mem->mNumBufs);
+ return;
+ }
+
+ native_handle_t* handle = nullptr;
+ if (object->mMetadataMode) {
+ if (mem->mBufSize == sizeof(VideoNativeHandleMetadata)) {
+ VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+ mem->mBuffers[index]->pointer();
+ if (md->eType == VideoNativeHandleMetadata::kMetadataBufferTypeNativeHandleSource) {
+ handle = md->pHandle;
+ }
+ }
+ }
+
+ if (object->mDeviceCallback != nullptr) {
+ if (handle == nullptr) {
+ object->mDeviceCallback->dataCallbackTimestamp(
+ (DataCallbackMsg) msg_type, mem->handle.mId, index, timestamp);
+ } else {
+ object->mDeviceCallback->handleCallbackTimestamp(
+ (DataCallbackMsg) msg_type, handle, mem->handle.mId, index, timestamp);
+ }
+ }
+}
+
+void CameraDevice::initHalPreviewWindow()
+{
+ mHalPreviewWindow.cancel_buffer = sCancelBuffer;
+ mHalPreviewWindow.lock_buffer = sLockBuffer;
+ mHalPreviewWindow.dequeue_buffer = sDequeueBuffer;
+ mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer;
+ mHalPreviewWindow.set_buffer_count = sSetBufferCount;
+ mHalPreviewWindow.set_buffers_geometry = sSetBuffersGeometry;
+ mHalPreviewWindow.set_crop = sSetCrop;
+ mHalPreviewWindow.set_timestamp = sSetTimestamp;
+ mHalPreviewWindow.set_usage = sSetUsage;
+ mHalPreviewWindow.set_swap_interval = sSetSwapInterval;
+
+ mHalPreviewWindow.get_min_undequeued_buffer_count =
+ sGetMinUndequeuedBufferCount;
+}
+
+// Methods from ::android::hardware::camera::device::V1_0::ICameraDevice follow.
+Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraResourceCost resCost;
+ if (status == Status::OK) {
+ int cost = 100;
+ std::vector<std::string> conflicting_devices;
+ struct camera_info info;
+
+ // If using post-2.4 module version, query the cost + conflicting devices from the HAL
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ cost = info.resource_cost;
+ for (size_t i = 0; i < info.conflicting_devices_length; i++) {
+ std::string cameraId(info.conflicting_devices[i]);
+ for (const auto& pair : mCameraDeviceNames) {
+ if (cameraId == pair.first) {
+ conflicting_devices.push_back(pair.second);
+ }
+ }
+ }
+ } else {
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+
+ if (status == Status::OK) {
+ resCost.resourceCost = cost;
+ resCost.conflictingDevices.resize(conflicting_devices.size());
+ for (size_t i = 0; i < conflicting_devices.size(); i++) {
+ resCost.conflictingDevices[i] = conflicting_devices[i];
+ ALOGV("CamDevice %s is conflicting with camDevice %s",
+ mCameraId.c_str(), resCost.conflictingDevices[i].c_str());
+ }
+ }
+ }
+ _hidl_cb(status, resCost);
+ return Void();
+}
+
+Return<void> CameraDevice::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraInfo cameraInfo;
+ if (status == Status::OK) {
+ struct camera_info info;
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ cameraInfo.facing = (CameraFacing) info.facing;
+ // Device 1.0 does not support external camera facing.
+ // The closest approximation would be front camera.
+ // TODO: figure out should we override here or let
+ // camera service handle it.
+ if (cameraInfo.facing == CameraFacing::EXTERNAL) {
+ cameraInfo.facing = CameraFacing::FRONT;
+ }
+ cameraInfo.orientation = info.orientation;
+ } else {
+ ALOGE("%s: get camera info failed!", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ _hidl_cb(status, cameraInfo);
+ return Void();
+}
+
+Return<Status> CameraDevice::setTorchMode(TorchMode mode) {
+ if (!mModule->isSetTorchModeSupported()) {
+ return Status::METHOD_NOT_SUPPORTED;
+ }
+
+ Status status = initStatus();
+ if (status == Status::OK) {
+ bool enable = (mode == TorchMode::ON) ? true : false;
+ status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable));
+ }
+ return status;
+}
+
+Return<Status> CameraDevice::dumpState(const hidl_handle& handle) {
+ Mutex::Autolock _l(mLock);
+ if (handle.getNativeHandle() == nullptr) {
+ ALOGE("%s: handle must not be null", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ if (handle->numFds != 1 || handle->numInts != 0) {
+ ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
+ __FUNCTION__, handle->numFds, handle->numInts);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ int fd = handle->data[0];
+
+ if (mDevice != nullptr) {
+ if (mDevice->ops->dump) { // It's fine if the HAL doesn't implement dump()
+ return getHidlStatus(mDevice->ops->dump(mDevice, fd));
+ }
+ }
+ return Status::OK;
+}
+
+Return<Status> CameraDevice::open(const sp<ICameraDeviceCallback>& callback) {
+ ALOGI("Opening camera %s", mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+
+ camera_info info;
+ status_t res = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (res != OK) {
+ ALOGE("Could not get camera info: %s: %d", mCameraId.c_str(), res);
+ return getHidlStatus(res);
+ }
+
+ int rc = OK;
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
+ info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
+ // Open higher version camera device as HAL1.0 device.
+ rc = mModule->openLegacy(mCameraId.c_str(),
+ CAMERA_DEVICE_API_VERSION_1_0,
+ (hw_device_t **)&mDevice);
+ } else {
+ rc = mModule->open(mCameraId.c_str(), (hw_device_t **)&mDevice);
+ }
+ if (rc != OK) {
+ mDevice = nullptr;
+ ALOGE("Could not open camera %s: %d", mCameraId.c_str(), rc);
+ return getHidlStatus(rc);
+ }
+
+ initHalPreviewWindow();
+ mDeviceCallback = callback;
+
+ if (mDevice->ops->set_callbacks) {
+ mDevice->ops->set_callbacks(mDevice,
+ sNotifyCb, sDataCb, sDataCbTimestamp, sGetMemory, this);
+ }
+
+ return getHidlStatus(rc);
+}
+
+Return<Status> CameraDevice::setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+
+ mHalPreviewWindow.mPreviewCallback = window;
+ if (mDevice->ops->set_preview_window) {
+ return getHidlStatus(mDevice->ops->set_preview_window(mDevice,
+ (window == nullptr) ? nullptr : &mHalPreviewWindow));
+ }
+ return Status::INTERNAL_ERROR; // HAL should provide set_preview_window
+}
+
+Return<void> CameraDevice::enableMsgType(uint32_t msgType) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Void();
+ }
+ if (mDevice->ops->enable_msg_type) {
+ mDevice->ops->enable_msg_type(mDevice, msgType);
+ }
+ return Void();
+}
+
+Return<void> CameraDevice::disableMsgType(uint32_t msgType) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Void();
+ }
+ if (mDevice->ops->disable_msg_type) {
+ mDevice->ops->disable_msg_type(mDevice, msgType);
+ }
+ return Void();
+}
+
+Return<bool> CameraDevice::msgTypeEnabled(uint32_t msgType) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return false;
+ }
+ if (mDevice->ops->msg_type_enabled) {
+ return mDevice->ops->msg_type_enabled(mDevice, msgType);
+ }
+ return false;
+}
+
+Return<Status> CameraDevice::startPreview() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->start_preview) {
+ return getHidlStatus(mDevice->ops->start_preview(mDevice));
+ }
+ return Status::INTERNAL_ERROR; // HAL should provide start_preview
+}
+
+Return<void> CameraDevice::stopPreview() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Void();
+ }
+ if (mDevice->ops->stop_preview) {
+ mDevice->ops->stop_preview(mDevice);
+ }
+ return Void();
+}
+
+Return<bool> CameraDevice::previewEnabled() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return false;
+ }
+ if (mDevice->ops->preview_enabled) {
+ return mDevice->ops->preview_enabled(mDevice);
+ }
+ return false;
+}
+
+Return<Status> CameraDevice::storeMetaDataInBuffers(bool enable) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->store_meta_data_in_buffers) {
+ status_t s = mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
+ if (s == OK && enable) {
+ mMetadataMode = true;
+ }
+ return getHidlStatus(s);
+ }
+ return enable ? Status::ILLEGAL_ARGUMENT : Status::OK;
+}
+
+Return<Status> CameraDevice::startRecording() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->start_recording) {
+ return getHidlStatus(mDevice->ops->start_recording(mDevice));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> CameraDevice::stopRecording() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Void();
+ }
+ if (mDevice->ops->stop_recording) {
+ mDevice->ops->stop_recording(mDevice);
+ }
+ return Void();
+}
+
+Return<bool> CameraDevice::recordingEnabled() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return false;
+ }
+ if (mDevice->ops->recording_enabled) {
+ return mDevice->ops->recording_enabled(mDevice);
+ }
+ return false;
+}
+
+void CameraDevice::releaseRecordingFrameLocked(
+ uint32_t memId, uint32_t bufferIndex, const native_handle_t* handle) {
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return;
+ }
+ if (mDevice->ops->release_recording_frame) {
+ CameraHeapMemory* camMemory = mMemoryMap.at(memId);
+ sp<MemoryHeapBase> heap = camMemory->mHeap;
+ if (bufferIndex >= camMemory->mNumBufs) {
+ ALOGE("%s: bufferIndex %d exceeds number of buffers %d",
+ __FUNCTION__, bufferIndex, camMemory->mNumBufs);
+ return;
+ }
+ sp<IMemory> mem = camMemory->mBuffers[bufferIndex];
+ // TODO: simplify below logic once we verify offset is indeed idx * mBufSize
+ // and heap == heap2
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap2 = mem->getMemory(&offset, &size);
+ if ((size_t)offset != bufferIndex * camMemory->mBufSize) {
+ ALOGI("%s: unexpected offset %zd (was expecting %zu)",
+ __FUNCTION__, offset, bufferIndex * camMemory->mBufSize);
+ }
+ if (heap != heap2) {
+ ALOGE("%s: heap mismatch!", __FUNCTION__);
+ return;
+ }
+ void *data = ((uint8_t *)heap->base()) + offset;
+ if (handle) {
+ VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) data;
+ if (md->eType == VideoNativeHandleMetadata::kMetadataBufferTypeNativeHandleSource) {
+ // Input handle will be closed by HIDL transport later, so clone it
+ // HAL implementation is responsible to close/delete the clone
+ native_handle_t* clone = native_handle_clone(handle);
+ if (!clone) {
+ ALOGE("%s: failed to clone buffer %p", __FUNCTION__, handle);
+ return;
+ }
+ md->pHandle = clone;
+ } else {
+ ALOGE("%s:Malform VideoNativeHandleMetadata at memId %d, bufferId %d",
+ __FUNCTION__, memId, bufferIndex);
+ return;
+ }
+ }
+ mDevice->ops->release_recording_frame(mDevice, data);
+ }
+}
+
+Return<void> CameraDevice::releaseRecordingFrame(uint32_t memId, uint32_t bufferIndex) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ releaseRecordingFrameLocked(memId, bufferIndex, nullptr);
+ return Void();
+}
+
+Return<void> CameraDevice::releaseRecordingFrameHandle(
+ uint32_t memId, uint32_t bufferIndex, const hidl_handle& frame) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ releaseRecordingFrameLocked(
+ memId, bufferIndex, frame.getNativeHandle());
+ return Void();
+}
+
+Return<Status> CameraDevice::autoFocus() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->auto_focus) {
+ return getHidlStatus(mDevice->ops->auto_focus(mDevice));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<Status> CameraDevice::cancelAutoFocus() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->cancel_auto_focus) {
+ return getHidlStatus(mDevice->ops->cancel_auto_focus(mDevice));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<Status> CameraDevice::takePicture() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->take_picture) {
+ return getHidlStatus(mDevice->ops->take_picture(mDevice));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<Status> CameraDevice::cancelPicture() {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->cancel_picture) {
+ return getHidlStatus(mDevice->ops->cancel_picture(mDevice));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<Status> CameraDevice::setParameters(const hidl_string& params) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->set_parameters) {
+ return getHidlStatus(mDevice->ops->set_parameters(mDevice, params.c_str()));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> CameraDevice::getParameters(getParameters_cb _hidl_cb) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ hidl_string outStr;
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ _hidl_cb(outStr);
+ return Void();
+ }
+ if (mDevice->ops->get_parameters) {
+ char *temp = mDevice->ops->get_parameters(mDevice);
+ outStr = temp;
+ if (mDevice->ops->put_parameters) {
+ mDevice->ops->put_parameters(mDevice, temp);
+ } else {
+ free(temp);
+ }
+ }
+ _hidl_cb(outStr);
+ return Void();
+}
+
+Return<Status> CameraDevice::sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) {
+ ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if (!mDevice) {
+ ALOGE("%s called while camera is not opened", __FUNCTION__);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+ if (mDevice->ops->send_command) {
+ return getHidlStatus(mDevice->ops->send_command(mDevice, (int32_t) cmd, arg1, arg2));
+ }
+ return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> CameraDevice::close() {
+ ALOGI("Closing camera %s", mCameraId.c_str());
+ Mutex::Autolock _l(mLock);
+ if(mDevice) {
+ int rc = mDevice->common.close(&mDevice->common);
+ if (rc != OK) {
+ ALOGE("Could not close camera %s: %d", mCameraId.c_str(), rc);
+ }
+ mDevice = nullptr;
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/1.0/default/CameraDevice_1_0.h b/camera/device/1.0/default/CameraDevice_1_0.h
new file mode 100644
index 0000000..2568f86
--- /dev/null
+++ b/camera/device/1.0/default/CameraDevice_1_0.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H
+
+#include <unordered_map>
+#include "utils/Mutex.h"
+#include "utils/SortedVector.h"
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include "CameraModule.h"
+#include "HandleImporter.h"
+
+#include <android/hardware/camera/device/1.0/ICameraDevice.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::device::V1_0::CameraInfo;
+using ::android::hardware::camera::device::V1_0::CommandType;
+using ::android::hardware::camera::device::V1_0::ICameraDevice;
+using ::android::hardware::camera::device::V1_0::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
+using ::android::hardware::camera::device::V1_0::MemoryId;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct CameraDevice : public ICameraDevice {
+
+ // Called by provider HAL. Provider HAL must ensure the uniqueness of
+ // CameraDevice object per cameraId, or there could be multiple CameraDevice
+ // trying to access the same physical camera.
+ // Also, provider will have to keep track of all CameraDevice objects in
+ // order to notify CameraDevice when the underlying camera is detached
+ CameraDevice(sp<CameraModule> module,
+ const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+ ~CameraDevice();
+
+ // Caller must use this method to check if CameraDevice ctor failed
+ bool isInitFailed() { return mInitFail; }
+ // Used by provider HAL to signal external camera disconnected
+ void setConnectionStatus(bool connected);
+
+ // Methods from ::android::hardware::camera::device::V1_0::ICameraDevice follow.
+ Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
+ Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+ Return<Status> setTorchMode(TorchMode mode) override;
+ Return<Status> dumpState(const hidl_handle& fd) override;
+ Return<Status> open(const sp<ICameraDeviceCallback>& callback) override;
+ Return<Status> setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) override;
+ Return<void> enableMsgType(uint32_t msgType) override;
+ Return<void> disableMsgType(uint32_t msgType) override;
+ Return<bool> msgTypeEnabled(uint32_t msgType) override;
+ Return<Status> startPreview() override;
+ Return<void> stopPreview() override;
+ Return<bool> previewEnabled() override;
+ Return<Status> storeMetaDataInBuffers(bool enable) override;
+ Return<Status> startRecording() override;
+ Return<void> stopRecording() override;
+ Return<bool> recordingEnabled() override;
+ Return<void> releaseRecordingFrame(uint32_t memId, uint32_t bufferIndex) override;
+ Return<void> releaseRecordingFrameHandle(
+ uint32_t memId, uint32_t bufferIndex, const hidl_handle& frame) override;
+ Return<Status> autoFocus() override;
+ Return<Status> cancelAutoFocus() override;
+ Return<Status> takePicture() override;
+ Return<Status> cancelPicture() override;
+ Return<Status> setParameters(const hidl_string& params) override;
+ Return<void> getParameters(getParameters_cb _hidl_cb) override;
+ Return<Status> sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) override;
+ Return<void> close() override;
+
+private:
+ struct CameraMemory : public camera_memory_t {
+ MemoryId mId;
+ CameraDevice* mDevice;
+ };
+
+ class CameraHeapMemory : public RefBase {
+ public:
+ CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers = 1);
+ explicit CameraHeapMemory(size_t buf_size, uint_t num_buffers = 1);
+ void commonInitialization();
+ virtual ~CameraHeapMemory();
+
+ size_t mBufSize;
+ uint_t mNumBufs;
+ // TODO: b/35887419: use hidl_memory instead and get rid of libbinder
+ sp<MemoryHeapBase> mHeap;
+ sp<MemoryBase>* mBuffers;
+ CameraMemory handle;
+ };
+
+ // TODO: b/35625849
+ // Meta data buffer layout for passing a native_handle to codec
+ // matching frameworks/native/include/media/hardware/MetadataBufferType.h and
+ // frameworks/native/include/media/hardware/HardwareAPI.h
+ struct VideoNativeHandleMetadata {
+ static const uint32_t kMetadataBufferTypeNativeHandleSource = 3;
+ uint32_t eType; // must be kMetadataBufferTypeNativeHandleSource
+ native_handle_t* pHandle;
+ };
+
+ const sp<CameraModule> mModule;
+ const std::string mCameraId;
+ // const after ctor
+ int mCameraIdInt;
+ int mDeviceVersion;
+
+ camera_device_t* mDevice = nullptr;
+
+ void initHalPreviewWindow();
+ struct CameraPreviewWindow : public preview_stream_ops {
+ // Called when we expect buffer will be re-allocated
+ void cleanUpCirculatingBuffers();
+
+ Mutex mLock;
+ sp<ICameraDevicePreviewCallback> mPreviewCallback = nullptr;
+ std::unordered_map<uint64_t, buffer_handle_t> mCirculatingBuffers;
+ std::unordered_map<buffer_handle_t*, uint64_t> mBufferIdMap;
+ } mHalPreviewWindow;
+
+ // gating access to mDevice, mInitFail, mDisconnected
+ mutable Mutex mLock;
+
+ bool mInitFail = false;
+ // Set by provider (when external camera is connected/disconnected)
+ bool mDisconnected;
+
+ static HandleImporter& sHandleImporter;
+
+ const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames;
+
+ sp<ICameraDeviceCallback> mDeviceCallback = nullptr;
+
+ std::unordered_map<MemoryId, CameraHeapMemory*> mMemoryMap;
+
+ bool mMetadataMode = false;
+
+ void releaseRecordingFrameLocked(uint32_t memId, uint32_t bufferIndex, const native_handle_t*);
+
+ // shared memory methods
+ static camera_memory_t* sGetMemory(int fd, size_t buf_size, uint_t num_bufs, void *user);
+ static void sPutMemory(camera_memory_t *data);
+
+ // Device callback forwarding methods
+ static void sNotifyCb(int32_t msg_type, int32_t ext1, int32_t ext2, void *user);
+ static void sDataCb(int32_t msg_type, const camera_memory_t *data, unsigned int index,
+ camera_frame_metadata_t *metadata, void *user);
+ static void sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type,
+ const camera_memory_t *data, unsigned index, void *user);
+
+ // Preview window callback forwarding methods
+ static int sDequeueBuffer(struct preview_stream_ops* w,
+ buffer_handle_t** buffer, int *stride);
+
+ static int sLockBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer);
+
+ static int sEnqueueBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer);
+
+ static int sCancelBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer);
+
+ static int sSetBufferCount(struct preview_stream_ops* w, int count);
+
+ static int sSetBuffersGeometry(struct preview_stream_ops* w,
+ int width, int height, int format);
+
+ static int sSetCrop(struct preview_stream_ops *w, int left, int top, int right, int bottom);
+
+ static int sSetTimestamp(struct preview_stream_ops *w, int64_t timestamp);
+
+ static int sSetUsage(struct preview_stream_ops* w, int usage);
+
+ static int sSetSwapInterval(struct preview_stream_ops *w, int interval);
+
+ static int sGetMinUndequeuedBufferCount(const struct preview_stream_ops *w, int *count);
+
+ // convert conventional HAL status to HIDL Status
+ static Status getHidlStatus(const int&);
+ static status_t getStatusT(const Status& s);
+
+ Status initStatus() const;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H
diff --git a/camera/device/1.0/types.hal b/camera/device/1.0/types.hal
new file mode 100644
index 0000000..b32c938
--- /dev/null
+++ b/camera/device/1.0/types.hal
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2016 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.camera.device@1.0;
+
+enum CameraFacing : uint32_t {
+ /** The facing of the camera is opposite to that of the screen. */
+ BACK = 0,
+ /** The facing of the camera is the same as that of the screen. */
+ FRONT = 1,
+ /**
+ * The facing of the camera is not fixed relative to the screen.
+ * The cameras with this facing are external cameras, e.g. USB cameras.
+ */
+ EXTERNAL = 2
+};
+
+/**
+ * Basic information about a camera device, always accessible via
+ * ICameraDevice::getCameraInfo().
+ */
+struct CameraInfo {
+ /**
+ * The direction that this device faces.
+ */
+ CameraFacing facing;
+
+ /**
+ * The orientation of the camera image. The value is the angle that the
+ * camera image needs to be rotated clockwise so it shows correctly on the
+ * display in its natural orientation. It must be 0, 90, 180, or 270.
+ *
+ * For example, suppose a device has a naturally tall screen. The
+ * back-facing camera sensor is mounted in landscape. You are looking at the
+ * screen. If the top side of the camera sensor is aligned with the right
+ * edge of the screen in natural orientation, the value must be 90. If the
+ * top side of a front-facing camera sensor is aligned with the right of the
+ * screen, the value must be 270.
+ *
+ * An external camera device must leave this set to 0.
+ *
+ */
+ uint32_t orientation;
+
+};
+
+/**
+ * Message types for ICameraDevice@1.0::enableMsgType()/disableMsgType()
+ *
+ * A set of bit masks for specifying how the received preview frames are
+ * handled before the previewCallback() call.
+ *
+ * The least significant 3 bits of an "int" value are used for this purpose:
+ *
+ * ..... 0 0 0
+ * ^ ^ ^
+ * | | |---------> determine whether the callback is enabled or not
+ * | |-----------> determine whether the callback is one-shot or not
+ * |-------------> determine whether the frame is copied out or not
+ *
+ * WARNING: When a frame is sent directly without copying, it is the frame
+ * receiver's responsiblity to make sure that the frame data won't get
+ * corrupted by subsequent preview frames filled by the camera. This flag is
+ * recommended only when copying out data brings significant performance price
+ * and the handling/processing of the received frame data is always faster than
+ * the preview frame rate so that data corruption won't occur.
+ *
+ * For instance,
+ * 1. 0x00 disables the callback. In this case, copy out and one shot bits
+ * are ignored.
+ * 2. 0x01 enables a callback without copying out the received frames. A
+ * typical use case is the Camcorder application to avoid making costly
+ * frame copies.
+ * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
+ * use case is the Camera application.
+ * 4. 0x07 is enabling a callback with frame copied out only once. A typical
+ * use case is the Barcode scanner application.
+ */
+enum FrameCallbackFlag : uint32_t {
+ ENABLE_MASK = 0x01,
+ ONE_SHOT_MASK = 0x02,
+ COPY_OUT_MASK = 0x04,
+ /** Typical use cases */
+ NOOP = 0x00,
+ CAMCORDER = 0x01,
+ CAMERA = 0x05,
+ BARCODE_SCANNER = 0x07
+};
+
+typedef bitfield<FrameCallbackFlag> FrameCallbackFlags;
+
+/**
+ * Subset of commands in /system/core/include/system/camera.h relevant for
+ * ICameraDevice@1.0::sendCommand()
+ */
+enum CommandType : uint32_t {
+ START_SMOOTH_ZOOM = 1,
+ STOP_SMOOTH_ZOOM = 2,
+
+ /**
+ * Start the face detection. This must be called only after preview is
+ * started. The camera must notify the listener of CAMERA_MSG_FACE and the
+ * detected faces in the preview frame. The detected faces may be the same
+ * as the previous ones. Apps must call CAMERA_CMD_STOP_FACE_DETECTION to
+ * stop the face detection. This method is supported if CameraParameters
+ * KEY_MAX_NUM_HW_DETECTED_FACES or KEY_MAX_NUM_SW_DETECTED_FACES is bigger
+ * than 0. Hardware and software face detection must not be running at the
+ * same time. If the face detection has started, apps must not send this
+ * again.
+ *
+ * In hardware face detection mode, CameraParameters KEY_WHITE_BALANCE,
+ * KEY_FOCUS_AREAS and KEY_METERING_AREAS have no effect.
+ *
+ * arg1 is the face detection type. It can be CAMERA_FACE_DETECTION_HW or
+ * CAMERA_FACE_DETECTION_SW. If the type of face detection requested is not
+ * supported, the HAL must return BAD_VALUE.
+ */
+ START_FACE_DETECTION = 6,
+
+ /**
+ * Stop the face detection.
+ */
+ STOP_FACE_DETECTION = 7,
+
+ /**
+ * Enable/disable focus move callback (CAMERA_MSG_FOCUS_MOVE). Passing
+ * arg1 = 0 must disable, while passing arg1 = 1 must enable the callback.
+ */
+ ENABLE_FOCUS_MOVE_MSG = 8,
+
+ /**
+ * Configure an explicit format to use for video recording metadata mode.
+ * This can be used to switch the format from the
+ * default IMPLEMENTATION_DEFINED gralloc format to some other
+ * device-supported format, and the default dataspace from the BT_709 color
+ * space to some other device-supported dataspace. arg1 is the HAL pixel
+ * format, and arg2 is the HAL dataSpace. This command returns
+ * INVALID_OPERATION error if it is sent after video recording is started,
+ * or the command is not supported at all.
+ *
+ * If the gralloc format is set to a format other than
+ * IMPLEMENTATION_DEFINED, then HALv3 devices must use gralloc usage flags
+ * of SW_READ_OFTEN.
+ */
+ SET_VIDEO_FORMAT = 11
+};
+
+/**
+ * Message types for ICameraDevice1Callback::notifyCallback()
+ */
+enum NotifyCallbackMsg : uint32_t {
+ ERROR = 0x0001,
+ SHUTTER = 0x0002,
+ FOCUS = 0x0004,
+ ZOOM = 0x0008,
+ // Notify on autofocus start and stop. This is useful in continuous
+ // autofocus - FOCUS_MODE_CONTINUOUS_VIDEO and FOCUS_MODE_CONTINUOUS_PICTURE.
+ FOCUS_MOVE = 0x0800
+};
+
+/**
+ * Message types for ICameraDevice1Callback::dataCallback() and
+ * ICameraDevice1Callback::dataCallbackTimestamp()
+ */
+enum DataCallbackMsg : uint32_t {
+ PREVIEW_FRAME = 0x0010,
+ VIDEO_FRAME = 0x0020,
+ POSTVIEW_FRAME = 0x0040,
+ RAW_IMAGE = 0x0080,
+ COMPRESSED_IMAGE = 0x0100,
+ RAW_IMAGE_NOTIFY = 0x0200,
+ // Preview frame metadata. This can be combined with
+ // CAMERA_MSG_PREVIEW_FRAME in dataCallback. For example, the apps can
+ // request FRAME and METADATA. Or the apps can request only FRAME or only
+ // METADATA.
+ PREVIEW_METADATA = 0x0400
+};
+
+/**
+ * Information for a single detected face.
+ */
+ struct CameraFace {
+ /**
+ * Bounds of the face [left, top, right, bottom]. (-1000, -1000) represents
+ * the top-left of the camera field of view, and (1000, 1000) represents the
+ * bottom-right of the field of view. The width and height cannot be 0 or
+ * negative. This is supported by both hardware and software face detection.
+ *
+ * The direction is relative to the sensor orientation, that is, what the
+ * sensor sees. The direction is not affected by the rotation or mirroring
+ * of CAMERA_CMD_SET_DISPLAY_ORIENTATION.
+ */
+ int32_t[4] rect;
+
+ /**
+ * The confidence level of the face. The range is 1 to 100. 100 is the
+ * highest confidence. This is supported by both hardware and software
+ * face detection.
+ */
+ int32_t score;
+
+ /**
+ * An unique id per face while the face is visible to the tracker. If
+ * the face leaves the field-of-view and comes back, it will get a new
+ * id. If the value is 0, id is not supported.
+ */
+ int32_t id;
+
+ /**
+ * The coordinates of the center of the left eye. The range is -1000 to
+ * 1000. -2000, -2000 if this is not supported.
+ */
+ int32_t[2] leftEye;
+
+ /**
+ * The coordinates of the center of the right eye. The range is -1000 to
+ * 1000. -2000, -2000 if this is not supported.
+ */
+ int32_t[2] rightEye;
+
+ /**
+ * The coordinates of the center of the mouth. The range is -1000 to 1000.
+ * -2000, -2000 if this is not supported.
+ */
+ int32_t[2] mouth;
+
+};
+
+/**
+ * The metadata of the frame data, such as face detection result.
+ */
+struct CameraFrameMetadata {
+ /**
+ * A vector of the detected faces.
+ */
+ vec<CameraFace> faces;
+};
+
+/*
+ * A simple integer handle to use to reference a particular memory buffer
+ * between the HAL and the framework.
+ */
+typedef uint32_t MemoryId;
diff --git a/camera/device/3.2/Android.bp b/camera/device/3.2/Android.bp
new file mode 100644
index 0000000..a3ac721
--- /dev/null
+++ b/camera/device/3.2/Android.bp
@@ -0,0 +1,82 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.camera.device@3.2_hal",
+ srcs: [
+ "types.hal",
+ "ICameraDevice.hal",
+ "ICameraDeviceCallback.hal",
+ "ICameraDeviceSession.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.device@3.2_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.2",
+ srcs: [
+ ":android.hardware.camera.device@3.2_hal",
+ ],
+ out: [
+ "android/hardware/camera/device/3.2/types.cpp",
+ "android/hardware/camera/device/3.2/CameraDeviceAll.cpp",
+ "android/hardware/camera/device/3.2/CameraDeviceCallbackAll.cpp",
+ "android/hardware/camera/device/3.2/CameraDeviceSessionAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.device@3.2_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.2",
+ srcs: [
+ ":android.hardware.camera.device@3.2_hal",
+ ],
+ out: [
+ "android/hardware/camera/device/3.2/types.h",
+ "android/hardware/camera/device/3.2/ICameraDevice.h",
+ "android/hardware/camera/device/3.2/IHwCameraDevice.h",
+ "android/hardware/camera/device/3.2/BnHwCameraDevice.h",
+ "android/hardware/camera/device/3.2/BpHwCameraDevice.h",
+ "android/hardware/camera/device/3.2/BsCameraDevice.h",
+ "android/hardware/camera/device/3.2/ICameraDeviceCallback.h",
+ "android/hardware/camera/device/3.2/IHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/3.2/BnHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/3.2/BpHwCameraDeviceCallback.h",
+ "android/hardware/camera/device/3.2/BsCameraDeviceCallback.h",
+ "android/hardware/camera/device/3.2/ICameraDeviceSession.h",
+ "android/hardware/camera/device/3.2/IHwCameraDeviceSession.h",
+ "android/hardware/camera/device/3.2/BnHwCameraDeviceSession.h",
+ "android/hardware/camera/device/3.2/BpHwCameraDeviceSession.h",
+ "android/hardware/camera/device/3.2/BsCameraDeviceSession.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.device@3.2",
+ generated_sources: ["android.hardware.camera.device@3.2_genc++"],
+ generated_headers: ["android.hardware.camera.device@3.2_genc++_headers"],
+ export_generated_headers: ["android.hardware.camera.device@3.2_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/camera/device/3.2/ICameraDevice.hal b/camera/device/3.2/ICameraDevice.hal
new file mode 100644
index 0000000..6e66bf3
--- /dev/null
+++ b/camera/device/3.2/ICameraDevice.hal
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 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.camera.device@3.2;
+
+import android.hardware.camera.common@1.0::types;
+import ICameraDeviceSession;
+import ICameraDeviceCallback;
+
+/**
+ * Camera device HAL, first modern version
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API at LIMITED or better hardware level.
+ *
+ */
+interface ICameraDevice {
+
+ /**
+ * Get camera device resource cost information.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On success
+ * INTERNAL_ERROR:
+ * An unexpected internal camera HAL error occurred, and the
+ * resource cost is not available.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ * @return resourceCost
+ * The resources required to open this camera device, or unspecified
+ * values if status is not OK.
+ */
+ getResourceCost() generates (Status status, CameraResourceCost resourceCost);
+
+ /**
+ * getCameraCharacteristics:
+ *
+ * Return the static camera information for this camera device. This
+ * information may not change between consecutive calls.
+ *
+ * When an external camera is disconnected, its camera id becomes
+ * invalid. Calling this method with this invalid camera id must result in
+ * ILLEGAL_ARGUMENT; this may happen even before the device status callback
+ * is invoked by the HAL.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful open of the camera device.
+ * INTERNAL_ERROR:
+ * The camera device cannot be opened due to an internal
+ * error.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ *
+ * @return cameraCharacteristics
+ * The static metadata for this camera device, or an empty metadata
+ * structure if status is not OK.
+ *
+ */
+ getCameraCharacteristics() generates
+ (Status status, CameraMetadata cameraCharacteristics);
+
+ /**
+ * setTorchMode:
+ *
+ * Turn on or off the torch mode of the flash unit associated with this
+ * camera device. If the operation is successful, HAL must notify the
+ * framework torch state by invoking
+ * ICameraProviderCallback::torchModeStatusChange() with the new state.
+ *
+ * An active camera session has a higher priority accessing the flash
+ * unit. When there are any resource conflicts, such as when open() is
+ * called to fully activate a camera device, the provider must notify the
+ * framework through ICameraProviderCallback::torchModeStatusChange() that
+ * the torch mode has been turned off and the torch mode state has become
+ * TORCH_MODE_STATUS_NOT_AVAILABLE. When resources to turn on torch mode
+ * become available again, the provider must notify the framework through
+ * ICameraProviderCallback::torchModeStatusChange() that the torch mode
+ * state has become TORCH_MODE_STATUS_AVAILABLE_OFF for set_torch_mode() to
+ * be called.
+ *
+ * When the client calls setTorchMode() to turn on the torch mode of a flash
+ * unit, if the HAL cannot keep multiple torch modes on simultaneously, the
+ * HAL must turn off the torch mode(s) that were turned on by previous
+ * setTorchMode() calls and notify the framework that the torch mode state
+ * of those flash unit(s) has become TORCH_MODE_STATUS_AVAILABLE_OFF.
+ *
+ * @param torchMode The new mode to set the device flash unit to.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful change to the torch state
+ * INTERNAL_ERROR:
+ * The flash unit cannot be operated due to an unexpected internal
+ * error.
+ * ILLEGAL_ARGUMENT:
+ * The camera ID is unknown.
+ * CAMERA_IN_USE:
+ * This camera device has been opened, so the torch cannot be
+ * controlled until it is closed.
+ * MAX_CAMERAS_IN_USE:
+ * Due to other camera devices being open, or due to other
+ * resource constraints, the torch cannot be controlled currently.
+ * METHOD_NOT_SUPPORTED:
+ * This provider does not support direct operation of flashlight
+ * torch mode. The framework must open the camera device and turn
+ * the torch on through the device interface.
+ * OPERATION_NOT_SUPPORTED:
+ * This camera device does not have a flash unit. This can
+ * be returned if and only if android.flash.info.available is
+ * false.
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ *
+ */
+ setTorchMode(TorchMode mode) generates (Status status);
+
+ /**
+ * open:
+ *
+ * Power on and initialize this camera device for active use, returning a
+ * session handle for active operations.
+ *
+ * @param callback Interface to invoke by the HAL for device asynchronous
+ * events.
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful open of the camera device.
+ * INTERNAL_ERROR:
+ * The camera device cannot be opened due to an internal
+ * error.
+ * ILLEGAL_ARGUMENT:
+ * The callbacks handle is invalid (for example, it is null).
+ * CAMERA_IN_USE:
+ * This camera device is already open.
+ * MAX_CAMERAS_IN_USE:
+ * The maximal number of camera devices that can be
+ * opened concurrently were opened already.
+ * CAMERA_DISCONNECTED:
+ * This external camera device has been disconnected, and is no
+ * longer available. This interface is now stale, and a new instance
+ * must be acquired if the device is reconnected. All subsequent
+ * calls on this interface must return CAMERA_DISCONNECTED.
+ * @return cameraDevice The interface to the newly-opened camera session,
+ * or null if status is not OK.
+ */
+ open(ICameraDeviceCallback callback) generates
+ (Status status, ICameraDeviceSession session);
+
+ /**
+ * dumpState:
+ *
+ * Print out debugging state for the camera device. This may be called by
+ * the framework when the camera service is asked for a debug dump, which
+ * happens when using the dumpsys tool, or when capturing a bugreport.
+ *
+ * The passed-in file descriptor can be used to write debugging text using
+ * dprintf() or write(). The text must be in ASCII encoding only.
+ *
+ * In case this camera device has been disconnected, the dump must not fail,
+ * but may simply print out 'Device disconnected' or equivalent.
+ *
+ * Performance requirements:
+ *
+ * This must be a non-blocking call. The HAL should return from this call
+ * in 1ms, must return from this call in 10ms. This call must avoid
+ * deadlocks, as it may be called at any point during camera operation.
+ * Any synchronization primitives used (such as mutex locks or semaphores)
+ * must be acquired with a timeout.
+ */
+ dumpState(handle fd);
+
+};
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..bf51da2
--- /dev/null
+++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 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.camera.device@3.2;
+
+import android.hardware.camera.common@1.0::types;
+
+/**
+ *
+ * Callback methods for the HAL to call into the framework.
+ *
+ * These methods are used to return metadata and image buffers for a completed
+ * or failed captures, and to notify the framework of asynchronous events such
+ * as errors.
+ *
+ * The framework must not call back into the HAL from within these callbacks,
+ * and these calls must not block for extended periods.
+ *
+ */
+interface ICameraDeviceCallback {
+
+ /**
+ * processCaptureResult:
+ *
+ * Send results from one or more completed or partially completed captures
+ * to the framework.
+ * processCaptureResult() may be invoked multiple times by the HAL in
+ * response to a single capture request. This allows, for example, the
+ * metadata and low-resolution buffers to be returned in one call, and
+ * post-processed JPEG buffers in a later call, once it is available. Each
+ * call must include the frame number of the request it is returning
+ * metadata or buffers for.
+ *
+ * A component (buffer or metadata) of the complete result may only be
+ * included in one process_capture_result call. A buffer for each stream,
+ * and the result metadata, must be returned by the HAL for each request in
+ * one of the processCaptureResult calls, even in case of errors producing
+ * some of the output. A call to processCaptureResult() with neither
+ * output buffers or result metadata is not allowed.
+ *
+ * The order of returning metadata and buffers for a single result does not
+ * matter, but buffers for a given stream must be returned in FIFO order. So
+ * the buffer for request 5 for stream A must always be returned before the
+ * buffer for request 6 for stream A. This also applies to the result
+ * metadata; the metadata for request 5 must be returned before the metadata
+ * for request 6.
+ *
+ * However, different streams are independent of each other, so it is
+ * acceptable and expected that the buffer for request 5 for stream A may be
+ * returned after the buffer for request 6 for stream B is. And it is
+ * acceptable that the result metadata for request 6 for stream B is
+ * returned before the buffer for request 5 for stream A is. If multiple
+ * capture results are included in a single call, camera framework must
+ * process results sequentially from lower index to higher index, as if
+ * these results were sent to camera framework one by one, from lower index
+ * to higher index.
+ *
+ * The HAL retains ownership of result structure, which only needs to be
+ * valid to access during this call.
+ *
+ * The output buffers do not need to be filled yet; the framework must wait
+ * on the stream buffer release sync fence before reading the buffer
+ * data. Therefore, this method should be called by the HAL as soon as
+ * possible, even if some or all of the output buffers are still in
+ * being filled. The HAL must include valid release sync fences into each
+ * output_buffers stream buffer entry, or -1 if that stream buffer is
+ * already filled.
+ *
+ * If the result buffer cannot be constructed for a request, the HAL must
+ * return an empty metadata buffer, but still provide the output buffers and
+ * their sync fences. In addition, notify() must be called with an
+ * ERROR_RESULT message.
+ *
+ * If an output buffer cannot be filled, its status field must be set to
+ * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER
+ * message.
+ *
+ * If the entire capture has failed, then this method still needs to be
+ * called to return the output buffers to the framework. All the buffer
+ * statuses must be STATUS_ERROR, and the result metadata must be an
+ * empty buffer. In addition, notify() must be called with a ERROR_REQUEST
+ * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages
+ * must not be sent.
+ *
+ * Performance requirements:
+ *
+ * This is a non-blocking call. The framework must handle each CaptureResult
+ * within 5ms.
+ *
+ * The pipeline latency (see S7 for definition) should be less than or equal to
+ * 4 frame intervals, and must be less than or equal to 8 frame intervals.
+ *
+ */
+ processCaptureResult(vec<CaptureResult> results);
+
+ /**
+ * notify:
+ *
+ * Asynchronous notification callback from the HAL, fired for various
+ * reasons. Only for information independent of frame capture, or that
+ * require specific timing. Multiple messages may be sent in one call; a
+ * message with a higher index must be considered to have occurred after a
+ * message with a lower index.
+ *
+ * Multiple threads may call notify() simultaneously.
+ *
+ * Buffers delivered to the framework must not be dispatched to the
+ * application layer until a start of exposure timestamp (or input image's
+ * start of exposure timestamp for a reprocess request) has been received
+ * via a SHUTTER notify() call. It is highly recommended to dispatch this
+ * call as early as possible.
+ *
+ * ------------------------------------------------------------------------
+ * Performance requirements:
+ *
+ * This is a non-blocking call. The framework must handle each message in 5ms.
+ */
+ notify(vec<NotifyMsg> msgs);
+
+};
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
new file mode 100644
index 0000000..e186c8d
--- /dev/null
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2016 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.camera.device@3.2;
+
+import android.hardware.camera.common@1.0::types;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ *
+ */
+interface ICameraDeviceSession {
+
+ /**
+ * constructDefaultRequestSettings:
+ *
+ * Create capture settings for standard camera use cases.
+ *
+ * The device must return a settings buffer that is configured to meet the
+ * requested use case, which must be one of the CAMERA3_TEMPLATE_*
+ * enums. All request control fields must be included.
+ *
+ * Performance requirements:
+ *
+ * This must be a non-blocking call. The HAL should return from this call
+ * in 1ms, and must return from this call in 5ms.
+ *
+ * Return values:
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful construction of default settings.
+ * INTERNAL_ERROR:
+ * An unexpected internal error occurred, and the default settings
+ * are not available.
+ * ILLEGAL_ARGUMENT:
+ * The camera HAL does not support the input template type
+ * CAMERA_DISCONNECTED:
+ * An external camera device has been disconnected, and is no longer
+ * available. This camera device interface is now stale, and a new
+ * instance must be acquired if the device is reconnected. All
+ * subsequent calls on this interface must return
+ * CAMERA_DISCONNECTED.
+ * @return template The default capture request settings for the requested
+ * use case, or an empty metadata structure if status is not OK.
+ *
+ */
+ constructDefaultRequestSettings(RequestTemplate type) generates
+ (Status status, CameraMetadata requestTemplate);
+
+ /**
+ * configureStreams:
+ *
+ * Reset the HAL camera device processing pipeline and set up new input and
+ * output streams. This call replaces any existing stream configuration with
+ * the streams defined in the streamList. This method must be called at
+ * least once before a request is submitted with processCaptureRequest().
+ *
+ * The streamList must contain at least one output-capable stream, and may
+ * not contain more than one input-capable stream.
+ *
+ * The streamList may contain streams that are also in the currently-active
+ * set of streams (from the previous call to configureStreams()). These
+ * streams must already have valid values for usage, maxBuffers, and the
+ * private pointer.
+ *
+ * If the HAL needs to change the stream configuration for an existing
+ * stream due to the new configuration, it may rewrite the values of usage
+ * and/or maxBuffers during the configure call.
+ *
+ * The framework must detect such a change, and may then reallocate the
+ * stream buffers before using buffers from that stream in a request.
+ *
+ * If a currently-active stream is not included in streamList, the HAL may
+ * safely remove any references to that stream. It must not be reused in a
+ * later configureStreams() call by the framework, and all the gralloc
+ * buffers for it must be freed after the configureStreams() call returns.
+ *
+ * If the stream is new, the maxBuffer field of the stream structure must be
+ * set to 0. The usage must be set to the consumer usage flags. The HAL
+ * device must set these fields in the configureStreams() return values.
+ * These fields are then used by the framework and the platform gralloc
+ * module to allocate the gralloc buffers for each stream.
+ *
+ * Newly allocated buffers may be included in a capture request at any time
+ * by the framework. Once a gralloc buffer is returned to the framework
+ * with processCaptureResult (and its respective releaseFence has been
+ * signaled) the framework may free or reuse it at any time.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Preconditions:
+ *
+ * The framework must only call this method when no captures are being
+ * processed. That is, all results have been returned to the framework, and
+ * all in-flight input and output buffers have been returned and their
+ * release sync fences have been signaled by the HAL. The framework must not
+ * submit new requests for capture while the configureStreams() call is
+ * underway.
+ *
+ * Postconditions:
+ *
+ * The HAL device must configure itself to provide maximum possible output
+ * frame rate given the sizes and formats of the output streams, as
+ * documented in the camera device's static metadata.
+ *
+ * Performance requirements:
+ *
+ * This call is expected to be heavyweight and possibly take several hundred
+ * milliseconds to complete, since it may require resetting and
+ * reconfiguring the image sensor and the camera processing pipeline.
+ * Nevertheless, the HAL device should attempt to minimize the
+ * reconfiguration delay to minimize the user-visible pauses during
+ * application operational mode changes (such as switching from still
+ * capture to video recording).
+ *
+ * The HAL should return from this call in 500ms, and must return from this
+ * call in 1000ms.
+ *
+ * @return Status Status code for the operation, one of:
+ * OK:
+ * On successful stream configuration.
+ * INTERNAL_ERROR:
+ * If there has been a fatal error and the device is no longer
+ * operational. Only close() can be called successfully by the
+ * framework after this error is returned.
+ * ILLEGAL_ARGUMENT:
+ * If the requested stream configuration is invalid. Some examples
+ * of invalid stream configurations include:
+ * - Including more than 1 INPUT stream
+ * - Not including any OUTPUT streams
+ * - Including streams with unsupported formats, or an unsupported
+ * size for that format.
+ * - Including too many output streams of a certain format.
+ * - Unsupported rotation configuration
+ * - Stream sizes/formats don't satisfy the
+ * camera3_stream_configuration_t->operation_mode requirements
+ * for non-NORMAL mode, or the requested operation_mode is not
+ * supported by the HAL.
+ * - Unsupported usage flag
+ * The camera service cannot filter out all possible illegal stream
+ * configurations, since some devices may support more simultaneous
+ * streams or larger stream resolutions than the minimum required
+ * for a given camera device hardware level. The HAL must return an
+ * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+ * ready to accept a future valid stream configuration in a later
+ * configureStreams call.
+ * @return finalConfiguration The stream parameters desired by the HAL for
+ * each stream, including maximum buffers, the usage flags, and the
+ * override format.
+ *
+ */
+ configureStreams(StreamConfiguration requestedConfiguration)
+ generates (Status status,
+ HalStreamConfiguration halConfiguration);
+
+ /**
+ * processCaptureRequest:
+ *
+ * Send a list of capture requests to the HAL. The HAL must not return from
+ * this call until it is ready to accept the next set of requests to
+ * process. Only one call to processCaptureRequest() must be made at a time
+ * by the framework, and the calls must all be from the same thread. The
+ * next call to processCaptureRequest() must be made as soon as a new
+ * request and its associated buffers are available. In a normal preview
+ * scenario, this means the function is generally called again by the
+ * framework almost instantly. If more than one request is provided by the
+ * client, the HAL must process the requests in order of lowest index to
+ * highest index.
+ *
+ * The actual request processing is asynchronous, with the results of
+ * capture being returned by the HAL through the processCaptureResult()
+ * call. This call requires the result metadata to be available, but output
+ * buffers may simply provide sync fences to wait on. Multiple requests are
+ * expected to be in flight at once, to maintain full output frame rate.
+ *
+ * The framework retains ownership of the request structure. It is only
+ * guaranteed to be valid during this call. The HAL device must make copies
+ * of the information it needs to retain for the capture processing. The HAL
+ * is responsible for waiting on and closing the buffers' fences and
+ * returning the buffer handles to the framework.
+ *
+ * The HAL must write the file descriptor for the input buffer's release
+ * sync fence into input_buffer->release_fence, if input_buffer is not
+ * valid. If the HAL returns -1 for the input buffer release sync fence, the
+ * framework is free to immediately reuse the input buffer. Otherwise, the
+ * framework must wait on the sync fence before refilling and reusing the
+ * input buffer.
+ *
+ * The input/output buffers provided by the framework in each request
+ * may be brand new (having never before seen by the HAL).
+ *
+ * ------------------------------------------------------------------------
+ * Performance considerations:
+ *
+ * Handling a new buffer should be extremely lightweight and there must be
+ * no frame rate degradation or frame jitter introduced.
+ *
+ * This call must return fast enough to ensure that the requested frame
+ * rate can be sustained, especially for streaming cases (post-processing
+ * quality settings set to FAST). The HAL should return this call in 1
+ * frame interval, and must return from this call in 4 frame intervals.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful start to processing the capture request
+ * ILLEGAL_ARGUMENT:
+ * If the input is malformed (the settings are empty when not
+ * allowed, there are 0 output buffers, etc) and capture processing
+ * cannot start. Failures during request processing must be
+ * handled by calling ICameraDeviceCallback::notify(). In case of
+ * this error, the framework retains responsibility for the
+ * stream buffers' fences and the buffer handles; the HAL must not
+ * close the fences or return these buffers with
+ * ICameraDeviceCallback::processCaptureResult().
+ * INTERNAL_ERROR:
+ * If the camera device has encountered a serious error. After this
+ * error is returned, only the close() method can be successfully
+ * called by the framework.
+ * @return numRequestProcessed Number of requests successfully processed by
+ * camera HAL. When status is OK, this must be equal to the size of
+ * requests. When the call fails, this number is the number of requests
+ * that HAL processed successfully before HAL runs into an error.
+ *
+ */
+ processCaptureRequest(vec<CaptureRequest> requests)
+ generates (Status status, uint32_t numRequestProcessed);
+
+ /**
+ * flush:
+ *
+ * Flush all currently in-process captures and all buffers in the pipeline
+ * on the given device. Generally, this method is used to dump all state as
+ * quickly as possible in order to prepare for a configure_streams() call.
+ *
+ * No buffers are required to be successfully returned, so every buffer
+ * held at the time of flush() (whether successfully filled or not) may be
+ * returned with CAMERA3_BUFFER_STATUS_ERROR. Note the HAL is still allowed
+ * to return valid (CAMERA3_BUFFER_STATUS_OK) buffers during this call,
+ * provided they are successfully filled.
+ *
+ * All requests currently in the HAL are expected to be returned as soon as
+ * possible. Not-in-process requests must return errors immediately. Any
+ * interruptible hardware blocks must be stopped, and any uninterruptible
+ * blocks must be waited on.
+ *
+ * flush() may be called concurrently to processCaptureRequest(), with the
+ * expectation that processCaptureRequest returns quickly and the
+ * request submitted in that processCaptureRequest call is treated like
+ * all other in-flight requests. Due to concurrency issues, it is possible
+ * that from the HAL's point of view, a processCaptureRequest() call may
+ * be started after flush has been invoked but has not returned yet. If such
+ * a call happens before flush() returns, the HAL must treat the new
+ * capture request like other in-flight pending requests (see #4 below).
+ *
+ * More specifically, the HAL must follow below requirements for various
+ * cases:
+ *
+ * 1. For captures that are too late for the HAL to cancel/stop, and must be
+ * completed normally by the HAL; i.e. the HAL can send shutter/notify
+ * and processCaptureResult and buffers as normal.
+ *
+ * 2. For pending requests that have not done any processing, the HAL must
+ * call notify CAMERA3_MSG_ERROR_REQUEST, and return all the output
+ * buffers with processCaptureResult in the error state
+ * (CAMERA3_BUFFER_STATUS_ERROR). The HAL must not place the release
+ * fence into an error state, instead, the release fences must be set to
+ * the acquire fences passed by the framework, or -1 if they have been
+ * waited on by the HAL already. This is also the path to follow for any
+ * captures for which the HAL already called notify() with
+ * CAMERA3_MSG_SHUTTER but won't be producing any metadata/valid buffers
+ * for. After CAMERA3_MSG_ERROR_REQUEST, for a given frame, only
+ * processCaptureResults with buffers in CAMERA3_BUFFER_STATUS_ERROR
+ * are allowed. No further notifys or processCaptureResult with
+ * non-empty metadata is allowed.
+ *
+ * 3. For partially completed pending requests that do not have all the
+ * output buffers or perhaps missing metadata, the HAL must follow
+ * below:
+ *
+ * 3.1. Call notify with CAMERA3_MSG_ERROR_RESULT if some of the expected
+ * result metadata (i.e. one or more partial metadata) won't be
+ * available for the capture.
+ *
+ * 3.2. Call notify with CAMERA3_MSG_ERROR_BUFFER for every buffer that
+ * won't be produced for the capture.
+ *
+ * 3.3. Call notify with CAMERA3_MSG_SHUTTER with the capture timestamp
+ * before any buffers/metadata are returned with
+ * processCaptureResult.
+ *
+ * 3.4. For captures that will produce some results, the HAL must not
+ * call CAMERA3_MSG_ERROR_REQUEST, since that indicates complete
+ * failure.
+ *
+ * 3.5. Valid buffers/metadata must be passed to the framework as
+ * normal.
+ *
+ * 3.6. Failed buffers must be returned to the framework as described
+ * for case 2. But failed buffers do not have to follow the strict
+ * ordering valid buffers do, and may be out-of-order with respect
+ * to valid buffers. For example, if buffers A, B, C, D, E are sent,
+ * D and E are failed, then A, E, B, D, C is an acceptable return
+ * order.
+ *
+ * 3.7. For fully-missing metadata, calling CAMERA3_MSG_ERROR_RESULT is
+ * sufficient, no need to call processCaptureResult with empty
+ * metadata or equivalent.
+ *
+ * 4. If a flush() is invoked while a processCaptureRequest() invocation
+ * is active, that process call must return as soon as possible. In
+ * addition, if a processCaptureRequest() call is made after flush()
+ * has been invoked but before flush() has returned, the capture request
+ * provided by the late processCaptureRequest call must be treated
+ * like a pending request in case #2 above.
+ *
+ * flush() must only return when there are no more outstanding buffers or
+ * requests left in the HAL. The framework may call configure_streams (as
+ * the HAL state is now quiesced) or may issue new requests.
+ *
+ * Note that it's sufficient to only support fully-succeeded and
+ * fully-failed result cases. However, it is highly desirable to support
+ * the partial failure cases as well, as it could help improve the flush
+ * call overall performance.
+ *
+ * Performance requirements:
+ *
+ * The HAL should return from this call in 100ms, and must return from this
+ * call in 1000ms. And this call must not be blocked longer than pipeline
+ * latency (see S7 for definition).
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a successful flush of the camera HAL.
+ * INTERNAL_ERROR:
+ * If the camera device has encountered a serious error. After this
+ * error is returned, only the close() method can be successfully
+ * called by the framework.
+ */
+ flush() generates (Status status);
+
+ /**
+ * close:
+ *
+ * Shut down the camera device.
+ *
+ * After this call, all calls to this session instance must return
+ * INTERNAL_ERROR.
+ *
+ * This method must always succeed, even if the device has encountered a
+ * serious error.
+ */
+ close();
+};
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
new file mode 100644
index 0000000..e0dc5ff
--- /dev/null
+++ b/camera/device/3.2/default/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "camera.device@3.2-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ srcs: ["CameraDevice.cpp",
+ "CameraDeviceSession.cpp",
+ "convert.cpp"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.provider@2.4",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper"
+ ],
+ export_include_dirs: ["."]
+}
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
new file mode 100644
index 0000000..a742335
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "CamDev@3.2-impl"
+#include <utils/Log.h>
+
+#include <utils/Vector.h>
+#include <utils/Trace.h>
+#include "CameraDevice_3_2.h"
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::Status;
+
+CameraDevice::CameraDevice(
+ sp<CameraModule> module, const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+ mModule(module),
+ mCameraId(cameraId),
+ mDisconnected(false),
+ mCameraDeviceNames(cameraDeviceNames) {
+ mCameraIdInt = atoi(mCameraId.c_str());
+ // Should not reach here as provider also validate ID
+ if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+ ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+
+ mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("%s: Camera id %s does not support HAL3.2+",
+ __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+}
+
+CameraDevice::~CameraDevice() {}
+
+Status CameraDevice::initStatus() const {
+ Mutex::Autolock _l(mLock);
+ Status status = Status::OK;
+ if (mInitFail) {
+ status = Status::INTERNAL_ERROR;
+ } else if (mDisconnected) {
+ status = Status::CAMERA_DISCONNECTED;
+ }
+ return status;
+}
+
+void CameraDevice::setConnectionStatus(bool connected) {
+ Mutex::Autolock _l(mLock);
+ mDisconnected = !connected;
+ if (mSession == nullptr) {
+ return;
+ }
+ sp<CameraDeviceSession> session = mSession.promote();
+ if (session == nullptr) {
+ return;
+ }
+ // Only notify active session disconnect events.
+ // Users will need to re-open camera after disconnect event
+ if (!connected) {
+ session->disconnect();
+ }
+ return;
+}
+
+Status CameraDevice::getHidlStatus(int status) {
+ switch (status) {
+ case 0: return Status::OK;
+ case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED;
+ case -EBUSY : return Status::CAMERA_IN_USE;
+ case -EUSERS: return Status::MAX_CAMERAS_IN_USE;
+ case -ENODEV: return Status::INTERNAL_ERROR;
+ case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+ default:
+ ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+ return Status::INTERNAL_ERROR;
+ }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
+Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraResourceCost resCost;
+ if (status == Status::OK) {
+ int cost = 100;
+ std::vector<std::string> conflicting_devices;
+ struct camera_info info;
+
+ // If using post-2.4 module version, query the cost + conflicting devices from the HAL
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ cost = info.resource_cost;
+ for (size_t i = 0; i < info.conflicting_devices_length; i++) {
+ std::string cameraId(info.conflicting_devices[i]);
+ for (const auto& pair : mCameraDeviceNames) {
+ if (cameraId == pair.first) {
+ conflicting_devices.push_back(pair.second);
+ }
+ }
+ }
+ } else {
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+
+ if (status == Status::OK) {
+ resCost.resourceCost = cost;
+ resCost.conflictingDevices.resize(conflicting_devices.size());
+ for (size_t i = 0; i < conflicting_devices.size(); i++) {
+ resCost.conflictingDevices[i] = conflicting_devices[i];
+ ALOGV("CamDevice %s is conflicting with camDevice %s",
+ mCameraId.c_str(), resCost.conflictingDevices[i].c_str());
+ }
+ }
+ }
+ _hidl_cb(status, resCost);
+ return Void();
+}
+
+Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraMetadata cameraCharacteristics;
+ if (status == Status::OK) {
+ //Module 2.1+ codepath.
+ struct camera_info info;
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ convertToHidl(info.static_camera_characteristics, &cameraCharacteristics);
+ } else {
+ ALOGE("%s: get camera info failed!", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ _hidl_cb(status, cameraCharacteristics);
+ return Void();
+}
+
+Return<Status> CameraDevice::setTorchMode(TorchMode mode) {
+ if (!mModule->isSetTorchModeSupported()) {
+ return Status::METHOD_NOT_SUPPORTED;
+ }
+
+ Status status = initStatus();
+ if (status == Status::OK) {
+ bool enable = (mode == TorchMode::ON) ? true : false;
+ status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable));
+ }
+ return status;
+}
+
+Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
+ Status status = initStatus();
+ sp<CameraDeviceSession> session = nullptr;
+
+ if (callback == nullptr) {
+ ALOGE("%s: cannot open camera %s. callback is null!",
+ __FUNCTION__, mCameraId.c_str());
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, session);
+ return Void();
+ }
+
+ if (status != Status::OK) {
+ // Provider will never pass initFailed device to client, so
+ // this must be a disconnected camera
+ ALOGE("%s: cannot open camera %s. camera is disconnected!",
+ __FUNCTION__, mCameraId.c_str());
+ _hidl_cb(Status::CAMERA_DISCONNECTED, session);
+ return Void();
+ } else {
+ mLock.lock();
+
+ ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt);
+ session = mSession.promote();
+ if (session != nullptr && !session->isClosed()) {
+ ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
+ mLock.unlock();
+ _hidl_cb(Status::CAMERA_IN_USE, nullptr);
+ return Void();
+ }
+
+ /** Open HAL device */
+ status_t res;
+ camera3_device_t *device;
+
+ ATRACE_BEGIN("camera3->open");
+ res = mModule->open(mCameraId.c_str(),
+ reinterpret_cast<hw_device_t**>(&device));
+ ATRACE_END();
+
+ if (res != OK) {
+ ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str());
+ mLock.unlock();
+ _hidl_cb(getHidlStatus(res), nullptr);
+ return Void();
+ }
+
+ /** Cross-check device version */
+ if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("%s: Could not open camera: "
+ "Camera device should be at least %x, reports %x instead",
+ __FUNCTION__,
+ CAMERA_DEVICE_API_VERSION_3_2,
+ device->common.version);
+ device->common.close(&device->common);
+ mLock.unlock();
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ struct camera_info info;
+ res = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (res != OK) {
+ ALOGE("%s: Could not open camera: getCameraInfo failed", __FUNCTION__);
+ device->common.close(&device->common);
+ mLock.unlock();
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ session = new CameraDeviceSession(
+ device, info.static_camera_characteristics, callback);
+ if (session == nullptr) {
+ ALOGE("%s: camera device session allocation failed", __FUNCTION__);
+ mLock.unlock();
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+ if (session->isInitFailed()) {
+ ALOGE("%s: camera device session init failed", __FUNCTION__);
+ session = nullptr;
+ mLock.unlock();
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+ mSession = session;
+ mLock.unlock();
+ }
+ _hidl_cb(status, session);
+ return Void();
+}
+
+Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) {
+ Mutex::Autolock _l(mLock);
+ if (handle.getNativeHandle() == nullptr) {
+ ALOGE("%s: handle must not be null", __FUNCTION__);
+ return Void();
+ }
+ if (handle->numFds != 1 || handle->numInts != 0) {
+ ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
+ __FUNCTION__, handle->numFds, handle->numInts);
+ return Void();
+ }
+ int fd = handle->data[0];
+ if (mSession == nullptr) {
+ dprintf(fd, "No active camera device session instance\n");
+ return Void();
+ }
+ sp<CameraDeviceSession> session = mSession.promote();
+ if (session == nullptr) {
+ dprintf(fd, "No active camera device session instance\n");
+ return Void();
+ }
+ // Call into active session to dump states
+ session->dumpState(handle);
+ return Void();
+}
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..fb1d1ff
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -0,0 +1,944 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "CamDevSession@3.2-impl"
+#include <android/log.h>
+
+#include <set>
+#include <utils/Trace.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+HandleImporter& CameraDeviceSession::sHandleImporter = HandleImporter::getInstance();
+const int CameraDeviceSession::ResultBatcher::NOT_BATCHED;
+
+CameraDeviceSession::CameraDeviceSession(
+ camera3_device_t* device,
+ const camera_metadata_t* deviceInfo,
+ const sp<ICameraDeviceCallback>& callback) :
+ camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
+ mDevice(device),
+ mResultBatcher(callback) {
+
+ mDeviceInfo = deviceInfo;
+ uint32_t numPartialResults = 1;
+ camera_metadata_entry partialResultsCount =
+ mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (partialResultsCount.count > 0) {
+ numPartialResults = partialResultsCount.data.i32[0];
+ }
+ mResultBatcher.setNumPartialResults(numPartialResults);
+
+ mInitFail = initialize();
+}
+
+bool CameraDeviceSession::initialize() {
+ /** Initialize device with callback functions */
+ ATRACE_BEGIN("camera3->initialize");
+ status_t res = mDevice->ops->initialize(mDevice, this);
+ ATRACE_END();
+
+ if (res != OK) {
+ ALOGE("%s: Unable to initialize HAL device: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ mDevice->common.close(&mDevice->common);
+ mClosed = true;
+ return true;
+ }
+ return false;
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+ if (!isClosed()) {
+ ALOGE("CameraDeviceSession deleted before close!");
+ close();
+ }
+}
+
+bool CameraDeviceSession::isClosed() {
+ Mutex::Autolock _l(mStateLock);
+ return mClosed;
+}
+
+Status CameraDeviceSession::initStatus() const {
+ Mutex::Autolock _l(mStateLock);
+ Status status = Status::OK;
+ if (mInitFail) {
+ status = Status::INTERNAL_ERROR;
+ } else if (mDisconnected) {
+ status = Status::CAMERA_DISCONNECTED;
+ } else if (mClosed) {
+ status = Status::INTERNAL_ERROR;
+ }
+ return status;
+}
+
+void CameraDeviceSession::disconnect() {
+ Mutex::Autolock _l(mStateLock);
+ mDisconnected = true;
+ ALOGW("%s: Camera device is disconnected. Closing.", __FUNCTION__);
+ if (!mClosed) {
+ mDevice->common.close(&mDevice->common);
+ mClosed = true;
+ }
+}
+
+void CameraDeviceSession::dumpState(const native_handle_t* fd) {
+ if (!isClosed()) {
+ mDevice->ops->dump(mDevice, fd->data[0]);
+ }
+}
+
+Status CameraDeviceSession::importRequest(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences) {
+ bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+ request.inputBuffer.bufferId != 0);
+ size_t numOutputBufs = request.outputBuffers.size();
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ // Validate all I/O buffers
+ hidl_vec<buffer_handle_t> allBufs;
+ hidl_vec<uint64_t> allBufIds;
+ allBufs.resize(numBufs);
+ allBufIds.resize(numBufs);
+ allBufPtrs.resize(numBufs);
+ allFences.resize(numBufs);
+ std::vector<int32_t> streamIds(numBufs);
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle();
+ allBufIds[i] = request.outputBuffers[i].bufferId;
+ allBufPtrs[i] = &allBufs[i];
+ streamIds[i] = request.outputBuffers[i].streamId;
+ }
+ if (hasInputBuf) {
+ allBufs[numOutputBufs] = request.inputBuffer.buffer.getNativeHandle();
+ allBufIds[numOutputBufs] = request.inputBuffer.bufferId;
+ allBufPtrs[numOutputBufs] = &allBufs[numOutputBufs];
+ streamIds[numOutputBufs] = request.inputBuffer.streamId;
+ }
+
+ for (size_t i = 0; i < numBufs; i++) {
+ buffer_handle_t buf = allBufs[i];
+ uint64_t bufId = allBufIds[i];
+ CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
+ if (cbs.count(bufId) == 0) {
+ if (buf == nullptr) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ sHandleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[bufId] = importedBuf;
+ }
+ }
+ allBufPtrs[i] = &cbs[bufId];
+ }
+
+ // All buffers are imported. Now validate output buffer acquire fences
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ if (!sHandleImporter.importFence(
+ request.outputBuffers[i].acquireFence, allFences[i])) {
+ ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+ cleanupInflightFences(allFences, i);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+
+ // Validate input buffer acquire fences
+ if (hasInputBuf) {
+ if (!sHandleImporter.importFence(
+ request.inputBuffer.acquireFence, allFences[numOutputBufs])) {
+ ALOGE("%s: input buffer acquire fence is invalid", __FUNCTION__);
+ cleanupInflightFences(allFences, numOutputBufs);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+ return Status::OK;
+}
+
+void CameraDeviceSession::cleanupInflightFences(
+ hidl_vec<int>& allFences, size_t numFences) {
+ for (size_t j = 0; j < numFences; j++) {
+ sHandleImporter.closeFence(allFences[j]);
+ }
+}
+
+CameraDeviceSession::ResultBatcher::ResultBatcher(
+ const sp<ICameraDeviceCallback>& callback) : mCallback(callback) {};
+
+bool CameraDeviceSession::ResultBatcher::InflightBatch::allDelivered() const {
+ if (!mShutterDelivered) return false;
+
+ if (mPartialResultProgress < mNumPartialResults) {
+ return false;
+ }
+
+ for (const auto& pair : mBatchBufs) {
+ if (!pair.second.mDelivered) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void CameraDeviceSession::ResultBatcher::setNumPartialResults(uint32_t n) {
+ Mutex::Autolock _l(mLock);
+ mNumPartialResults = n;
+}
+
+void CameraDeviceSession::ResultBatcher::setBatchedStreams(
+ const std::vector<int>& streamsToBatch) {
+ Mutex::Autolock _l(mLock);
+ mStreamsToBatch = streamsToBatch;
+}
+
+void CameraDeviceSession::ResultBatcher::registerBatch(
+ const hidl_vec<CaptureRequest>& requests) {
+ auto batch = std::make_shared<InflightBatch>();
+ batch->mFirstFrame = requests[0].frameNumber;
+ batch->mBatchSize = requests.size();
+ batch->mLastFrame = batch->mFirstFrame + batch->mBatchSize - 1;
+ batch->mNumPartialResults = mNumPartialResults;
+ for (int id : mStreamsToBatch) {
+ batch->mBatchBufs[id] = InflightBatch::BufferBatch();
+ }
+ Mutex::Autolock _l(mLock);
+ mInflightBatches.push_back(batch);
+}
+
+std::pair<int, std::shared_ptr<CameraDeviceSession::ResultBatcher::InflightBatch>>
+CameraDeviceSession::ResultBatcher::getBatch(
+ uint32_t frameNumber) {
+ Mutex::Autolock _l(mLock);
+ int numBatches = mInflightBatches.size();
+ if (numBatches == 0) {
+ return std::make_pair(NOT_BATCHED, nullptr);
+ }
+ uint32_t frameMin = mInflightBatches[0]->mFirstFrame;
+ uint32_t frameMax = mInflightBatches[numBatches - 1]->mLastFrame;
+ if (frameNumber < frameMin || frameNumber > frameMax) {
+ return std::make_pair(NOT_BATCHED, nullptr);
+ }
+ for (int i = 0; i < numBatches; i++) {
+ if (frameNumber >= mInflightBatches[i]->mFirstFrame &&
+ frameNumber <= mInflightBatches[i]->mLastFrame) {
+ return std::make_pair(i, mInflightBatches[i]);
+ }
+ }
+ return std::make_pair(NOT_BATCHED, nullptr);
+}
+
+void CameraDeviceSession::ResultBatcher::checkAndRemoveFirstBatch() {
+ Mutex::Autolock _l(mLock);
+ if (mInflightBatches.size() > 0) {
+ std::shared_ptr<InflightBatch> batch = mInflightBatches[0];
+ bool shouldRemove = false;
+ {
+ Mutex::Autolock _l(batch->mLock);
+ if (batch->allDelivered()) {
+ batch->mRemoved = true;
+ shouldRemove = true;
+ }
+ }
+ if (shouldRemove) {
+ mInflightBatches.pop_front();
+ }
+ }
+}
+
+void CameraDeviceSession::ResultBatcher::sendBatchShutterCbsLocked(std::shared_ptr<InflightBatch> batch) {
+ if (batch->mShutterDelivered) {
+ ALOGW("%s: batch shutter callback already sent!", __FUNCTION__);
+ return;
+ }
+
+ mCallback->notify(batch->mShutterMsgs);
+ batch->mShutterDelivered = true;
+ batch->mShutterMsgs.clear();
+}
+
+void CameraDeviceSession::ResultBatcher::freeReleaseFences(hidl_vec<CaptureResult>& results) {
+ for (auto& result : results) {
+ if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ result.inputBuffer.releaseFence.getNativeHandle());
+ native_handle_delete(handle);
+ }
+ for (auto& buf : result.outputBuffers) {
+ if (buf.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ buf.releaseFence.getNativeHandle());
+ native_handle_delete(handle);
+ }
+ }
+ }
+ return;
+}
+
+void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked(std::shared_ptr<InflightBatch> batch) {
+ sendBatchBuffersLocked(batch, mStreamsToBatch);
+}
+
+void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked(
+ std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams) {
+ size_t batchSize = 0;
+ for (int streamId : streams) {
+ auto it = batch->mBatchBufs.find(streamId);
+ if (it != batch->mBatchBufs.end()) {
+ InflightBatch::BufferBatch& bb = it->second;
+ if (bb.mDelivered) {
+ continue;
+ }
+ if (bb.mBuffers.size() > batchSize) {
+ batchSize = bb.mBuffers.size();
+ }
+ } else {
+ ALOGE("%s: stream ID %d is not batched!", __FUNCTION__, streamId);
+ return;
+ }
+ }
+
+ if (batchSize == 0) {
+ ALOGW("%s: there is no buffer to be delivered for this batch.", __FUNCTION__);
+ for (int streamId : streams) {
+ InflightBatch::BufferBatch& bb = batch->mBatchBufs[streamId];
+ bb.mDelivered = true;
+ }
+ return;
+ }
+
+ hidl_vec<CaptureResult> results;
+ results.resize(batchSize);
+ for (size_t i = 0; i < batchSize; i++) {
+ results[i].frameNumber = batch->mFirstFrame + i;
+ results[i].partialResult = 0; // 0 for buffer only results
+ results[i].inputBuffer.streamId = -1;
+ results[i].inputBuffer.bufferId = 0;
+ results[i].inputBuffer.buffer = nullptr;
+ std::vector<StreamBuffer> outBufs;
+ for (int streamId : streams) {
+ InflightBatch::BufferBatch& bb = batch->mBatchBufs[streamId];
+ if (bb.mDelivered) {
+ continue;
+ }
+ if (i < bb.mBuffers.size()) {
+ outBufs.push_back(bb.mBuffers[i]);
+ }
+ }
+ results[i].outputBuffers = outBufs;
+ }
+ mCallback->processCaptureResult(results);
+ freeReleaseFences(results);
+ for (int streamId : streams) {
+ InflightBatch::BufferBatch& bb = batch->mBatchBufs[streamId];
+ bb.mDelivered = true;
+ bb.mBuffers.clear();
+ }
+}
+
+void CameraDeviceSession::ResultBatcher::sendBatchMetadataLocked(
+ std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx) {
+ if (lastPartialResultIdx <= batch->mPartialResultProgress) {
+ // Result has been delivered. Return
+ ALOGW("%s: partial result %u has been delivered", __FUNCTION__, lastPartialResultIdx);
+ return;
+ }
+
+ std::vector<CaptureResult> results;
+ std::vector<uint32_t> toBeRemovedIdxes;
+ for (auto& pair : batch->mResultMds) {
+ uint32_t partialIdx = pair.first;
+ if (partialIdx > lastPartialResultIdx) {
+ continue;
+ }
+ toBeRemovedIdxes.push_back(partialIdx);
+ InflightBatch::MetadataBatch& mb = pair.second;
+ for (const auto& p : mb.mMds) {
+ CaptureResult result;
+ result.frameNumber = p.first;
+ result.result = std::move(p.second);
+ result.inputBuffer.streamId = -1;
+ result.inputBuffer.bufferId = 0;
+ result.inputBuffer.buffer = nullptr;
+ result.partialResult = partialIdx;
+ results.push_back(std::move(result));
+ }
+ mb.mMds.clear();
+ }
+ mCallback->processCaptureResult(results);
+ batch->mPartialResultProgress = lastPartialResultIdx;
+ for (uint32_t partialIdx : toBeRemovedIdxes) {
+ batch->mResultMds.erase(partialIdx);
+ }
+}
+
+void CameraDeviceSession::ResultBatcher::notifySingleMsg(NotifyMsg& msg) {
+ mCallback->notify({msg});
+ return;
+}
+
+void CameraDeviceSession::ResultBatcher::notify(NotifyMsg& msg) {
+ uint32_t frameNumber;
+ if (CC_LIKELY(msg.type == MsgType::SHUTTER)) {
+ frameNumber = msg.msg.shutter.frameNumber;
+ } else {
+ frameNumber = msg.msg.error.frameNumber;
+ }
+
+ auto pair = getBatch(frameNumber);
+ int batchIdx = pair.first;
+ if (batchIdx == NOT_BATCHED) {
+ notifySingleMsg(msg);
+ return;
+ }
+
+ // When error happened, stop batching for all batches earlier
+ if (CC_UNLIKELY(msg.type == MsgType::ERROR)) {
+ Mutex::Autolock _l(mLock);
+ for (int i = 0; i <= batchIdx; i++) {
+ // Send batched data up
+ std::shared_ptr<InflightBatch> batch = mInflightBatches[0];
+ {
+ Mutex::Autolock _l(batch->mLock);
+ sendBatchShutterCbsLocked(batch);
+ sendBatchBuffersLocked(batch);
+ sendBatchMetadataLocked(batch, mNumPartialResults);
+ if (!batch->allDelivered()) {
+ ALOGE("%s: error: some batch data not sent back to framework!",
+ __FUNCTION__);
+ }
+ batch->mRemoved = true;
+ }
+ mInflightBatches.pop_front();
+ }
+ // Send the error up
+ notifySingleMsg(msg);
+ return;
+ }
+ // Queue shutter callbacks for future delivery
+ std::shared_ptr<InflightBatch> batch = pair.second;
+ {
+ Mutex::Autolock _l(batch->mLock);
+ // Check if the batch is removed (mostly by notify error) before lock was acquired
+ if (batch->mRemoved) {
+ // Fall back to non-batch path
+ notifySingleMsg(msg);
+ return;
+ }
+
+ batch->mShutterMsgs.push_back(msg);
+ if (frameNumber == batch->mLastFrame) {
+ sendBatchShutterCbsLocked(batch);
+ }
+ } // end of batch lock scope
+
+ // see if the batch is complete
+ if (frameNumber == batch->mLastFrame) {
+ checkAndRemoveFirstBatch();
+ }
+}
+
+void CameraDeviceSession::ResultBatcher::processOneCaptureResult(CaptureResult& result) {
+ hidl_vec<CaptureResult> results = {result};
+ mCallback->processCaptureResult(results);
+ freeReleaseFences(results);
+ return;
+}
+
+void CameraDeviceSession::ResultBatcher::processCaptureResult(CaptureResult& result) {
+ auto pair = getBatch(result.frameNumber);
+ int batchIdx = pair.first;
+ if (batchIdx == NOT_BATCHED) {
+ processOneCaptureResult(result);
+ return;
+ }
+ std::shared_ptr<InflightBatch> batch = pair.second;
+ {
+ Mutex::Autolock _l(batch->mLock);
+ // Check if the batch is removed (mostly by notify error) before lock was acquired
+ if (batch->mRemoved) {
+ // Fall back to non-batch path
+ processOneCaptureResult(result);
+ return;
+ }
+
+ // queue metadata
+ if (result.result.size() != 0) {
+ // Save a copy of metadata
+ batch->mResultMds[result.partialResult].mMds.push_back(
+ std::make_pair(result.frameNumber, result.result));
+ }
+
+ // queue buffer
+ std::vector<int> filledStreams;
+ std::vector<StreamBuffer> nonBatchedBuffers;
+ for (auto& buffer : result.outputBuffers) {
+ auto it = batch->mBatchBufs.find(buffer.streamId);
+ if (it != batch->mBatchBufs.end()) {
+ InflightBatch::BufferBatch& bb = it->second;
+ bb.mBuffers.push_back(buffer);
+ filledStreams.push_back(buffer.streamId);
+ } else {
+ nonBatchedBuffers.push_back(buffer);
+ }
+ }
+
+ // send non-batched buffers up
+ if (nonBatchedBuffers.size() > 0 || result.inputBuffer.streamId != -1) {
+ CaptureResult nonBatchedResult;
+ nonBatchedResult.frameNumber = result.frameNumber;
+ nonBatchedResult.outputBuffers = nonBatchedBuffers;
+ nonBatchedResult.inputBuffer = result.inputBuffer;
+ nonBatchedResult.partialResult = 0; // 0 for buffer only results
+ processOneCaptureResult(nonBatchedResult);
+ }
+
+ if (result.frameNumber == batch->mLastFrame) {
+ // Send data up
+ if (result.partialResult > 0) {
+ sendBatchMetadataLocked(batch, result.partialResult);
+ }
+ // send buffer up
+ if (filledStreams.size() > 0) {
+ sendBatchBuffersLocked(batch, filledStreams);
+ }
+ }
+ } // end of batch lock scope
+
+ // see if the batch is complete
+ if (result.frameNumber == batch->mLastFrame) {
+ checkAndRemoveFirstBatch();
+ }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+Return<void> CameraDeviceSession::constructDefaultRequestSettings(
+ RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraMetadata outMetadata;
+ const camera_metadata_t *rawRequest;
+ if (status == Status::OK) {
+ ATRACE_BEGIN("camera3->construct_default_request_settings");
+ rawRequest = mDevice->ops->construct_default_request_settings(mDevice, (int) type);
+ ATRACE_END();
+ if (rawRequest == nullptr) {
+ ALOGI("%s: template %d is not supported on this camera device",
+ __FUNCTION__, type);
+ status = Status::ILLEGAL_ARGUMENT;
+ } else {
+ convertToHidl(rawRequest, &outMetadata);
+ }
+ }
+ _hidl_cb(status, outMetadata);
+ return Void();
+}
+
+Return<void> CameraDeviceSession::configureStreams(
+ const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) {
+ Status status = initStatus();
+ HalStreamConfiguration outStreams;
+
+ // hold the inflight lock for entire configureStreams scope since there must not be any
+ // inflight request/results during stream configuration.
+ Mutex::Autolock _l(mInflightLock);
+ if (!mInflightBuffers.empty()) {
+ ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+ __FUNCTION__, mInflightBuffers.size());
+ _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+ return Void();
+ }
+
+ if (status != Status::OK) {
+ _hidl_cb(status, outStreams);
+ return Void();
+ }
+
+ camera3_stream_configuration_t stream_list;
+ hidl_vec<camera3_stream_t*> streams;
+
+ stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
+ stream_list.num_streams = requestedConfiguration.streams.size();
+ streams.resize(stream_list.num_streams);
+ stream_list.streams = streams.data();
+
+ for (uint32_t i = 0; i < stream_list.num_streams; i++) {
+ int id = requestedConfiguration.streams[i].id;
+
+ if (mStreamMap.count(id) == 0) {
+ Camera3Stream stream;
+ convertFromHidl(requestedConfiguration.streams[i], &stream);
+ mStreamMap[id] = stream;
+ mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+ } else {
+ // width/height/format must not change, but usage/rotation might need to change
+ if (mStreamMap[id].stream_type !=
+ (int) requestedConfiguration.streams[i].streamType ||
+ mStreamMap[id].width != requestedConfiguration.streams[i].width ||
+ mStreamMap[id].height != requestedConfiguration.streams[i].height ||
+ mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
+ mStreamMap[id].data_space != (android_dataspace_t)
+ requestedConfiguration.streams[i].dataSpace) {
+ ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+ _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+ return Void();
+ }
+ mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
+ mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
+ }
+ streams[i] = &mStreamMap[id];
+ }
+
+ ATRACE_BEGIN("camera3->configure_streams");
+ status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+ ATRACE_END();
+
+ // In case Hal returns error most likely it was not able to release
+ // the corresponding resources of the deleted streams.
+ if (ret == OK) {
+ // delete unused streams, note we do this after adding new streams to ensure new stream
+ // will not have the same address as deleted stream, and HAL has a chance to reference
+ // the to be deleted stream in configure_streams call
+ for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+ int id = it->first;
+ bool found = false;
+ for (const auto& stream : requestedConfiguration.streams) {
+ if (id == stream.id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // Unmap all buffers of deleted stream
+ // in case the configuration call succeeds and HAL
+ // is able to release the corresponding resources too.
+ cleanupBuffersLocked(id);
+ it = mStreamMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Track video streams
+ mVideoStreamIds.clear();
+ for (const auto& stream : requestedConfiguration.streams) {
+ if (stream.streamType == StreamType::OUTPUT &&
+ stream.usage & graphics::allocator::V2_0::ConsumerUsage::VIDEO_ENCODER) {
+ mVideoStreamIds.push_back(stream.id);
+ }
+ }
+ mResultBatcher.setBatchedStreams(mVideoStreamIds);
+ }
+
+ if (ret == -EINVAL) {
+ status = Status::ILLEGAL_ARGUMENT;
+ } else if (ret != OK) {
+ status = Status::INTERNAL_ERROR;
+ } else {
+ convertToHidl(stream_list, &outStreams);
+ }
+
+ _hidl_cb(status, outStreams);
+ return Void();
+}
+
+// Needs to get called after acquiring 'mInflightLock'
+void CameraDeviceSession::cleanupBuffersLocked(int id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+Return<void> CameraDeviceSession::processCaptureRequest(
+ const hidl_vec<CaptureRequest>& requests, processCaptureRequest_cb _hidl_cb) {
+ uint32_t numRequestProcessed = 0;
+ Status s = Status::OK;
+ for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
+ s = processOneCaptureRequest(requests[i]);
+ if (s != Status::OK) {
+ break;
+ }
+ }
+
+ if (s == Status::OK && requests.size() > 1) {
+ mResultBatcher.registerBatch(requests);
+ }
+
+ _hidl_cb(s, numRequestProcessed);
+ return Void();
+}
+
+Status CameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request) {
+ Status status = initStatus();
+ if (status != Status::OK) {
+ ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
+ return status;
+ }
+
+ camera3_capture_request_t halRequest;
+ halRequest.frame_number = request.frameNumber;
+ bool converted = convertFromHidl(request.settings, &halRequest.settings);
+ if (!converted) {
+ ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ hidl_vec<buffer_handle_t*> allBufPtrs;
+ hidl_vec<int> allFences;
+ bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+ request.inputBuffer.bufferId != 0);
+ size_t numOutputBufs = request.outputBuffers.size();
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ status = importRequest(request, allBufPtrs, allFences);
+ if (status != Status::OK) {
+ return status;
+ }
+
+ hidl_vec<camera3_stream_buffer_t> outHalBufs;
+ outHalBufs.resize(numOutputBufs);
+ {
+ Mutex::Autolock _l(mInflightLock);
+ if (hasInputBuf) {
+ auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+ auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+ convertFromHidl(
+ allBufPtrs[numOutputBufs], request.inputBuffer.status,
+ &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
+ &bufCache);
+ halRequest.input_buffer = &bufCache;
+ } else {
+ halRequest.input_buffer = nullptr;
+ }
+
+ halRequest.num_output_buffers = numOutputBufs;
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+ auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+ convertFromHidl(
+ allBufPtrs[i], request.outputBuffers[i].status,
+ &mStreamMap[request.outputBuffers[i].streamId], allFences[i],
+ &bufCache);
+ outHalBufs[i] = bufCache;
+ }
+ halRequest.output_buffers = outHalBufs.data();
+ }
+
+ ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
+ ATRACE_BEGIN("camera3->process_capture_request");
+ status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
+ ATRACE_END();
+ if (ret != OK) {
+ Mutex::Autolock _l(mInflightLock);
+ ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+ cleanupInflightFences(allFences, numBufs);
+ if (hasInputBuf) {
+ auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+ mInflightBuffers.erase(key);
+ }
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+ mInflightBuffers.erase(key);
+ }
+ return Status::INTERNAL_ERROR;
+ }
+
+ return Status::OK;
+}
+
+Return<Status> CameraDeviceSession::flush() {
+ Status status = initStatus();
+ if (status == Status::OK) {
+ // Flush is always supported on device 3.1 or later
+ status_t ret = mDevice->ops->flush(mDevice);
+ if (ret != OK) {
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ return status;
+}
+
+Return<void> CameraDeviceSession::close() {
+ Mutex::Autolock _l(mStateLock);
+ if (!mClosed) {
+ {
+ Mutex::Autolock _l(mInflightLock);
+ if (!mInflightBuffers.empty()) {
+ ALOGE("%s: trying to close while there are still %zu inflight buffers!",
+ __FUNCTION__, mInflightBuffers.size());
+ }
+ }
+
+ ATRACE_BEGIN("camera3->close");
+ mDevice->common.close(&mDevice->common);
+ ATRACE_END();
+
+ // free all imported buffers
+ for(auto& pair : mCirculatingBuffers) {
+ CirculatingBuffers& buffers = pair.second;
+ for (auto& p2 : buffers) {
+ sHandleImporter.freeBuffer(p2.second);
+ }
+ }
+
+ mClosed = true;
+ }
+ return Void();
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult(
+ const camera3_callback_ops *cb,
+ const camera3_capture_result *hal_result) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+ uint32_t frameNumber = hal_result->frame_number;
+ bool hasInputBuf = (hal_result->input_buffer != nullptr);
+ size_t numOutputBufs = hal_result->num_output_buffers;
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ if (numBufs > 0) {
+ Mutex::Autolock _l(d->mInflightLock);
+ if (hasInputBuf) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ // validate if buffer is inflight
+ auto key = std::make_pair(streamId, frameNumber);
+ if (d->mInflightBuffers.count(key) != 1) {
+ ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
+ __FUNCTION__, streamId, frameNumber);
+ return;
+ }
+ }
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ // validate if buffer is inflight
+ auto key = std::make_pair(streamId, frameNumber);
+ if (d->mInflightBuffers.count(key) != 1) {
+ ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
+ __FUNCTION__, streamId, frameNumber);
+ return;
+ }
+ }
+ }
+ // We don't need to validate/import fences here since we will be passing them to camera service
+ // within the scope of this function
+ CaptureResult result;
+ result.frameNumber = frameNumber;
+ result.partialResult = hal_result->partial_result;
+ convertToHidl(hal_result->result, &result.result);
+ if (hasInputBuf) {
+ result.inputBuffer.streamId =
+ static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ result.inputBuffer.buffer = nullptr;
+ result.inputBuffer.status = (BufferStatus) hal_result->input_buffer->status;
+ // skip acquire fence since it's no use to camera service
+ if (hal_result->input_buffer->release_fence != -1) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = hal_result->input_buffer->release_fence;
+ result.inputBuffer.releaseFence = handle;
+ } else {
+ result.inputBuffer.releaseFence = nullptr;
+ }
+ } else {
+ result.inputBuffer.streamId = -1;
+ }
+
+ result.outputBuffers.resize(numOutputBufs);
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ result.outputBuffers[i].streamId =
+ static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ result.outputBuffers[i].buffer = nullptr;
+ result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status;
+ // skip acquire fence since it's of no use to camera service
+ if (hal_result->output_buffers[i].release_fence != -1) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = hal_result->output_buffers[i].release_fence;
+ result.outputBuffers[i].releaseFence = handle;
+ } else {
+ result.outputBuffers[i].releaseFence = nullptr;
+ }
+ }
+
+ // Free inflight record/fences.
+ // Do this before call back to camera service because camera service might jump to
+ // configure_streams right after the processCaptureResult call so we need to finish
+ // updating inflight queues first
+ if (numBufs > 0) {
+ Mutex::Autolock _l(d->mInflightLock);
+ if (hasInputBuf) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ auto key = std::make_pair(streamId, frameNumber);
+ d->mInflightBuffers.erase(key);
+ }
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ auto key = std::make_pair(streamId, frameNumber);
+ d->mInflightBuffers.erase(key);
+ }
+
+ if (d->mInflightBuffers.empty()) {
+ ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
+ }
+ }
+
+ d->mResultBatcher.processCaptureResult(result);
+}
+
+void CameraDeviceSession::sNotify(
+ const camera3_callback_ops *cb,
+ const camera3_notify_msg *msg) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+ NotifyMsg hidlMsg;
+ convertToHidl(msg, &hidlMsg);
+
+ if (hidlMsg.type == (MsgType) CAMERA3_MSG_ERROR &&
+ hidlMsg.msg.error.errorStreamId != -1) {
+ if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
+ ALOGE("%s: unknown stream ID %d reports an error!",
+ __FUNCTION__, hidlMsg.msg.error.errorStreamId);
+ return;
+ }
+ }
+ d->mResultBatcher.notify(hidlMsg);
+}
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
new file mode 100644
index 0000000..8923c05
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+
+#include <deque>
+#include <map>
+#include <unordered_map>
+#include "hardware/camera_common.h"
+#include "hardware/camera3.h"
+#include "utils/Mutex.h"
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include <include/convert.h>
+#include "HandleImporter.h"
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/**
+ * Function pointer types with C calling convention to
+ * use for HAL callback functions.
+ */
+extern "C" {
+ typedef void (callbacks_process_capture_result_t)(
+ const struct camera3_callback_ops *,
+ const camera3_capture_result_t *);
+
+ typedef void (callbacks_notify_t)(
+ const struct camera3_callback_ops *,
+ const camera3_notify_msg_t *);
+}
+
+struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callback_ops {
+
+ CameraDeviceSession(camera3_device_t*,
+ const camera_metadata_t* deviceInfo,
+ const sp<ICameraDeviceCallback>&);
+ ~CameraDeviceSession();
+ // Call by CameraDevice to dump active device states
+ void dumpState(const native_handle_t* fd);
+ // Caller must use this method to check if CameraDeviceSession ctor failed
+ bool isInitFailed() { return mInitFail; }
+ // Used by CameraDevice to signal external camera disconnected
+ void disconnect();
+ bool isClosed();
+
+ // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+ Return<void> constructDefaultRequestSettings(
+ RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) override;
+ Return<void> configureStreams(
+ const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override;
+ Return<void> processCaptureRequest(
+ const hidl_vec<CaptureRequest>& requests, processCaptureRequest_cb _hidl_cb) override;
+ Return<Status> flush() override;
+ Return<void> close() override;
+
+private:
+ // protecting mClosed/mDisconnected/mInitFail
+ mutable Mutex mStateLock;
+ // device is closed either
+ // - closed by user
+ // - init failed
+ // - camera disconnected
+ bool mClosed = false;
+
+ // Set by CameraDevice (when external camera is disconnected)
+ bool mDisconnected = false;
+
+ camera3_device_t* mDevice;
+ // Stream ID -> Camera3Stream cache
+ std::map<int, Camera3Stream> mStreamMap;
+
+ mutable Mutex mInflightLock; // protecting mInflightBuffers and mCirculatingBuffers
+ // (streamID, frameNumber) -> inflight buffer cache
+ std::map<std::pair<int, uint32_t>, camera3_stream_buffer_t> mInflightBuffers;
+
+ // buffers currently ciculating between HAL and camera service
+ // key: bufferId sent via HIDL interface
+ // value: imported buffer_handle_t
+ // Buffer will be imported during process_capture_request and will be freed
+ // when the its stream is deleted or camera device session is closed
+ typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+ // Stream ID -> circulating buffers map
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ static HandleImporter& sHandleImporter;
+
+ bool mInitFail;
+
+ common::V1_0::helper::CameraMetadata mDeviceInfo;
+
+ class ResultBatcher {
+ public:
+ ResultBatcher(const sp<ICameraDeviceCallback>& callback);
+ void setNumPartialResults(uint32_t n);
+ void setBatchedStreams(const std::vector<int>& streamsToBatch);
+
+ void registerBatch(const hidl_vec<CaptureRequest>& requests);
+ void notify(NotifyMsg& msg);
+ void processCaptureResult(CaptureResult& result);
+
+ private:
+ struct InflightBatch {
+ // Protect access to entire struct. Acquire this lock before read/write any data or
+ // calling any methods. processCaptureResult and notify will compete for this lock
+ // HIDL IPCs might be issued while the lock is held
+ Mutex mLock;
+
+ bool allDelivered() const;
+
+ uint32_t mFirstFrame;
+ uint32_t mLastFrame;
+ uint32_t mBatchSize;
+
+ bool mShutterDelivered = false;
+ std::vector<NotifyMsg> mShutterMsgs;
+
+ struct BufferBatch {
+ bool mDelivered = false;
+ // This currently assumes every batched request will output to the batched stream
+ // and since HAL must always send buffers in order, no frameNumber tracking is
+ // needed
+ std::vector<StreamBuffer> mBuffers;
+ };
+ // Stream ID -> VideoBatch
+ std::unordered_map<int, BufferBatch> mBatchBufs;
+
+ struct MetadataBatch {
+ // (frameNumber, metadata)
+ std::vector<std::pair<uint32_t, CameraMetadata>> mMds;
+ };
+ // Partial result IDs that has been delivered to framework
+ uint32_t mNumPartialResults;
+ uint32_t mPartialResultProgress = 0;
+ // partialResult -> MetadataBatch
+ std::map<uint32_t, MetadataBatch> mResultMds;
+
+ // Set to true when batch is removed from mInflightBatches
+ // processCaptureResult and notify must check this flag after acquiring mLock to make
+ // sure this batch isn't removed while waiting for mLock
+ bool mRemoved = false;
+ };
+
+ static const int NOT_BATCHED = -1;
+
+ // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched)
+ // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch
+ // It's possible that the InflightBatch is removed from mInflightBatches before the
+ // InflightBatch::mLock is acquired (most likely caused by an error notification), so
+ // caller must check InflightBatch::mRemoved flag after the lock is acquried.
+ // This method will hold ResultBatcher::mLock briefly
+ std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber);
+
+ // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so
+ // This method will hold ResultBatcher::mLock briefly
+ void checkAndRemoveFirstBatch();
+
+ // The following sendXXXX methods must be called while the InflightBatch::mLock is locked
+ // HIDL IPC methods will be called during these methods.
+ void sendBatchShutterCbsLocked(std::shared_ptr<InflightBatch> batch);
+ // send buffers for all batched streams
+ void sendBatchBuffersLocked(std::shared_ptr<InflightBatch> batch);
+ // send buffers for specified streams
+ void sendBatchBuffersLocked(
+ std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams);
+ void sendBatchMetadataLocked(
+ std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
+ // End of sendXXXX methods
+
+ // helper methods
+ void freeReleaseFences(hidl_vec<CaptureResult>&);
+ void notifySingleMsg(NotifyMsg& msg);
+ void processOneCaptureResult(CaptureResult& result);
+
+ // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
+ // processCaptureRequest, processCaptureResult, notify will compete for this lock
+ // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error)
+ mutable Mutex mLock;
+ std::deque<std::shared_ptr<InflightBatch>> mInflightBatches;
+ uint32_t mNumPartialResults;
+ std::vector<int> mStreamsToBatch;
+ const sp<ICameraDeviceCallback> mCallback;
+ } mResultBatcher;
+
+ std::vector<int> mVideoStreamIds;
+
+ bool initialize();
+
+ Status initStatus() const;
+
+ // Validate and import request's input buffer and acquire fence
+ Status importRequest(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences);
+
+ static void cleanupInflightFences(
+ hidl_vec<int>& allFences, size_t numFences);
+
+ void cleanupBuffersLocked(int id);
+
+ Status processOneCaptureRequest(const CaptureRequest& request);
+ /**
+ * Static callback forwarding methods from HAL to instance
+ */
+ static callbacks_process_capture_result_t sProcessCaptureResult;
+ static callbacks_notify_t sNotify;
+};
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h
new file mode 100644
index 0000000..4e86067
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice_3_2.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraModule.h"
+#include "CameraMetadata.h"
+#include "CameraDeviceSession.h"
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct CameraDevice : public ICameraDevice {
+ // Called by provider HAL. Provider HAL must ensure the uniqueness of
+ // CameraDevice object per cameraId, or there could be multiple CameraDevice
+ // trying to access the same physical camera.
+ // Also, provider will have to keep track of all CameraDevice objects in
+ // order to notify CameraDevice when the underlying camera is detached
+ CameraDevice(sp<CameraModule> module,
+ const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+ ~CameraDevice();
+ // Caller must use this method to check if CameraDevice ctor failed
+ bool isInitFailed() { return mInitFail; }
+ // Used by provider HAL to signal external camera disconnected
+ void setConnectionStatus(bool connected);
+
+ /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
+ // The following method can be called without opening the actual camera device
+ Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
+ Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
+ Return<Status> setTorchMode(TorchMode mode) override;
+
+ // Open the device HAL and also return a default capture session
+ Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override;
+
+
+ // Forward the dump call to the opened session, or do nothing
+ Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override;
+ /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
+
+private:
+ const sp<CameraModule> mModule;
+ const std::string mCameraId;
+ // const after ctor
+ int mCameraIdInt;
+ int mDeviceVersion;
+ bool mInitFail = false;
+ // Set by provider (when external camera is connected/disconnected)
+ bool mDisconnected;
+ wp<CameraDeviceSession> mSession = nullptr;
+
+ const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames;
+
+ // gating access to mSession and mDisconnected
+ mutable Mutex mLock;
+
+ // convert conventional HAL status to HIDL Status
+ static Status getHidlStatus(int);
+
+ Status initStatus() const;
+};
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
new file mode 100644
index 0000000..35676df
--- /dev/null
+++ b/camera/device/3.2/default/convert.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.camera.device@3.2-convert-impl"
+#include <android/log.h>
+
+#include "include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::camera::device::V3_2::ConsumerUsageFlags;
+using ::android::hardware::camera::device::V3_2::ProducerUsageFlags;
+
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) {
+ if (src.size() == 0) {
+ // Special case for null metadata
+ *dst = nullptr;
+ return true;
+ }
+
+ const uint8_t* data = src.data();
+ // sanity check the size of CameraMetadata match underlying camera_metadata_t
+ if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) {
+ ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
+ return false;
+ }
+ *dst = (camera_metadata_t*) data;
+ return true;
+}
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void convertToHidl(const camera_metadata_t *src, CameraMetadata* dst) {
+ if (src == nullptr) {
+ return;
+ }
+ size_t size = get_camera_metadata_size(src);
+ dst->setToExternal((uint8_t *) src, size);
+ return;
+}
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst) {
+ dst->mId = src.id;
+ dst->stream_type = (int) src.streamType;
+ dst->width = src.width;
+ dst->height = src.height;
+ dst->format = (int) src.format;
+ dst->data_space = (android_dataspace_t) src.dataSpace;
+ dst->rotation = (int) src.rotation;
+ dst->usage = (uint32_t) src.usage;
+ // Fields to be filled by HAL (max_buffers, priv) are initialized to 0
+ dst->max_buffers = 0;
+ dst->priv = 0;
+ return;
+}
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst) {
+ dst->id = src->mId;
+ dst->overrideFormat = (PixelFormat) src->format;
+ dst->maxBuffers = src->max_buffers;
+ if (src->stream_type == CAMERA3_STREAM_OUTPUT) {
+ dst->consumerUsage = (ConsumerUsageFlags) 0;
+ dst->producerUsage = (ProducerUsageFlags) src->usage;
+ } else if (src->stream_type == CAMERA3_STREAM_INPUT) {
+ dst->producerUsage = (ProducerUsageFlags) 0;
+ dst->consumerUsage = (ConsumerUsageFlags) src->usage;
+ } else {
+ //Should not reach here per current HIDL spec, but we might end up adding
+ // bi-directional stream to HIDL.
+ ALOGW("%s: Stream type %d is not currently supported!",
+ __FUNCTION__, src->stream_type);
+ }
+}
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) {
+ dst->streams.resize(src.num_streams);
+ for (uint32_t i = 0; i < src.num_streams; i++) {
+ convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]);
+ }
+ return;
+}
+
+void convertFromHidl(
+ buffer_handle_t* bufPtr, BufferStatus status, camera3_stream_t* stream, int acquireFence,
+ camera3_stream_buffer_t* dst) {
+ dst->stream = stream;
+ dst->buffer = bufPtr;
+ dst->status = (int) status;
+ dst->acquire_fence = acquireFence;
+ dst->release_fence = -1; // meant for HAL to fill in
+}
+
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst) {
+ dst->type = (MsgType) src->type;
+ switch (src->type) {
+ case CAMERA3_MSG_ERROR:
+ {
+ // The camera3_stream_t* must be the same as what wrapper HAL passed to conventional
+ // HAL, or the ID lookup will return garbage. Caller should validate the ID here is
+ // indeed one of active stream IDs
+ Camera3Stream* stream = static_cast<Camera3Stream*>(
+ src->message.error.error_stream);
+ dst->msg.error.frameNumber = src->message.error.frame_number;
+ dst->msg.error.errorStreamId = (stream != nullptr) ? stream->mId : -1;
+ dst->msg.error.errorCode = (ErrorCode) src->message.error.error_code;
+ }
+ break;
+ case CAMERA3_MSG_SHUTTER:
+ dst->msg.shutter.frameNumber = src->message.shutter.frame_number;
+ dst->msg.shutter.timestamp = src->message.shutter.timestamp;
+ break;
+ default:
+ ALOGE("%s: HIDL type converion failed. Unknown msg type 0x%x",
+ __FUNCTION__, src->type);
+ }
+ return;
+}
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/include/convert.h b/camera/device/3.2/default/include/convert.h
new file mode 100644
index 0000000..96891f0
--- /dev/null
+++ b/camera/device/3.2/default/include/convert.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <set>
+
+
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include "hardware/camera3.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+// The camera3_stream_t sent to conventional HAL. Added mId fields to enable stream ID lookup
+// fromt a downcasted camera3_stream
+struct Camera3Stream : public camera3_stream {
+ int mId;
+};
+
+// *dst will point to the data owned by src, but src still owns the data after this call returns.
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst);
+void convertToHidl(const camera_metadata_t* src, CameraMetadata* dst);
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst);
+void convertToHidl(const Camera3Stream* src, HalStream* dst);
+
+void convertFromHidl(
+ buffer_handle_t*, BufferStatus, camera3_stream_t*, int acquireFence, // inputs
+ camera3_stream_buffer_t* dst);
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst);
+
+// The camera3_stream_t* in src must be the same as what wrapper HAL passed to conventional
+// HAL, or the ID lookup will return garbage. Caller should validate the ID in ErrorMsg is
+// indeed one of active stream IDs
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst);
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal
new file mode 100644
index 0000000..ba5bbe0
--- /dev/null
+++ b/camera/device/3.2/types.hal
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2016 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.camera.device@3.2;
+
+import android.hardware.graphics.allocator@2.0::types;
+import android.hardware.graphics.common@1.0::types;
+
+typedef vec<uint8_t> CameraMetadata;
+typedef bitfield<ProducerUsage> ProducerUsageFlags;
+typedef bitfield<ConsumerUsage> ConsumerUsageFlags;
+typedef bitfield<Dataspace> DataspaceFlags;
+
+/**
+ * StreamType:
+ *
+ * The type of the camera stream, which defines whether the camera HAL device is
+ * the producer or the consumer for that stream, and how the buffers of the
+ * stream relate to the other streams.
+ */
+enum StreamType : uint32_t {
+ /**
+ * This stream is an output stream; the camera HAL device must fill buffers
+ * from this stream with newly captured or reprocessed image data.
+ */
+ OUTPUT = 0,
+
+ /**
+ * This stream is an input stream; the camera HAL device must read buffers
+ * from this stream and send them through the camera processing pipeline,
+ * as if the buffer was a newly captured image from the imager.
+ *
+ * The pixel format for input stream can be any format reported by
+ * android.scaler.availableInputOutputFormatsMap. The pixel format of the
+ * output stream that is used to produce the reprocessing data may be any
+ * format reported by android.scaler.availableStreamConfigurations. The
+ * supported input/output stream combinations depends the camera device
+ * capabilities, see android.scaler.availableInputOutputFormatsMap for
+ * stream map details.
+ *
+ * This kind of stream is generally used to reprocess data into higher
+ * quality images (that otherwise would cause a frame rate performance
+ * loss), or to do off-line reprocessing.
+ *
+ * The typical use cases are OPAQUE (typically ZSL) and YUV reprocessing,
+ * see S8.2, S8.3 and S10 for more details.
+ */
+ INPUT = 1
+
+};
+
+/**
+ * StreamRotation:
+ *
+ * The required counterclockwise rotation of camera stream.
+ */
+enum StreamRotation : uint32_t {
+ /* No rotation */
+ ROTATION_0 = 0,
+
+ /* Rotate by 90 degree counterclockwise */
+ ROTATION_90 = 1,
+
+ /* Rotate by 180 degree counterclockwise */
+ ROTATION_180 = 2,
+
+ /* Rotate by 270 degree counterclockwise */
+ ROTATION_270 = 3
+
+};
+
+/**
+ * StreamConfigurationMode:
+ *
+ * This defines the general operation mode for the HAL (for a given stream
+ * configuration) where modes besides NORMAL have different semantics, and
+ * usually limit the generality of the API in exchange for higher performance in
+ * some particular area.
+ */
+enum StreamConfigurationMode : uint32_t {
+ /**
+ * Normal stream configuration operation mode. This is the default camera
+ * operation mode, where all semantics of HAL APIs and metadata controls
+ * apply.
+ */
+ NORMAL_MODE = 0,
+
+ /**
+ * Special constrained high speed operation mode for devices that can not
+ * support high speed output in NORMAL mode. All streams in this
+ * configuration are operating at high speed mode and have different
+ * characteristics and limitations to achieve high speed output. The NORMAL
+ * mode can still be used for high speed output if the HAL can support high
+ * speed output while satisfying all the semantics of HAL APIs and metadata
+ * controls. It is recommended for the HAL to support high speed output in
+ * NORMAL mode (by advertising the high speed FPS ranges in
+ * android.control.aeAvailableTargetFpsRanges) if possible.
+ *
+ * This mode has below limitations/requirements:
+ *
+ * 1. The HAL must support up to 2 streams with sizes reported by
+ * android.control.availableHighSpeedVideoConfigurations.
+ * 2. In this mode, the HAL is expected to output up to 120fps or
+ * higher. This mode must support the targeted FPS range and size
+ * configurations reported by
+ * android.control.availableHighSpeedVideoConfigurations.
+ * 3. The HAL must support IMPLEMENTATION_DEFINED output
+ * stream format.
+ * 4. To achieve efficient high speed streaming, the HAL may have to
+ * aggregate multiple frames together and send to camera device for
+ * processing where the request controls are same for all the frames in
+ * this batch (batch mode). The HAL must support max batch size and the
+ * max batch size requirements defined by
+ * android.control.availableHighSpeedVideoConfigurations.
+ * 5. In this mode, the HAL must override aeMode, awbMode, and afMode to
+ * ON, ON, and CONTINUOUS_VIDEO, respectively. All post-processing
+ * block mode controls must be overridden to be FAST. Therefore, no
+ * manual control of capture and post-processing parameters is
+ * possible. All other controls operate the same as when
+ * android.control.mode == AUTO. This means that all other
+ * android.control.* fields must continue to work, such as
+ *
+ * android.control.aeTargetFpsRange
+ * android.control.aeExposureCompensation
+ * android.control.aeLock
+ * android.control.awbLock
+ * android.control.effectMode
+ * android.control.aeRegions
+ * android.control.afRegions
+ * android.control.awbRegions
+ * android.control.afTrigger
+ * android.control.aePrecaptureTrigger
+ *
+ * Outside of android.control.*, the following controls must work:
+ *
+ * android.flash.mode (TORCH mode only, automatic flash for still
+ * capture must not work since aeMode is ON)
+ * android.lens.opticalStabilizationMode (if it is supported)
+ * android.scaler.cropRegion
+ * android.statistics.faceDetectMode (if it is supported)
+ * 6. To reduce the amount of data passed across process boundaries at
+ * high frame rate, within one batch, camera framework only propagates
+ * the last shutter notify and the last capture results (including partial
+ * results and final result) to the app. The shutter notifies and capture
+ * results for the other requests in the batch are derived by
+ * the camera framework. As a result, the HAL can return empty metadata
+ * except for the last result in the batch.
+ *
+ * For more details about high speed stream requirements, see
+ * android.control.availableHighSpeedVideoConfigurations and
+ * CONSTRAINED_HIGH_SPEED_VIDEO capability defined in
+ * android.request.availableCapabilities.
+ *
+ * This mode only needs to be supported by HALs that include
+ * CONSTRAINED_HIGH_SPEED_VIDEO in the android.request.availableCapabilities
+ * static metadata.
+ */
+ CONSTRAINED_HIGH_SPEED_MODE = 1,
+
+ /**
+ * A set of vendor-defined operating modes, for custom default camera
+ * application features that can't be implemented in the fully flexible fashion
+ * required for NORMAL_MODE.
+ */
+ VENDOR_MODE_0 = 0x8000,
+ VENDOR_MODE_1,
+ VENDOR_MODE_2,
+ VENDOR_MODE_3,
+ VENDOR_MODE_4,
+ VENDOR_MODE_5,
+ VENDOR_MODE_6,
+ VENDOR_MODE_7
+};
+
+/**
+ * Stream:
+ *
+ * A descriptor for a single camera input or output stream. A stream is defined
+ * by the framework by its buffer resolution and format, and additionally by the
+ * HAL with the gralloc usage flags and the maximum in-flight buffer count.
+ *
+ * If a configureStreams() call returns a non-fatal error, all active streams
+ * remain valid as if configureStreams() had not been called.
+ *
+ */
+struct Stream {
+ /**
+ * Stream ID - a nonnegative integer identifier for a stream.
+ *
+ * The identical stream ID must reference the same stream, with the same
+ * width/height/format, across consecutive calls to configureStreams.
+ *
+ * If previously-used stream ID is not used in a new call to
+ * configureStreams, then that stream is no longer active. Such a stream ID
+ * may be reused in a future configureStreams with a new
+ * width/height/format.
+ *
+ */
+ int32_t id;
+
+ /**
+ * The type of the stream (input vs output, etc).
+ */
+ StreamType streamType;
+
+ /**
+ * The width in pixels of the buffers in this stream
+ */
+ uint32_t width;
+
+ /**
+ * The height in pixels of the buffers in this stream
+ */
+ uint32_t height;
+
+ /**
+ * The pixel format for the buffers in this stream.
+ *
+ * If IMPLEMENTATION_DEFINED is used, then the platform
+ * gralloc module must select a format based on the usage flags provided by
+ * the camera device and the other endpoint of the stream.
+ *
+ */
+ android.hardware.graphics.common@1.0::PixelFormat format;
+
+ /**
+ * The gralloc usage flags for this stream, as needed by the consumer of
+ * the stream.
+ *
+ * The usage flags from the producer and the consumer must be combined
+ * together and then passed to the platform gralloc HAL module for
+ * allocating the gralloc buffers for each stream.
+ *
+ * The HAL may use these consumer flags to decide stream configuration. For
+ * streamType INPUT, the value of this field is always 0. For all streams
+ * passed via configureStreams(), the HAL must set its own
+ * additional usage flags in its output HalStreamConfiguration.
+ *
+ * The usage flag for an output stream may be bitwise combination of usage
+ * flags for multiple consumers, for the purpose of sharing one camera
+ * stream between those consumers. The HAL must fail configureStreams call
+ * with ILLEGAL_ARGUMENT if the combined flags cannot be supported due to
+ * imcompatible buffer format, dataSpace, or other hardware limitations.
+ */
+ ConsumerUsageFlags usage;
+
+ /**
+ * A field that describes the contents of the buffer. The format and buffer
+ * dimensions define the memory layout and structure of the stream buffers,
+ * while dataSpace defines the meaning of the data within the buffer.
+ *
+ * For most formats, dataSpace defines the color space of the image data.
+ * In addition, for some formats, dataSpace indicates whether image- or
+ * depth-based data is requested. See
+ * android.hardware.graphics.common@1.0::types for details of formats and
+ * valid dataSpace values for each format.
+ *
+ * The HAL must use this dataSpace to configure the stream to the correct
+ * colorspace, or to select between color and depth outputs if
+ * supported. The dataspace values are set using the V0 dataspace
+ * definitions.
+ */
+ DataspaceFlags dataSpace;
+
+ /**
+ * The required output rotation of the stream.
+ *
+ * This must be inspected by HAL along with stream width and height. For
+ * example, if the rotation is 90 degree and the stream width and height is
+ * 720 and 1280 respectively, camera service must supply buffers of size
+ * 720x1280, and HAL must capture a 1280x720 image and rotate the image by
+ * 90 degree counterclockwise. The rotation field must be ignored when the
+ * stream type is input.
+ *
+ * The HAL must inspect this field during stream configuration and return
+ * IllegalArgument if HAL cannot perform such rotation. HAL must always
+ * support ROTATION_0, so a configureStreams() call must not fail for
+ * unsupported rotation if rotation field of all streams is ROTATION_0.
+ *
+ */
+ StreamRotation rotation;
+
+};
+
+/**
+ * StreamConfiguration:
+ *
+ * A structure of stream definitions, used by configureStreams(). This
+ * structure defines all the output streams and the reprocessing input
+ * stream for the current camera use case.
+ */
+struct StreamConfiguration {
+ /**
+ * An array of camera stream pointers, defining the input/output
+ * configuration for the camera HAL device.
+ *
+ * At most one input-capable stream may be defined.
+ * At least one output-capable stream must be defined.
+ */
+ vec<Stream> streams;
+
+ /**
+ * The operation mode of streams in this configuration. The HAL can use this
+ * mode as an indicator to set the stream property (e.g.,
+ * HalStream::maxBuffers) appropriately. For example, if the
+ * configuration is
+ * CONSTRAINED_HIGH_SPEED_MODE, the HAL may
+ * want to set aside more buffers for batch mode operation (see
+ * android.control.availableHighSpeedVideoConfigurations for batch mode
+ * definition).
+ *
+ */
+ StreamConfigurationMode operationMode;
+
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * The HAL may specify the desired format, maximum buffers, and
+ * usage flags for each stream.
+ *
+ */
+struct HalStream {
+ /**
+ * Stream ID - a nonnegative integer identifier for a stream.
+ *
+ * The ID must be one of the stream IDs passed into configureStreams.
+ */
+ int32_t id;
+
+ /**
+ * An override pixel format for the buffers in this stream.
+ *
+ * The HAL must respect the requested format in Stream unless it is
+ * IMPLEMENTATION_DEFINED, in which case the override format here must be
+ * used by the client instead, for this stream. This allows cross-platform
+ * HALs to use a standard format since IMPLEMENTATION_DEFINED formats often
+ * require device-specific information. In all other cases, the
+ * overrideFormat must match the requested format.
+ *
+ * When HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED is used, then the platform
+ * gralloc module must select a format based on the usage flags provided by
+ * the camera device and the other endpoint of the stream.
+ */
+ android.hardware.graphics.common@1.0::PixelFormat overrideFormat;
+
+ /**
+ * The gralloc usage flags for this stream, as needed by the HAL.
+ *
+ * For output streams, these are the HAL's producer usage flags. For input
+ * streams, these are the HAL's consumer usage flags. The usage flags from
+ * the producer and the consumer must be combined together and then passed
+ * to the platform graphics allocator HAL for allocating the gralloc buffers
+ * for each stream.
+ *
+ * If the stream's type is INPUT, then producerUsage must be 0, and
+ * consumerUsage must be set. For other types, producerUsage must be set,
+ * and consumerUsage must be 0.
+ */
+ ProducerUsageFlags producerUsage;
+ ConsumerUsageFlags consumerUsage;
+
+ /**
+ * The maximum number of buffers the HAL device may need to have dequeued at
+ * the same time. The HAL device may not have more buffers in-flight from
+ * this stream than this value.
+ */
+ uint32_t maxBuffers;
+
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * A structure of stream definitions, returned by configureStreams(). This
+ * structure defines the HAL's desired parameters for each stream.
+ *
+ * All streams that were defined in the input to configureStreams() must have a
+ * corresponding entry in this structure when returned by configureStreams().
+ */
+struct HalStreamConfiguration {
+ vec<HalStream> streams;
+};
+
+/**
+ * BufferStatus:
+ *
+ * The current status of a single stream buffer.
+ */
+enum BufferStatus : uint32_t {
+ /**
+ * The buffer is in a normal state, and can be used after waiting on its
+ * sync fence.
+ */
+ OK = 0,
+
+ /**
+ * The buffer does not contain valid data, and the data in it must not be
+ * used. The sync fence must still be waited on before reusing the buffer.
+ */
+ ERROR = 1
+};
+
+/**
+ * StreamBuffer:
+ *
+ * A single buffer from a camera3 stream. It includes a handle to its parent
+ * stream, the handle to the gralloc buffer itself, and sync fences
+ *
+ * The buffer does not specify whether it is to be used for input or output;
+ * that is determined by its parent stream type and how the buffer is passed to
+ * the HAL device.
+ */
+struct StreamBuffer {
+ /**
+ * The ID of the stream this buffer is associated with. -1 indicates an
+ * invalid (empty) StreamBuffer, in which case buffer must also point to
+ * null and bufferId must be 0.
+ */
+ int32_t streamId;
+
+ /**
+ * The unique ID of the buffer within this StreamBuffer. 0 indicates this
+ * StreamBuffer contains no buffer.
+ * For StreamBuffers sent to the HAL in a CaptureRequest, this ID uniquely
+ * identifies a buffer. When a buffer is sent to HAL for the first time,
+ * both bufferId and buffer handle must be filled. HAL must keep track of
+ * the mapping between bufferId and corresponding buffer until the
+ * corresponding stream is removed from stream configuration or until camera
+ * device session is closed. After the first time a buffer is introduced to
+ * HAL, in the future camera service must refer to the same buffer using
+ * only bufferId, and keep the buffer handle null.
+ */
+ uint64_t bufferId;
+
+ /**
+ * The graphics buffer handle to the buffer.
+ *
+ * For StreamBuffers sent to the HAL in a CaptureRequest, if the bufferId
+ * is not seen by the HAL before, this buffer handle is guaranteed to be a
+ * valid handle to a graphics buffer, with dimensions and format matching
+ * that of the stream. If the bufferId has been sent to the HAL before, this
+ * buffer handle must be null and HAL must look up the actual buffer handle
+ * to use from its own bufferId to buffer handle map.
+ *
+ * For StreamBuffers returned in a CaptureResult, this must be null, since
+ * the handle to the buffer is already known to the client (since the client
+ * sent it in the matching CaptureRequest), and the handle can be identified
+ * by the combination of frame number and stream ID.
+ */
+ handle buffer;
+
+ /**
+ * Current state of the buffer. The framework must not pass buffers to the
+ * HAL that are in an error state. In case a buffer could not be filled by
+ * the HAL, it must have its status set to ERROR when returned to the
+ * framework with processCaptureResult().
+ */
+ BufferStatus status;
+
+ /**
+ * The acquire sync fence for this buffer. The HAL must wait on this fence
+ * fd before attempting to read from or write to this buffer.
+ *
+ * In a buffer included in a CaptureRequest, the client may set this to null
+ * to indicate that no waiting is necessary for this buffer.
+ *
+ * When the HAL returns an input or output buffer to the framework with
+ * processCaptureResult(), the acquireFence must be set to null. If the HAL
+ * never waits on the acquireFence due to an error in filling or reading a
+ * buffer, when calling processCaptureResult() the HAL must set the
+ * releaseFence of the buffer to be the acquireFence passed to it by the
+ * client. This allows the client to wait on the fence before reusing the
+ * buffer.
+ */
+ handle acquireFence;
+
+ /**
+ * The release sync fence for this buffer. The HAL must set this to a valid
+ * fence fd when returning the input buffer or output buffers to the client
+ * in a CaptureResult, or set it to null to indicate that no waiting is
+ * required for this buffer.
+ *
+ * The client must set this to be null for all buffers included in a
+ * processCaptureRequest call.
+ *
+ * After signaling the releaseFence for this buffer, the HAL
+ * must not make any further attempts to access this buffer as the
+ * ownership has been fully transferred back to the client.
+ *
+ * If this is null, then the ownership of this buffer is transferred back
+ * immediately upon the call of processCaptureResult.
+ */
+ handle releaseFence;
+
+};
+
+/**
+ * CameraBlob:
+ *
+ * Transport header for camera blob types; generally compressed JPEG buffers in
+ * output streams.
+ *
+ * To capture JPEG images, a stream is created using the pixel format
+ * HAL_PIXEL_FORMAT_BLOB and dataspace HAL_DATASPACE_V0_JFIF. The buffer size
+ * for the stream is calculated by the framework, based on the static metadata
+ * field android.jpeg.maxSize. Since compressed JPEG images are of variable
+ * size, the HAL needs to include the final size of the compressed image using
+ * this structure inside the output stream buffer. The camera blob ID field must
+ * be set to CameraBlobId::JPEG.
+ *
+ * The transport header must be at the end of the JPEG output stream
+ * buffer. That means the jpegBlobId must start at byte[buffer_size -
+ * sizeof(CameraBlob)], where the buffer_size is the size of gralloc
+ * buffer. Any HAL using this transport header must account for it in
+ * android.jpeg.maxSize. The JPEG data itself starts at the beginning of the
+ * buffer and must be blobSize bytes long.
+ */
+enum CameraBlobId : uint16_t {
+ JPEG = 0x00FF,
+};
+
+struct CameraBlob {
+ CameraBlobId blobId;
+
+ uint32_t blobSize;
+};
+
+/**
+ * MsgType:
+ *
+ * Indicates the type of message sent, which specifies which member of the
+ * message union is valid.
+ *
+ */
+enum MsgType : uint32_t {
+ /**
+ * An error has occurred. NotifyMsg::Message::Error contains the
+ * error information.
+ */
+ ERROR = 1,
+
+ /**
+ * The exposure of a given request or processing a reprocess request has
+ * begun. NotifyMsg::Message::Shutter contains the information
+ * the capture.
+ */
+ SHUTTER = 2
+};
+
+/**
+ * Defined error codes for MsgType::ERROR
+ */
+enum ErrorCode : uint32_t {
+ /**
+ * A serious failure occured. No further frames or buffer streams must
+ * be produced by the device. Device must be treated as closed. The
+ * client must reopen the device to use it again. The frameNumber field
+ * is unused.
+ */
+ ERROR_DEVICE = 1,
+
+ /**
+ * An error has occurred in processing a request. No output (metadata or
+ * buffers) must be produced for this request. The frameNumber field
+ * specifies which request has been dropped. Subsequent requests are
+ * unaffected, and the device remains operational.
+ */
+ ERROR_REQUEST = 2,
+
+ /**
+ * An error has occurred in producing an output result metadata buffer
+ * for a request, but output stream buffers for it must still be
+ * available. Subsequent requests are unaffected, and the device remains
+ * operational. The frameNumber field specifies the request for which
+ * result metadata won't be available.
+ */
+ ERROR_RESULT = 3,
+
+ /**
+ * An error has occurred in placing an output buffer into a stream for a
+ * request. The frame metadata and other buffers may still be
+ * available. Subsequent requests are unaffected, and the device remains
+ * operational. The frameNumber field specifies the request for which the
+ * buffer was dropped, and errorStreamId indicates the stream
+ * that dropped the frame.
+ */
+ ERROR_BUFFER = 4,
+};
+
+/**
+ * ErrorMsg:
+ *
+ * Message contents for MsgType::ERROR
+ */
+struct ErrorMsg {
+ /**
+ * Frame number of the request the error applies to. 0 if the frame number
+ * isn't applicable to the error.
+ */
+ uint32_t frameNumber;
+
+ /**
+ * Pointer to the stream that had a failure. -1 if the stream isn't
+ * applicable to the error.
+ */
+ int32_t errorStreamId;
+
+ /**
+ * The code for this error.
+ */
+ ErrorCode errorCode;
+
+};
+
+/**
+ * ShutterMsg:
+ *
+ * Message contents for MsgType::SHUTTER
+ */
+struct ShutterMsg {
+ /**
+ * Frame number of the request that has begun exposure or reprocessing.
+ */
+ uint32_t frameNumber;
+
+ /**
+ * Timestamp for the start of capture. For a reprocess request, this must
+ * be input image's start of capture. This must match the capture result
+ * metadata's sensor exposure start timestamp.
+ */
+ uint64_t timestamp;
+
+};
+
+/**
+ * NotifyMsg:
+ *
+ * The message structure sent to ICameraDevice3Callback::notify()
+ */
+struct NotifyMsg {
+ /**
+ * The message type.
+ */
+ MsgType type;
+
+ union Message {
+ /**
+ * Error message contents. Valid if type is MsgType::ERROR
+ */
+ ErrorMsg error;
+
+ /**
+ * Shutter message contents. Valid if type is MsgType::SHUTTER
+ */
+ ShutterMsg shutter;
+ } msg;
+
+};
+
+/**
+ * RequestTemplate:
+ *
+ * Available template types for
+ * ICameraDevice::constructDefaultRequestSettings()
+ */
+enum RequestTemplate : uint32_t {
+ /**
+ * Standard camera preview operation with 3A on auto.
+ */
+ PREVIEW = 1,
+
+ /**
+ * Standard camera high-quality still capture with 3A and flash on auto.
+ */
+ STILL_CAPTURE = 2,
+
+ /**
+ * Standard video recording plus preview with 3A on auto, torch off.
+ */
+ VIDEO_RECORD = 3,
+
+ /**
+ * High-quality still capture while recording video. Applications typically
+ * include preview, video record, and full-resolution YUV or JPEG streams in
+ * request. Must not cause stuttering on video stream. 3A on auto.
+ */
+ VIDEO_SNAPSHOT = 4,
+
+ /**
+ * Zero-shutter-lag mode. Application typically request preview and
+ * full-resolution data for each frame, and reprocess it to JPEG when a
+ * still image is requested by user. Settings must provide highest-quality
+ * full-resolution images without compromising preview frame rate. 3A on
+ * auto.
+ */
+ ZERO_SHUTTER_LAG = 5,
+
+ /**
+ * A basic template for direct application control of capture
+ * parameters. All automatic control is disabled (auto-exposure, auto-white
+ * balance, auto-focus), and post-processing parameters are set to preview
+ * quality. The manual capture parameters (exposure, sensitivity, etc.)
+ * are set to reasonable defaults, but may be overridden by the
+ * application depending on the intended use case.
+ */
+ MANUAL = 6,
+
+ /**
+ * First value for vendor-defined request templates
+ */
+ VENDOR_TEMPLATE_START = 0x40000000,
+
+};
+
+/**
+ * CaptureRequest:
+ *
+ * A single request for image capture/buffer reprocessing, sent to the Camera
+ * HAL device by the framework in processCaptureRequest().
+ *
+ * The request contains the settings to be used for this capture, and the set of
+ * output buffers to write the resulting image data in. It may optionally
+ * contain an input buffer, in which case the request is for reprocessing that
+ * input buffer instead of capturing a new image with the camera sensor. The
+ * capture is identified by the frameNumber.
+ *
+ * In response, the camera HAL device must send a CaptureResult
+ * structure asynchronously to the framework, using the processCaptureResult()
+ * callback.
+ */
+struct CaptureRequest {
+ /**
+ * The frame number is an incrementing integer set by the framework to
+ * uniquely identify this capture. It needs to be returned in the result
+ * call, and is also used to identify the request in asynchronous
+ * notifications sent to ICameraDevice3Callback::notify().
+ */
+ uint32_t frameNumber;
+
+ /**
+ * The settings buffer contains the capture and processing parameters for
+ * the request. As a special case, an empty settings buffer indicates that
+ * the settings are identical to the most-recently submitted capture
+ * request. A empty buffer cannot be used as the first submitted request
+ * after a configureStreams() call.
+ */
+ CameraMetadata settings;
+
+ /**
+ * The input stream buffer to use for this request, if any.
+ *
+ * An invalid inputBuffer is signified by a null inputBuffer::buffer, in
+ * which case the value of all other members of inputBuffer must be ignored.
+ *
+ * If inputBuffer is invalid, then the request is for a new capture from the
+ * imager. If inputBuffer is valid, the request is for reprocessing the
+ * image contained in inputBuffer, and the HAL must release the inputBuffer
+ * back to the client in a subsequent processCaptureResult call.
+ *
+ * The HAL is required to wait on the acquire sync fence of the input buffer
+ * before accessing it.
+ *
+ */
+ StreamBuffer inputBuffer;
+
+ /**
+ * An array of at least 1 stream buffers, to be filled with image
+ * data from this capture/reprocess. The HAL must wait on the acquire fences
+ * of each stream buffer before writing to them.
+ *
+ * The HAL takes ownership of the handles in outputBuffers; the client
+ * must not access them until they are returned in a CaptureResult.
+ *
+ * Any or all of the buffers included here may be brand new in this
+ * request (having never before seen by the HAL).
+ */
+ vec<StreamBuffer> outputBuffers;
+
+};
+
+/**
+ * CaptureResult:
+ *
+ * The result of a single capture/reprocess by the camera HAL device. This is
+ * sent to the framework asynchronously with processCaptureResult(), in
+ * response to a single capture request sent to the HAL with
+ * processCaptureRequest(). Multiple processCaptureResult() calls may be
+ * performed by the HAL for each request.
+ *
+ * Each call, all with the same frame
+ * number, may contain some subset of the output buffers, and/or the result
+ * metadata.
+ *
+ * The result structure contains the output metadata from this capture, and the
+ * set of output buffers that have been/will be filled for this capture. Each
+ * output buffer may come with a release sync fence that the framework must wait
+ * on before reading, in case the buffer has not yet been filled by the HAL.
+ *
+ * The metadata may be provided multiple times for a single frame number. The
+ * framework must accumulate together the final result set by combining each
+ * partial result together into the total result set.
+ *
+ * If an input buffer is given in a request, the HAL must return it in one of
+ * the processCaptureResult calls, and the call may be to just return the
+ * input buffer, without metadata and output buffers; the sync fences must be
+ * handled the same way they are done for output buffers.
+ *
+ * Performance considerations:
+ *
+ * Applications receive these partial results immediately, so sending partial
+ * results is a highly recommended performance optimization to avoid the total
+ * pipeline latency before sending the results for what is known very early on
+ * in the pipeline.
+ *
+ * A typical use case might be calculating the AF state halfway through the
+ * pipeline; by sending the state back to the framework immediately, we get a
+ * 50% performance increase and perceived responsiveness of the auto-focus.
+ *
+ */
+struct CaptureResult {
+ /**
+ * The frame number is an incrementing integer set by the framework in the
+ * submitted request to uniquely identify this capture. It is also used to
+ * identify the request in asynchronous notifications sent to
+ * ICameraDevice3Callback::notify().
+ */
+ uint32_t frameNumber;
+
+ /**
+ * The result metadata for this capture. This contains information about the
+ * final capture parameters, the state of the capture and post-processing
+ * hardware, the state of the 3A algorithms, if enabled, and the output of
+ * any enabled statistics units.
+ *
+ * If there was an error producing the result metadata, result must be an
+ * empty metadata buffer, and notify() must be called with
+ * ErrorCode::ERROR_RESULT.
+ *
+ * Multiple calls to processCaptureResult() with a given frameNumber
+ * may include (partial) result metadata.
+ *
+ * Partial metadata submitted must not include any metadata key returned
+ * in a previous partial result for a given frame. Each new partial result
+ * for that frame must also set a distinct partialResult value.
+ *
+ * If notify has been called with ErrorCode::ERROR_RESULT, all further
+ * partial results for that frame are ignored by the framework.
+ */
+ CameraMetadata result;
+
+ /**
+ * The completed output stream buffers for this capture.
+ *
+ * They may not yet be filled at the time the HAL calls
+ * processCaptureResult(); the framework must wait on the release sync
+ * fences provided by the HAL before reading the buffers.
+ *
+ * The StreamBuffer::buffer handle must be null for all returned buffers;
+ * the client must cache the handle and look it up via the combination of
+ * frame number and stream ID.
+ *
+ * The number of output buffers returned must be less than or equal to the
+ * matching capture request's count. If this is less than the buffer count
+ * in the capture request, at least one more call to processCaptureResult
+ * with the same frameNumber must be made, to return the remaining output
+ * buffers to the framework. This may only be zero if the structure includes
+ * valid result metadata or an input buffer is returned in this result.
+ *
+ * The HAL must set the stream buffer's release sync fence to a valid sync
+ * fd, or to null if the buffer has already been filled.
+ *
+ * If the HAL encounters an error while processing the buffer, and the
+ * buffer is not filled, the buffer's status field must be set to ERROR. If
+ * the HAL did not wait on the acquire fence before encountering the error,
+ * the acquire fence must be copied into the release fence, to allow the
+ * framework to wait on the fence before reusing the buffer.
+ *
+ * The acquire fence must be set to null for all output buffers.
+ *
+ * This vector may be empty; if so, at least one other processCaptureResult
+ * call must be made (or have been made) by the HAL to provide the filled
+ * output buffers.
+ *
+ * When processCaptureResult is called with a new buffer for a frame,
+ * all previous frames' buffers for that corresponding stream must have been
+ * already delivered (the fences need not have yet been signaled).
+ *
+ * Buffers for a frame may be sent to framework before the corresponding
+ * SHUTTER-notify call is made by the HAL.
+ *
+ * Performance considerations:
+ *
+ * Buffers delivered to the framework are not dispatched to the
+ * application layer until a start of exposure timestamp has been received
+ * via a SHUTTER notify() call. It is highly recommended to
+ * dispatch that call as early as possible.
+ */
+ vec<StreamBuffer> outputBuffers;
+
+ /**
+ * The handle for the input stream buffer for this capture, if any.
+ *
+ * It may not yet be consumed at the time the HAL calls
+ * processCaptureResult(); the framework must wait on the release sync fence
+ * provided by the HAL before reusing the buffer.
+ *
+ * The HAL must handle the sync fences the same way they are done for
+ * outputBuffers.
+ *
+ * Only one input buffer is allowed to be sent per request. Similarly to
+ * output buffers, the ordering of returned input buffers must be
+ * maintained by the HAL.
+ *
+ * Performance considerations:
+ *
+ * The input buffer should be returned as early as possible. If the HAL
+ * supports sync fences, it can call processCaptureResult to hand it back
+ * with sync fences being set appropriately. If the sync fences are not
+ * supported, the buffer can only be returned when it is consumed, which
+ * may take long time; the HAL may choose to copy this input buffer to make
+ * the buffer return sooner.
+ */
+ StreamBuffer inputBuffer;
+
+ /**
+ * In order to take advantage of partial results, the HAL must set the
+ * static metadata android.request.partialResultCount to the number of
+ * partial results it sends for each frame.
+ *
+ * Each new capture result with a partial result must set
+ * this field to a distinct inclusive value between
+ * 1 and android.request.partialResultCount.
+ *
+ * HALs not wishing to take advantage of this feature must not
+ * set an android.request.partialResultCount or partial_result to a value
+ * other than 1.
+ *
+ * This value must be set to 0 when a capture result contains buffers only
+ * and no metadata.
+ */
+ uint32_t partialResult;
+
+};
diff --git a/camera/device/README.md b/camera/device/README.md
new file mode 100644
index 0000000..6e5703a
--- /dev/null
+++ b/camera/device/README.md
@@ -0,0 +1,76 @@
+## Camera Device HAL ##
+---
+
+## Overview: ##
+
+The camera.device HAL interface is used by the Android camera service to operate
+individual camera devices. Instances of camera.device HAL interface can be obtained
+via one of the ICameraProvider::getCameraDeviceInterface_V<N>_x() methods, where N
+is the major version of the camera device interface.
+
+Obtaining the device interface does not turn on the respective camera device;
+each camera device interface has an actual open() method to begin an active
+camera session. Without invoking open(), the interface can be used for querying
+camera static information.
+
+More complete information about the Android camera HAL and subsystem can be found at
+[source.android.com](http://source.android.com/devices/camera/index.html).
+
+## Version history: ##
+
+### ICameraDevice.hal@1.0:
+
+HIDL version of the legacy camera device HAL. Intended as a shim for devices
+needing to use the deprecated pre-HIDL camera device HAL v1.0.
+
+May be used in HIDL passthrough mode for devices upgrading to the Android O
+release; must be used in binderized mode for devices launching in the O release.
+
+It is strongly recommended to not use this interface for new devices, as new
+devices may not use this interface starting with the Android P release, and all
+support for ICameraDevice@1.0 will be removed with the Android R release.
+
+This HAL interface version only allows support at the LEGACY level for the
+android.hardware.camera2 API.
+
+Subsidiary HALs:
+
+#### ICameraDevice1PreviewCallback.hal@1.0:
+
+Callback interface for obtaining, filling, and returning graphics buffers for
+preview operation with the ICameraDevice@1.0 inteface.
+
+#### ICameraDevice1Callback.hal@1.0:
+
+Callback interface for sending events and data buffers from the HAL to the
+camera service.
+
+### ICameraDevice.hal@3.2:
+
+HIDL version of the baseline camera device HAL, required for LIMITED or FULL
+operation through the android.hardware.camera2 API.
+
+The main HAL contains methods for static queries about the device, similar to
+the HALv3-specific sections of the legacy camera module HAL. Simply obtaining an
+instance of the camera device interface does not turn on the camera device.
+
+May be used in passthrough mode for devices upgrading to the Android O release;
+must be used in binderized mode for all new devices launching with Android O or
+later.
+
+The open() method actually opens the camera device for use, returning a Session
+interface for operating the active camera. It takes a Callback interface as an
+argument.
+
+Subsidiary HALs:
+
+#### ICameraDevice3Session.hal@3.2:
+
+Closely matches the features and operation of the pre-HIDL camera device HAL
+v3.2, containing methods for configuring an active camera device and submitting
+capture requests to it.
+
+#### ICameraDevice3Callback.hal@3.2:
+
+Callback interface for sending completed captures and other asynchronous events
+from tehe HAL to the client.
diff --git a/camera/metadata/3.2/Android.bp b/camera/metadata/3.2/Android.bp
new file mode 100644
index 0000000..1e464d6
--- /dev/null
+++ b/camera/metadata/3.2/Android.bp
@@ -0,0 +1,53 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.camera.metadata@3.2_hal",
+ srcs: [
+ "types.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.metadata@3.2_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.metadata@3.2",
+ srcs: [
+ ":android.hardware.camera.metadata@3.2_hal",
+ ],
+ out: [
+ "android/hardware/camera/metadata/3.2/types.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.metadata@3.2_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.metadata@3.2",
+ srcs: [
+ ":android.hardware.camera.metadata@3.2_hal",
+ ],
+ out: [
+ "android/hardware/camera/metadata/3.2/types.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.metadata@3.2",
+ generated_sources: ["android.hardware.camera.metadata@3.2_genc++"],
+ generated_headers: ["android.hardware.camera.metadata@3.2_genc++_headers"],
+ export_generated_headers: ["android.hardware.camera.metadata@3.2_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+}
diff --git a/camera/metadata/3.2/Android.mk b/camera/metadata/3.2/Android.mk
new file mode 100644
index 0000000..86cee91
--- /dev/null
+++ b/camera/metadata/3.2/Android.mk
@@ -0,0 +1,2462 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.camera.metadata@3.2-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidBlackLevelLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidBlackLevelLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidBlackLevelLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidColorCorrectionAberrationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionAberrationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionAberrationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidColorCorrectionMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeAntibandingMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeAntibandingMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeAntibandingMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeLockAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLockAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLockAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAePrecaptureTrigger)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAePrecaptureTrigger.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAePrecaptureTrigger
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfTrigger)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfTrigger.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfTrigger
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbLockAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLockAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLockAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlCaptureIntent)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlCaptureIntent.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlCaptureIntent
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlEffectMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEffectMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEffectMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlEnableZsl)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEnableZsl.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEnableZsl
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlSceneMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlSceneMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlSceneMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlVideoStabilizationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlVideoStabilizationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlVideoStabilizationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDemosaicMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDemosaicMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDemosaicMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDepthDepthIsExclusive)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthDepthIsExclusive.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthDepthIsExclusive
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidEdgeMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidEdgeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidEdgeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashInfoAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashInfoAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashInfoAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidHotPixelMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidHotPixelMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidHotPixelMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidInfoSupportedHardwareLevel)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidInfoSupportedHardwareLevel.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidInfoSupportedHardwareLevel
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLedAvailableLeds)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedAvailableLeds.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedAvailableLeds
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLedTransmit)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedTransmit.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedTransmit
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensFacing)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensFacing.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensFacing
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensOpticalStabilizationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensOpticalStabilizationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensOpticalStabilizationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidNoiseReductionMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidNoiseReductionMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidNoiseReductionMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidQuirksPartialResult)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidQuirksPartialResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidQuirksPartialResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestAvailableCapabilities)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestAvailableCapabilities.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestAvailableCapabilities
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestMetadataMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestMetadataMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestMetadataMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestType)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerAvailableFormats)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableFormats.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableFormats
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerAvailableStreamConfigurations)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableStreamConfigurations.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableStreamConfigurations
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerCroppingType)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerCroppingType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerCroppingType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoColorFilterArrangement)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoColorFilterArrangement.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoColorFilterArrangement
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoLensShadingApplied)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoLensShadingApplied.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoLensShadingApplied
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoTimestampSource)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoTimestampSource.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoTimestampSource
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorReferenceIlluminant1)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorReferenceIlluminant1.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorReferenceIlluminant1
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorTestPatternMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorTestPatternMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorTestPatternMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidShadingMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidShadingMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidShadingMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsFaceDetectMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsFaceDetectMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsFaceDetectMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsHistogramMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHistogramMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHistogramMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsHotPixelMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHotPixelMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHotPixelMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsLensShadingMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsLensShadingMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsLensShadingMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsSceneFlicker)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSceneFlicker.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSceneFlicker
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsSharpnessMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSharpnessMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSharpnessMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSyncFrameNumber)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncFrameNumber.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncFrameNumber
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSyncMaxLatency)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncMaxLatency.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncMaxLatency
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidTonemapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidTonemapPresetCurve)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapPresetCurve.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapPresetCurve
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataSection)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataSection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataSectionStart)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSectionStart.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataSectionStart
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataTag)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataTag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataTag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.camera.metadata@3.2-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidBlackLevelLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidBlackLevelLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidBlackLevelLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidColorCorrectionAberrationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionAberrationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionAberrationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidColorCorrectionMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeAntibandingMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeAntibandingMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeAntibandingMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeLockAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLockAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLockAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAePrecaptureTrigger)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAePrecaptureTrigger.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAePrecaptureTrigger
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAeState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAfTrigger)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfTrigger.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfTrigger
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbLock)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLock.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLock
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbLockAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLockAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLockAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlAwbState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlCaptureIntent)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlCaptureIntent.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlCaptureIntent
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlEffectMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEffectMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEffectMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlEnableZsl)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEnableZsl.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEnableZsl
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlSceneMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlSceneMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlSceneMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidControlVideoStabilizationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlVideoStabilizationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlVideoStabilizationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDemosaicMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDemosaicMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDemosaicMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidDepthDepthIsExclusive)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthDepthIsExclusive.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthDepthIsExclusive
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidEdgeMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidEdgeMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidEdgeMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashInfoAvailable)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashInfoAvailable.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashInfoAvailable
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidFlashState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidHotPixelMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidHotPixelMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidHotPixelMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidInfoSupportedHardwareLevel)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidInfoSupportedHardwareLevel.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidInfoSupportedHardwareLevel
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLedAvailableLeds)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedAvailableLeds.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedAvailableLeds
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLedTransmit)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedTransmit.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedTransmit
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensFacing)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensFacing.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensFacing
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensOpticalStabilizationMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensOpticalStabilizationMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensOpticalStabilizationMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidLensState)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidNoiseReductionMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidNoiseReductionMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidNoiseReductionMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidQuirksPartialResult)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidQuirksPartialResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidQuirksPartialResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestAvailableCapabilities)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestAvailableCapabilities.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestAvailableCapabilities
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestMetadataMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestMetadataMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestMetadataMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidRequestType)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerAvailableFormats)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableFormats.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableFormats
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerAvailableStreamConfigurations)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableStreamConfigurations.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableStreamConfigurations
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidScalerCroppingType)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerCroppingType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerCroppingType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoColorFilterArrangement)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoColorFilterArrangement.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoColorFilterArrangement
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoLensShadingApplied)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoLensShadingApplied.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoLensShadingApplied
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorInfoTimestampSource)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoTimestampSource.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoTimestampSource
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorReferenceIlluminant1)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorReferenceIlluminant1.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorReferenceIlluminant1
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSensorTestPatternMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorTestPatternMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorTestPatternMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidShadingMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidShadingMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidShadingMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsFaceDetectMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsFaceDetectMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsFaceDetectMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsHistogramMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHistogramMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHistogramMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsHotPixelMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHotPixelMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHotPixelMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsLensShadingMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsLensShadingMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsLensShadingMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsSceneFlicker)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSceneFlicker.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSceneFlicker
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidStatisticsSharpnessMapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSharpnessMapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSharpnessMapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSyncFrameNumber)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncFrameNumber.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncFrameNumber
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidSyncMaxLatency)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncMaxLatency.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncMaxLatency
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidTonemapMode)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataEnumAndroidTonemapPresetCurve)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapPresetCurve.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapPresetCurve
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataSection)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSection.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataSection
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataSectionStart)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSectionStart.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataSectionStart
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CameraMetadataTag)
+#
+GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataTag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.camera.metadata@3.2::types.CameraMetadataTag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/camera/metadata/3.2/docs.html b/camera/metadata/3.2/docs.html
new file mode 100644
index 0000000..004ecae
--- /dev/null
+++ b/camera/metadata/3.2/docs.html
@@ -0,0 +1,27340 @@
+<!DOCTYPE html>
+<html>
+<!-- Copyright (C) 2012 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.
+-->
+<head>
+ <!-- automatically generated from html.mako. do NOT edit directly -->
+ <meta charset="utf-8" />
+ <title>Android Camera HAL3.4 Properties</title>
+ <style type="text/css">
+ body { background-color: #f7f7f7; font-family: Roboto, sans-serif;}
+ h1 { color: #333333; }
+ h2 { color: #333333; }
+ a:link { color: #258aaf; text-decoration: none}
+ a:hover { color: #459aaf; text-decoration: underline }
+ a:visited { color: #154a5f; text-decoration: none}
+ .section { color: #eeeeee; font-size: 1.5em; font-weight: bold; background-color: #888888; padding: 0.5em 0em 0.5em 0.5em; border-width: thick thin thin thin; border-color: #111111 #777777 #777777 #777777}
+ .kind { color: #eeeeee; font-size: 1.2em; font-weight: bold; padding-left: 1.5em; background-color: #aaaaaa }
+ .entry { background-color: #f0f0f0 }
+ .entry_cont { background-color: #f0f0f0 }
+ .entries_header { background-color: #dddddd; text-align: center}
+
+ /* toc style */
+ .toc_section_header { font-size:1.3em; }
+ .toc_kind_header { font-size:1.2em; }
+ .toc_deprecated { text-decoration:line-through; }
+
+ /* table column sizes */
+ table { border-collapse:collapse; table-layout: fixed; width: 100%; word-wrap: break-word }
+ td,th { border: 1px solid; border-color: #aaaaaa; padding-left: 0.5em; padding-right: 0.5em }
+ .th_name { width: 20% }
+ .th_units { width: 10% }
+ .th_tags { width: 5% }
+ .th_details { width: 25% }
+ .th_type { width: 20% }
+ .th_description { width: 20% }
+ .th_range { width: 10% }
+ td { font-size: 0.9em; }
+
+ /* hide the first thead, we need it there only to enforce column sizes */
+ .thead_dummy { visibility: hidden; }
+
+ /* Entry flair */
+ .entry_name { color: #333333; padding-left:1.0em; font-size:1.1em; font-family: monospace; vertical-align:top; }
+ .entry_name_deprecated { text-decoration:line-through; }
+
+ /* Entry type flair */
+ .entry_type_name { font-size:1.1em; color: #669900; font-weight: bold;}
+ .entry_type_name_enum:after { color: #669900; font-weight: bold; content:" (enum)" }
+ .entry_type_visibility { font-weight: bolder; padding-left:1em}
+ .entry_type_synthetic { font-weight: bolder; color: #996600; }
+ .entry_type_hwlevel { font-weight: bolder; color: #000066; }
+ .entry_type_deprecated { font-weight: bolder; color: #4D4D4D; }
+ .entry_type_enum_name { font-family: monospace; font-weight: bolder; }
+ .entry_type_enum_notes:before { content:" - " }
+ .entry_type_enum_notes>p:first-child { display:inline; }
+ .entry_type_enum_value:before { content:" = " }
+ .entry_type_enum_value { font-family: monospace; }
+ .entry ul { margin: 0 0 0 0; list-style-position: inside; padding-left: 0.5em; }
+ .entry ul li { padding: 0 0 0 0; margin: 0 0 0 0;}
+ .entry_range_deprecated { font-weight: bolder; }
+
+ /* Entry tags flair */
+ .entry_tags ul { list-style-type: none; }
+
+ /* Entry details (full docs) flair */
+ .entry_details_header { font-weight: bold; background-color: #dddddd;
+ text-align: center; font-size: 1.1em; margin-left: 0em; margin-right: 0em; }
+
+ /* Entry spacer flair */
+ .entry_spacer { background-color: transparent; border-style: none; height: 0.5em; }
+
+ /* TODO: generate abbr element for each tag link? */
+ /* TODO for each x.y.z try to link it to the entry */
+
+ </style>
+
+ <style>
+
+ {
+ /* broken...
+ supposedly there is a bug in chrome that it lays out tables before
+ it knows its being printed, so the page-break-* styles are ignored
+ */
+ tr { page-break-after: always; page-break-inside: avoid; }
+ }
+
+ </style>
+</head>
+
+
+
+<body>
+ <h1>Android Camera HAL3.2 Properties</h1>
+
+
+ <h2>Table of Contents</h2>
+ <ul class="toc">
+ <li><a href="#tag_index" class="toc_section_header">Tags</a></li>
+ <li>
+ <span class="toc_section_header"><a href="#section_colorCorrection">colorCorrection</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.colorCorrection.mode">android.colorCorrection.mode</a></li>
+ <li
+ ><a href="#controls_android.colorCorrection.transform">android.colorCorrection.transform</a></li>
+ <li
+ ><a href="#controls_android.colorCorrection.gains">android.colorCorrection.gains</a></li>
+ <li
+ ><a href="#controls_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.colorCorrection.mode">android.colorCorrection.mode</a></li>
+ <li
+ ><a href="#dynamic_android.colorCorrection.transform">android.colorCorrection.transform</a></li>
+ <li
+ ><a href="#dynamic_android.colorCorrection.gains">android.colorCorrection.gains</a></li>
+ <li
+ ><a href="#dynamic_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_control">control</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li>
+ <li
+ ><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li>
+ <li
+ ><a href="#controls_android.control.aeLock">android.control.aeLock</a></li>
+ <li
+ ><a href="#controls_android.control.aeMode">android.control.aeMode</a></li>
+ <li
+ ><a href="#controls_android.control.aeRegions">android.control.aeRegions</a></li>
+ <li
+ ><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li>
+ <li
+ ><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li>
+ <li
+ ><a href="#controls_android.control.afMode">android.control.afMode</a></li>
+ <li
+ ><a href="#controls_android.control.afRegions">android.control.afRegions</a></li>
+ <li
+ ><a href="#controls_android.control.afTrigger">android.control.afTrigger</a></li>
+ <li
+ ><a href="#controls_android.control.awbLock">android.control.awbLock</a></li>
+ <li
+ ><a href="#controls_android.control.awbMode">android.control.awbMode</a></li>
+ <li
+ ><a href="#controls_android.control.awbRegions">android.control.awbRegions</a></li>
+ <li
+ ><a href="#controls_android.control.captureIntent">android.control.captureIntent</a></li>
+ <li
+ ><a href="#controls_android.control.effectMode">android.control.effectMode</a></li>
+ <li
+ ><a href="#controls_android.control.mode">android.control.mode</a></li>
+ <li
+ ><a href="#controls_android.control.sceneMode">android.control.sceneMode</a></li>
+ <li
+ ><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
+ <li
+ ><a href="#controls_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a></li>
+ <li
+ ><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a></li>
+ <li
+ ><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a></li>
+ <li
+ ><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a></li>
+ <li
+ ><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a></li>
+ <li
+ ><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a></li>
+ <li
+ ><a href="#static_android.control.availableEffects">android.control.availableEffects</a></li>
+ <li
+ ><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a></li>
+ <li
+ ><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a></li>
+ <li
+ ><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a></li>
+ <li
+ ><a href="#static_android.control.maxRegions">android.control.maxRegions</a></li>
+ <li
+ ><a href="#static_android.control.maxRegionsAe">android.control.maxRegionsAe</a></li>
+ <li
+ ><a href="#static_android.control.maxRegionsAwb">android.control.maxRegionsAwb</a></li>
+ <li
+ ><a href="#static_android.control.maxRegionsAf">android.control.maxRegionsAf</a></li>
+ <li
+ ><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a></li>
+ <li
+ ><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a></li>
+ <li
+ ><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a></li>
+ <li
+ ><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a></li>
+ <li
+ ><a href="#static_android.control.availableModes">android.control.availableModes</a></li>
+ <li
+ ><a href="#static_android.control.postRawSensitivityBoostRange">android.control.postRawSensitivityBoostRange</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.control.aePrecaptureId">android.control.aePrecaptureId</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeLock">android.control.aeLock</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeMode">android.control.aeMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeRegions">android.control.aeRegions</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li>
+ <li
+ ><a href="#dynamic_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li>
+ <li
+ ><a href="#dynamic_android.control.aeState">android.control.aeState</a></li>
+ <li
+ ><a href="#dynamic_android.control.afMode">android.control.afMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.afRegions">android.control.afRegions</a></li>
+ <li
+ ><a href="#dynamic_android.control.afTrigger">android.control.afTrigger</a></li>
+ <li
+ ><a href="#dynamic_android.control.afState">android.control.afState</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.control.afTriggerId">android.control.afTriggerId</a></li>
+ <li
+ ><a href="#dynamic_android.control.awbLock">android.control.awbLock</a></li>
+ <li
+ ><a href="#dynamic_android.control.awbMode">android.control.awbMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.awbRegions">android.control.awbRegions</a></li>
+ <li
+ ><a href="#dynamic_android.control.captureIntent">android.control.captureIntent</a></li>
+ <li
+ ><a href="#dynamic_android.control.awbState">android.control.awbState</a></li>
+ <li
+ ><a href="#dynamic_android.control.effectMode">android.control.effectMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.mode">android.control.mode</a></li>
+ <li
+ ><a href="#dynamic_android.control.sceneMode">android.control.sceneMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
+ <li
+ ><a href="#dynamic_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_demosaic">demosaic</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.demosaic.mode">android.demosaic.mode</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_edge">edge</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.edge.mode">android.edge.mode</a></li>
+ <li
+ ><a href="#controls_android.edge.strength">android.edge.strength</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.edge.mode">android.edge.mode</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_flash">flash</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.flash.firingPower">android.flash.firingPower</a></li>
+ <li
+ ><a href="#controls_android.flash.firingTime">android.flash.firingTime</a></li>
+ <li
+ ><a href="#controls_android.flash.mode">android.flash.mode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+
+ <li
+ ><a href="#static_android.flash.info.available">android.flash.info.available</a></li>
+ <li
+ ><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a></li>
+
+ <li
+ ><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a></li>
+ <li
+ ><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.flash.firingPower">android.flash.firingPower</a></li>
+ <li
+ ><a href="#dynamic_android.flash.firingTime">android.flash.firingTime</a></li>
+ <li
+ ><a href="#dynamic_android.flash.mode">android.flash.mode</a></li>
+ <li
+ ><a href="#dynamic_android.flash.state">android.flash.state</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_hotPixel">hotPixel</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_jpeg">jpeg</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li>
+ <li
+ ><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li>
+ <li
+ ><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li>
+ <li
+ ><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li>
+ <li
+ ><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a></li>
+ <li
+ ><a href="#controls_android.jpeg.quality">android.jpeg.quality</a></li>
+ <li
+ ><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li>
+ <li
+ ><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a></li>
+ <li
+ ><a href="#static_android.jpeg.maxSize">android.jpeg.maxSize</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.orientation">android.jpeg.orientation</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.quality">android.jpeg.quality</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.size">android.jpeg.size</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li>
+ <li
+ ><a href="#dynamic_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_lens">lens</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.lens.aperture">android.lens.aperture</a></li>
+ <li
+ ><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a></li>
+ <li
+ ><a href="#controls_android.lens.focalLength">android.lens.focalLength</a></li>
+ <li
+ ><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a></li>
+ <li
+ ><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+
+ <li
+ ><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a></li>
+ <li
+ ><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a></li>
+ <li
+ ><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a></li>
+ <li
+ ><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a></li>
+ <li
+ ><a href="#static_android.lens.info.hyperfocalDistance">android.lens.info.hyperfocalDistance</a></li>
+ <li
+ ><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a></li>
+ <li
+ ><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a></li>
+ <li
+ ><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a></li>
+
+ <li
+ ><a href="#static_android.lens.facing">android.lens.facing</a></li>
+ <li
+ ><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a></li>
+ <li
+ ><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a></li>
+ <li
+ ><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li>
+ <li
+ ><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.lens.aperture">android.lens.aperture</a></li>
+ <li
+ ><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a></li>
+ <li
+ ><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a></li>
+ <li
+ ><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a></li>
+ <li
+ ><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a></li>
+ <li
+ ><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li>
+ <li
+ ><a href="#dynamic_android.lens.state">android.lens.state</a></li>
+ <li
+ ><a href="#dynamic_android.lens.poseRotation">android.lens.poseRotation</a></li>
+ <li
+ ><a href="#dynamic_android.lens.poseTranslation">android.lens.poseTranslation</a></li>
+ <li
+ ><a href="#dynamic_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li>
+ <li
+ ><a href="#dynamic_android.lens.radialDistortion">android.lens.radialDistortion</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_noiseReduction">noiseReduction</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a></li>
+ <li
+ ><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_quirks">quirks</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.quirks.meteringCropRegion">android.quirks.meteringCropRegion</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.quirks.triggerAfWithAuto">android.quirks.triggerAfWithAuto</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.quirks.useZslFormat">android.quirks.useZslFormat</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.quirks.usePartialResult">android.quirks.usePartialResult</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.quirks.partialResult">android.quirks.partialResult</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_request">request</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#controls_android.request.frameCount">android.request.frameCount</a></li>
+ <li
+ ><a href="#controls_android.request.id">android.request.id</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#controls_android.request.inputStreams">android.request.inputStreams</a></li>
+ <li
+ ><a href="#controls_android.request.metadataMode">android.request.metadataMode</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#controls_android.request.outputStreams">android.request.outputStreams</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#controls_android.request.type">android.request.type</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a></li>
+ <li
+ ><a href="#static_android.request.maxNumOutputRaw">android.request.maxNumOutputRaw</a></li>
+ <li
+ ><a href="#static_android.request.maxNumOutputProc">android.request.maxNumOutputProc</a></li>
+ <li
+ ><a href="#static_android.request.maxNumOutputProcStalling">android.request.maxNumOutputProcStalling</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a></li>
+ <li
+ ><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a></li>
+ <li
+ ><a href="#static_android.request.pipelineMaxDepth">android.request.pipelineMaxDepth</a></li>
+ <li
+ ><a href="#static_android.request.partialResultCount">android.request.partialResultCount</a></li>
+ <li
+ ><a href="#static_android.request.availableCapabilities">android.request.availableCapabilities</a></li>
+ <li
+ ><a href="#static_android.request.availableRequestKeys">android.request.availableRequestKeys</a></li>
+ <li
+ ><a href="#static_android.request.availableResultKeys">android.request.availableResultKeys</a></li>
+ <li
+ ><a href="#static_android.request.availableCharacteristicsKeys">android.request.availableCharacteristicsKeys</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.request.frameCount">android.request.frameCount</a></li>
+ <li
+ ><a href="#dynamic_android.request.id">android.request.id</a></li>
+ <li
+ ><a href="#dynamic_android.request.metadataMode">android.request.metadataMode</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.request.outputStreams">android.request.outputStreams</a></li>
+ <li
+ ><a href="#dynamic_android.request.pipelineDepth">android.request.pipelineDepth</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_scaler">scaler</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a></li>
+ <li
+ ><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#static_android.scaler.availableRawSizes">android.scaler.availableRawSizes</a></li>
+ <li
+ ><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a></li>
+ <li
+ ><a href="#static_android.scaler.availableStreamConfigurations">android.scaler.availableStreamConfigurations</a></li>
+ <li
+ ><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a></li>
+ <li
+ ><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a></li>
+ <li
+ ><a href="#static_android.scaler.streamConfigurationMap">android.scaler.streamConfigurationMap</a></li>
+ <li
+ ><a href="#static_android.scaler.croppingType">android.scaler.croppingType</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.scaler.cropRegion">android.scaler.cropRegion</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_sensor">sensor</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a></li>
+ <li
+ ><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a></li>
+ <li
+ ><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a></li>
+ <li
+ ><a href="#controls_android.sensor.testPatternData">android.sensor.testPatternData</a></li>
+ <li
+ ><a href="#controls_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+
+ <li
+ ><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a></li>
+ <li
+ ><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a></li>
+ <li
+ ><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a></li>
+ <li
+ ><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a></li>
+ <li
+ ><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a></li>
+ <li
+ ><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a></li>
+ <li
+ ><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a></li>
+ <li
+ ><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a></li>
+ <li
+ ><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a></li>
+ <li
+ ><a href="#static_android.sensor.info.lensShadingApplied">android.sensor.info.lensShadingApplied</a></li>
+ <li
+ ><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a></li>
+
+ <li
+ ><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a></li>
+ <li
+ ><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a></li>
+ <li
+ ><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a></li>
+ <li
+ ><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a></li>
+ <li
+ ><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a></li>
+ <li
+ ><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a></li>
+ <li
+ ><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a></li>
+ <li
+ ><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a></li>
+ <li
+ ><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a></li>
+ <li
+ ><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a></li>
+ <li
+ ><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a></li>
+ <li
+ ><a href="#static_android.sensor.orientation">android.sensor.orientation</a></li>
+ <li
+ ><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a></li>
+ <li
+ ><a href="#static_android.sensor.availableTestPatternModes">android.sensor.availableTestPatternModes</a></li>
+ <li
+ ><a href="#static_android.sensor.opticalBlackRegions">android.sensor.opticalBlackRegions</a></li>
+ <li
+ ><a href="#static_android.sensor.opaqueRawSize">android.sensor.opaqueRawSize</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.sensor.exposureTime">android.sensor.exposureTime</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.frameDuration">android.sensor.frameDuration</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.sensitivity">android.sensor.sensitivity</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.testPatternData">android.sensor.testPatternData</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a></li>
+ <li
+ ><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_shading">shading</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.shading.mode">android.shading.mode</a></li>
+ <li
+ ><a href="#controls_android.shading.strength">android.shading.strength</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.shading.mode">android.shading.mode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.shading.availableModes">android.shading.availableModes</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_statistics">statistics</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li>
+ <li
+ ><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a></li>
+ <li
+ ><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li>
+ <li
+ ><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li>
+ <li
+ ><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+
+ <li
+ ><a href="#static_android.statistics.info.availableFaceDetectModes">android.statistics.info.availableFaceDetectModes</a></li>
+ <li
+ ><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a></li>
+ <li
+ ><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a></li>
+ <li
+ ><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a></li>
+ <li
+ ><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a></li>
+ <li
+ ><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a></li>
+ <li
+ ><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a></li>
+ <li
+ ><a href="#static_android.statistics.info.availableLensShadingMapModes">android.statistics.info.availableLensShadingMapModes</a></li>
+
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.faces">android.statistics.faces</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.histogramMode">android.statistics.histogramMode</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.statistics.lensShadingCorrectionMap</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensShadingMap">android.statistics.lensShadingMap</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.statistics.predictedColorGains">android.statistics.predictedColorGains</a></li>
+ <li
+ class="toc_deprecated"
+ ><a href="#dynamic_android.statistics.predictedColorTransform">android.statistics.predictedColorTransform</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.sceneFlicker">android.statistics.sceneFlicker</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_tonemap">tonemap</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li>
+ <li
+ ><a href="#controls_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li>
+ <li
+ ><a href="#controls_android.tonemap.curveRed">android.tonemap.curveRed</a></li>
+ <li
+ ><a href="#controls_android.tonemap.curve">android.tonemap.curve</a></li>
+ <li
+ ><a href="#controls_android.tonemap.mode">android.tonemap.mode</a></li>
+ <li
+ ><a href="#controls_android.tonemap.gamma">android.tonemap.gamma</a></li>
+ <li
+ ><a href="#controls_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.tonemap.maxCurvePoints">android.tonemap.maxCurvePoints</a></li>
+ <li
+ ><a href="#static_android.tonemap.availableToneMapModes">android.tonemap.availableToneMapModes</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.curveRed">android.tonemap.curveRed</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.curve">android.tonemap.curve</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.mode">android.tonemap.mode</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.gamma">android.tonemap.gamma</a></li>
+ <li
+ ><a href="#dynamic_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_led">led</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.led.transmit">android.led.transmit</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.led.transmit">android.led.transmit</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.led.availableLeds">android.led.availableLeds</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_info">info</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.info.supportedHardwareLevel">android.info.supportedHardwareLevel</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_blackLevel">blackLevel</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.blackLevel.lock">android.blackLevel.lock</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_sync">sync</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_reprocess">reprocess</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">controls</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">dynamic</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#dynamic_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li>
+ </ul>
+ </li>
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ <li>
+ <span class="toc_section_header"><a href="#section_depth">depth</a></span>
+ <ul class="toc_section">
+ <li>
+ <span class="toc_kind_header">static</span>
+ <ul class="toc_section">
+ <li
+ ><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a></li>
+ <li
+ ><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a></li>
+ <li
+ ><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a></li>
+ <li
+ ><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a></li>
+ <li
+ ><a href="#static_android.depth.depthIsExclusive">android.depth.depthIsExclusive</a></li>
+ </ul>
+ </li>
+ </ul> <!-- toc_section -->
+ </li>
+ </ul>
+
+
+ <h1>Properties</h1>
+ <table class="properties">
+
+ <thead class="thead_dummy">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead> <!-- so that the first occurrence of thead is not
+ above the first occurrence of tr -->
+<!-- <namespace name="android"> -->
+ <tr><td colspan="6" id="section_colorCorrection" class="section">colorCorrection</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.colorCorrection.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>color<wbr/>Correction.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">TRANSFORM_MATRIX</span>
+ <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p>
+<p>All advanced white balance adjustments (not specified
+by our white balance pipeline) must be disabled.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override
+this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Color correction processing must not slow down
+capture rate relative to sensor raw output.<wbr/></p>
+<p>Advanced white balance adjustments above and beyond
+the specified white balance pipeline may be applied.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+the camera device uses the last frame's AWB values
+(or defaults if AWB has never been run).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Color correction processing operates at improved
+quality but the capture rate might be reduced (relative to sensor
+raw output rate)</p>
+<p>Advanced white balance adjustments above and beyond
+the specified white balance pipeline may be applied.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+the camera device uses the last frame's AWB values
+(or defaults if AWB has never been run).<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The mode control selects how the image data is converted from the
+sensor's native color into linear sRGB color.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this
+control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the
+application controls how the color mapping is performed.<wbr/></p>
+<p>We define the expected processing pipeline below.<wbr/> For consistency
+across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may
+do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the
+camera device (in the results) and be roughly correct.<wbr/></p>
+<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from
+FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point
+as what was produced by the camera device in the earlier frame.<wbr/></p>
+<p>The expected processing pipeline is as follows:</p>
+<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p>
+<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance
+gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform
+matrix (applied after demosaic).<wbr/></p>
+<p>The 4-channel white-balance gains are defined as:</p>
+<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ]
+</code></pre>
+<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the
+output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/>
+These may be identical for a given camera device implementation; if
+the camera device does not support a separate gain for even/<wbr/>odd green
+channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to
+<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
+<p>The matrices for color transforms are defined as a 9-entry vector:</p>
+<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
+</code></pre>
+<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/>
+to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p>
+<p>with colors as follows:</p>
+<pre><code>r' = I0r + I1g + I2b
+g' = I3r + I4g + I5b
+b' = I6r + I7g + I8b
+</code></pre>
+<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow
+values are clipped to fit within the range.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.colorCorrection.transform">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>color<wbr/>Correction.<wbr/>transform
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A color transform matrix to use to transform
+from sensor RGB color space to output linear sRGB color space.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Unitless scale factors
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is either set by the camera device when the request
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or
+directly by the application in the request when the
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>In the latter case,<wbr/> the camera device may round the matrix to account
+for precision issues; the final rounded matrix should be reported back
+in this matrix result metadata.<wbr/> The transform should keep the magnitude
+of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color
+values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p>
+<p>The valid range of each matrix element varies on different devices,<wbr/> but
+values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.colorCorrection.gains">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>color<wbr/>Correction.<wbr/>gains
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rggbChannelVector]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Gains applying to Bayer raw color channels for
+white-balance.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Unitless gain factors
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>These per-channel gains are either set by the camera device
+when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not
+TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the
+request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is
+TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>The gains in the result metadata are the gains actually
+applied by the camera device to the current frame.<wbr/></p>
+<p>The valid range of gains varies on different devices,<wbr/> but gains
+between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given
+device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because
+this can create color artifacts.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The 4-channel white-balance gains are defined in
+the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain
+for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code>
+is the gain for green pixels on the odd rows.<wbr/></p>
+<p>If a HAL does not support a separate gain for even/<wbr/>odd green
+channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write
+<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.colorCorrection.aberrationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate
+relative to sensor raw output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be
+reduced (relative to sensor raw output rate)</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
+can not focus on the same point after exiting from the lens.<wbr/> This metadata defines
+the high level control of chromatic aberration correction algorithm,<wbr/> which aims to
+minimize the chromatic artifacts that may occur along the object boundaries in an
+image.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration
+correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will
+use the highest-quality aberration correction algorithms,<wbr/> even if it slows down
+capture rate.<wbr/> FAST means the camera device will not slow down capture rate when
+applying aberration correction.<wbr/></p>
+<p>LEGACY devices will always be in FAST mode.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.colorCorrection.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>color<wbr/>Correction.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">TRANSFORM_MATRIX</span>
+ <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p>
+<p>All advanced white balance adjustments (not specified
+by our white balance pipeline) must be disabled.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override
+this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Color correction processing must not slow down
+capture rate relative to sensor raw output.<wbr/></p>
+<p>Advanced white balance adjustments above and beyond
+the specified white balance pipeline may be applied.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+the camera device uses the last frame's AWB values
+(or defaults if AWB has never been run).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Color correction processing operates at improved
+quality but the capture rate might be reduced (relative to sensor
+raw output rate)</p>
+<p>Advanced white balance adjustments above and beyond
+the specified white balance pipeline may be applied.<wbr/></p>
+<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
+the camera device uses the last frame's AWB values
+(or defaults if AWB has never been run).<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The mode control selects how the image data is converted from the
+sensor's native color into linear sRGB color.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this
+control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the
+application controls how the color mapping is performed.<wbr/></p>
+<p>We define the expected processing pipeline below.<wbr/> For consistency
+across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may
+do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the
+camera device (in the results) and be roughly correct.<wbr/></p>
+<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from
+FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point
+as what was produced by the camera device in the earlier frame.<wbr/></p>
+<p>The expected processing pipeline is as follows:</p>
+<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p>
+<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance
+gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform
+matrix (applied after demosaic).<wbr/></p>
+<p>The 4-channel white-balance gains are defined as:</p>
+<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ]
+</code></pre>
+<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the
+output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/>
+These may be identical for a given camera device implementation; if
+the camera device does not support a separate gain for even/<wbr/>odd green
+channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to
+<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
+<p>The matrices for color transforms are defined as a 9-entry vector:</p>
+<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
+</code></pre>
+<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/>
+to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p>
+<p>with colors as follows:</p>
+<pre><code>r' = I0r + I1g + I2b
+g' = I3r + I4g + I5b
+b' = I6r + I7g + I8b
+</code></pre>
+<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow
+values are clipped to fit within the range.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.colorCorrection.transform">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>color<wbr/>Correction.<wbr/>transform
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A color transform matrix to use to transform
+from sensor RGB color space to output linear sRGB color space.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Unitless scale factors
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is either set by the camera device when the request
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or
+directly by the application in the request when the
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>In the latter case,<wbr/> the camera device may round the matrix to account
+for precision issues; the final rounded matrix should be reported back
+in this matrix result metadata.<wbr/> The transform should keep the magnitude
+of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color
+values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p>
+<p>The valid range of each matrix element varies on different devices,<wbr/> but
+values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.colorCorrection.gains">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>color<wbr/>Correction.<wbr/>gains
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rggbChannelVector]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Gains applying to Bayer raw color channels for
+white-balance.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Unitless gain factors
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>These per-channel gains are either set by the camera device
+when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not
+TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the
+request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is
+TRANSFORM_<wbr/>MATRIX.<wbr/></p>
+<p>The gains in the result metadata are the gains actually
+applied by the camera device to the current frame.<wbr/></p>
+<p>The valid range of gains varies on different devices,<wbr/> but gains
+between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given
+device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because
+this can create color artifacts.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The 4-channel white-balance gains are defined in
+the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain
+for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code>
+is the gain for green pixels on the odd rows.<wbr/></p>
+<p>If a HAL does not support a separate gain for even/<wbr/>odd green
+channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write
+<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.colorCorrection.aberrationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate
+relative to sensor raw output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be
+reduced (relative to sensor raw output rate)</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
+can not focus on the same point after exiting from the lens.<wbr/> This metadata defines
+the high level control of chromatic aberration correction algorithm,<wbr/> which aims to
+minimize the chromatic artifacts that may occur along the object boundaries in an
+image.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration
+correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will
+use the highest-quality aberration correction algorithms,<wbr/> even if it slows down
+capture rate.<wbr/> FAST means the camera device will not slow down capture rate when
+applying aberration correction.<wbr/></p>
+<p>LEGACY devices will always be in FAST mode.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.colorCorrection.availableAberrationModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of aberration correction modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key lists the valid modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a>.<wbr/> If no
+aberration correction modes are available for a device,<wbr/> this list will solely include
+OFF mode.<wbr/> All camera devices will support either OFF or FAST mode.<wbr/></p>
+<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always list
+OFF mode.<wbr/> This includes all FULL level devices.<wbr/></p>
+<p>LEGACY devices will always only support FAST mode.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if chromatic aberration control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_control" class="section">control</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.control.aeAntibandingMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to
+avoid banding problems.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">50HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
+avoid banding problems with 50Hz illumination sources.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">60HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
+avoid banding problems with 60Hz illumination
+sources.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its
+antibanding routine to the current illumination
+condition.<wbr/> This is the default mode if AUTO is
+available on given camera device.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired setting for the camera device's auto-exposure
+algorithm's antibanding compensation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent
+lights,<wbr/> flicker at the rate of the power supply frequency
+(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is
+typically not noticeable to a person,<wbr/> it can be visible to
+a camera device.<wbr/> If a camera sets its exposure time to the
+wrong value,<wbr/> the flicker may become visible in the
+viewfinder as flicker or in a final captured image,<wbr/> as a
+set of variable-brightness bands across the image.<wbr/></p>
+<p>Therefore,<wbr/> the auto-exposure routines of camera devices
+include antibanding routines that ensure that the chosen
+exposure value will not cause such banding.<wbr/> The choice of
+exposure time depends on the rate of flicker,<wbr/> which the
+camera device can detect automatically,<wbr/> or the expected
+rate can be selected by the application using this
+control.<wbr/></p>
+<p>A given camera device may not support all of the possible
+options for the antibanding mode.<wbr/> The
+<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains
+the available modes for a given camera device.<wbr/></p>
+<p>AUTO mode is the default if it is available on given
+camera device.<wbr/> When AUTO mode is not available,<wbr/> the
+default will be either 50HZ or 60HZ,<wbr/> and both 50HZ
+and 60HZ will be available.<wbr/></p>
+<p>If manual exposure control is enabled (by setting
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
+then this setting has no effect,<wbr/> and the application must
+ensure it selects exposure times that do not cause banding
+issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist
+the application in this.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For all capture request templates,<wbr/> this field must be set
+to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/>
+the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and
+60HZ must be available.<wbr/></p>
+<p>If manual exposure control is enabled (by setting
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
+then the exposure values provided by the application must not be
+adjusted for antibanding.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aeExposureCompensation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Adjustment to auto-exposure (AE) target image
+brightness.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Compensation steps
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The adjustment is measured as a count of steps,<wbr/> with the
+step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the
+allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p>
+<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6'
+will mean an exposure compensation of +2 EV; -3 will mean an
+exposure compensation of -1 EV.<wbr/> One EV represents a doubling
+of image brightness.<wbr/> Note that this control will only be
+effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control
+will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p>
+<p>In the event of exposure compensation value being changed,<wbr/> camera device
+may take several frames to reach the newly requested exposure target.<wbr/>
+During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING
+state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will
+change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or
+FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aeLock">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm
+is free to update its parameters.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm
+must not update the exposure and sensitivity parameters
+while the lock is active.<wbr/></p>
+<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes
+will still take effect while auto-exposure is locked.<wbr/></p>
+<p>Some rare LEGACY devices may not support
+this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-exposure (AE) is currently locked to its latest
+calculated values.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/>
+and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
+<p>Note that even when AE is locked,<wbr/> the flash may be fired if
+the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/>
+ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p>
+<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock
+is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p>
+<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>)
+when AE is already locked,<wbr/> the camera device will not change the exposure time
+(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
+parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
+is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/>
+Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p>
+<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock
+the AE if AE is locked by the camera device internally during precapture metering
+sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an
+ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence
+will never succeed in a sequence of preview requests where AE lock is always set
+to <code>false</code>.<wbr/></p>
+<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
+get locked do not necessarily correspond to the settings that were present in the
+latest capture result received from the camera device,<wbr/> since additional captures
+and AE updates may have occurred even before the result was sent out.<wbr/> If an
+application is switching between automatic and manual control and wishes to eliminate
+any flicker during the switch,<wbr/> the following procedure is recommended:</p>
+<ol>
+<li>Starting in auto-AE mode:</li>
+<li>Lock AE</li>
+<li>Wait for the first result to be output that has the AE locked</li>
+<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li>
+<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li>
+</ol>
+<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aeMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p>
+<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera
+device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's
+a flash unit for this camera device.<wbr/></p>
+<p>Note that auto-white balance (AWB) and auto-focus (AF)
+behavior is device dependent when AE is in OFF mode.<wbr/>
+To have consistent behavior across different devices,<wbr/>
+it is recommended to either set AWB and AF to OFF mode
+or lock AWB and AF before setting AE to OFF.<wbr/>
+See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
+for more details.<wbr/></p>
+<p>LEGACY devices do not support the OFF mode and will
+override attempts to use this value to ON.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/>
+with no flash control.<wbr/></p>
+<p>The application's values for
+<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The
+application has control over the various
+android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_AUTO_FLASH</span>
+ <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
+the camera's flash unit,<wbr/> firing it in low-light
+conditions.<wbr/></p>
+<p>The flash may be fired during a precapture sequence
+(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
+may be fired for captures for which the
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
+STILL_<wbr/>CAPTURE</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span>
+ <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
+the camera's flash unit,<wbr/> always firing it for still
+captures.<wbr/></p>
+<p>The flash may be fired during a precapture sequence
+(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
+will always be fired for captures for which the
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
+STILL_<wbr/>CAPTURE</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span>
+ <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye
+reduction.<wbr/></p>
+<p>If deemed necessary by the camera device,<wbr/> a red eye
+reduction flash will fire during the precapture
+sequence.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired mode for the camera device's
+auto-exposure routine.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is
+AUTO.<wbr/></p>
+<p>When set to any of the ON modes,<wbr/> the camera device's
+auto-exposure routine is enabled,<wbr/> overriding the
+application's selected exposure time,<wbr/> sensor sensitivity,<wbr/>
+and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes
+is selected,<wbr/> the camera device's flash unit controls are
+also overridden.<wbr/></p>
+<p>The FLASH modes are only available if the camera device
+has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p>
+<p>If flash TORCH mode is desired,<wbr/> this field must be set to
+ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p>
+<p>When set to any of the ON modes,<wbr/> the values chosen by the
+camera device auto-exposure routine for the overridden
+fields for a given capture will be available in its
+CaptureResult.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aeRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of regions supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one
+region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0
+weight is ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aeTargetFpsRange">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Range over which the auto-exposure routine can
+adjust the capture frame rate to maintain good
+exposure.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Frames per second (FPS)
+ </td>
+
+ <td class="entry_range">
+ <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not
+manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.aePrecaptureTrigger">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">IDLE</span>
+ <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">START</span>
+ <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started
+by the camera device.<wbr/></p>
+<p>The exact effect of the precapture trigger depends on
+the current AE mode and state.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANCEL</span>
+ <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed
+precapture metering sequence,<wbr/> the auto-exposure routine will return to its
+initial state.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will trigger a precapture
+metering sequence when it processes this request.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is normally set to IDLE,<wbr/> or is not
+included at all in the request settings.<wbr/> When included and
+set to START,<wbr/> the camera device will trigger the auto-exposure (AE)
+precapture metering sequence.<wbr/></p>
+<p>When set to CANCEL,<wbr/> the camera device will cancel any active
+precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/>
+If a precapture metering sequence is already completed,<wbr/> and the camera
+device has implicitly locked the AE for subsequent still capture,<wbr/> the
+CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p>
+<p>The precapture sequence should be triggered before starting a
+high-quality still capture for final metering decisions to
+be made,<wbr/> and for firing pre-capture flash pulses to estimate
+scene brightness and required final capture flash power,<wbr/> when
+the flash is enabled.<wbr/></p>
+<p>Normally,<wbr/> this entry should be set to START for only a
+single request,<wbr/> and the application should wait until the
+sequence completes before starting a new one.<wbr/></p>
+<p>When a precapture metering sequence is finished,<wbr/> the camera device
+may lock the auto-exposure routine internally to be able to accurately expose the
+subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/>
+For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is
+submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should
+submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request
+with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a
+still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for
+API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device
+internally locked AE if the application doesn't submit a still capture request after
+the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not
+be used in devices that have earlier API levels.<wbr/></p>
+<p>The exact effect of auto-exposure (AE) precapture trigger
+depends on the current AE mode and state; see
+<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition
+details.<wbr/></p>
+<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported;
+capturing a high-resolution JPEG image will automatically trigger a
+precapture sequence before the high-resolution capture,<wbr/> including
+potentially firing a pre-capture flash.<wbr/></p>
+<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
+simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
+the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
+focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
+trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
+changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for
+example.<wbr/></p>
+<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then
+the camera device will complete them in the optimal order for that device.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active
+(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/> It is acceptable for the HAL to
+treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
+AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
+to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.afMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens;
+<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the
+application.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p>
+<p>In this mode,<wbr/> the lens does not move unless
+the autofocus trigger action is called.<wbr/> When that trigger
+is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
+the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p>
+<p>Always supported if lens is not fixed focus.<wbr/></p>
+<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens
+is fixed-focus.<wbr/></p>
+<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/>
+and sets the AF state to INACTIVE.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MACRO</span>
+ <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p>
+<p>In this mode,<wbr/> the lens does not move unless the
+autofocus trigger action is called.<wbr/> When that trigger is
+activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
+the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This
+mode is optimized for focusing on objects very close to
+the camera.<wbr/></p>
+<p>When that trigger is activated,<wbr/> AF will transition to
+ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or
+NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens
+position to default,<wbr/> and sets the AF state to
+INACTIVE.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span>
+ <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
+position continually to attempt to provide a
+constantly-in-focus image stream.<wbr/></p>
+<p>The focusing behavior should be suitable for good quality
+video recording; typically this means slower focus
+movement and no overshoots.<wbr/> When the AF trigger is not
+involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/>
+and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED
+states as appropriate.<wbr/> When the AF trigger is activated,<wbr/>
+the algorithm should immediately transition into
+AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
+lens position until a cancel AF trigger is received.<wbr/></p>
+<p>Once cancel is received,<wbr/> the algorithm should transition
+back to INACTIVE and resume passive scan.<wbr/> Note that this
+behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an
+ongoing PASSIVE_<wbr/>SCAN must immediately be
+canceled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span>
+ <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
+position continually to attempt to provide a
+constantly-in-focus image stream.<wbr/></p>
+<p>The focusing behavior should be suitable for still image
+capture; typically this means focusing as fast as
+possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF
+algorithm should start in INACTIVE state,<wbr/> and then
+transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as
+appropriate as it attempts to maintain focus.<wbr/> When the AF
+trigger is activated,<wbr/> the algorithm should finish its
+PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into
+AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
+lens position until a cancel AF trigger is received.<wbr/></p>
+<p>When the AF cancel trigger is activated,<wbr/> the algorithm
+should transition back to INACTIVE and then act as if it
+has just been started.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">EDOF</span>
+ <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p>
+<p>The camera device will produce images with an extended
+depth of field automatically; no special focusing
+operations need to be done before taking a picture.<wbr/></p>
+<p>AF triggers are ignored,<wbr/> and the AF state will always be
+INACTIVE.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what
+mode it is set to.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus
+(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>).<wbr/> Also note that
+when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device
+dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before
+setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p>
+<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/>
+the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>
+in result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a
+request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end
+up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see
+<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is
+locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move
+after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that
+the same focal plane remains in focus.<wbr/></p>
+<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF
+scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger
+(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the
+same lock behavior as above.<wbr/></p>
+<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the
+focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/>
+However,<wbr/> the lens must not move regardless of the camera movement for any focus distance
+manual control.<wbr/></p>
+<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on
+camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to
+remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/>
+by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue
+that will arise on camera modules with open-loop VCMs.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.afRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-focus.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of focus areas supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region
+is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is
+ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.afTrigger">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Trigger
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">IDLE</span>
+ <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">START</span>
+ <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANCEL</span>
+ <span class="entry_type_enum_notes"><p>Autofocus will return to its initial
+state,<wbr/> and cancel any currently active trigger.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will trigger autofocus for this request.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is normally set to IDLE,<wbr/> or is not
+included at all in the request settings.<wbr/></p>
+<p>When included and set to START,<wbr/> the camera device will trigger the
+autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p>
+<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/>
+and return to its initial AF state.<wbr/></p>
+<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a
+single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying
+START for multiple captures in a row means restarting the AF operation over
+and over again.<wbr/></p>
+<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p>
+<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
+simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
+the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
+focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
+trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
+changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active
+(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/> It is acceptable for the HAL to
+treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
+AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
+to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.awbLock">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB
+algorithm is free to update its parameters if in AUTO
+mode.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB
+algorithm will not update its parameters while the lock
+is active.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-white balance (AWB) is currently locked to its
+latest calculated values.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/>
+and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
+<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
+get locked do not necessarily correspond to the settings that were present in the
+latest capture result received from the camera device,<wbr/> since additional captures
+and AWB updates may have occurred even before the result was sent out.<wbr/> If an
+application is switching between automatic and manual control and wishes to eliminate
+any flicker during the switch,<wbr/> the following procedure is recommended:</p>
+<ol>
+<li>Starting in auto-AWB mode:</li>
+<li>Lock AWB</li>
+<li>Wait for the first result to be output that has the AWB locked</li>
+<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li>
+<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li>
+</ol>
+<p>Note that AWB lock is only meaningful when
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/>
+AWB is already fixed to a specific setting.<wbr/></p>
+<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.awbMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p>
+<p>The application-selected color transform matrix
+(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains
+(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera
+device for manual white balance control.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">INCANDESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses incandescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant A.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FLUORESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses fluorescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant F2.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">WARM_FLUORESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses warm fluorescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant F4.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DAYLIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses daylight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant D65.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses cloudy daylight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TWILIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses twilight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SHADE</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses shade light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-white balance (AWB) is currently setting the color
+transform fields,<wbr/> and what its illumination target
+is.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p>
+<p>When set to the ON mode,<wbr/> the camera device's auto-white balance
+routine is enabled,<wbr/> overriding the application's selected
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
+is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to
+also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before
+setting AE mode to OFF.<wbr/></p>
+<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance
+routine is disabled.<wbr/> The application manually controls the white
+balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>
+and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p>
+<p>When set to any other modes,<wbr/> the camera device's auto-white
+balance routine is disabled.<wbr/> The camera device uses each
+particular illumination target for white balance
+adjustment.<wbr/> The application's values for
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/>
+<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.awbRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>awb<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-white-balance illuminant
+estimation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of regions supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must range from 0 to 1000,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if
+only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with
+0 weight is ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.captureIntent">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>capture<wbr/>Intent
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CUSTOM</span>
+ <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other
+categories.<wbr/> The camera device will default to preview-like
+behavior.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PREVIEW</span>
+ <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p>
+<p>The precapture trigger may be used to start off a metering
+w/<wbr/>flash sequence.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STILL_CAPTURE</span>
+ <span class="entry_type_enum_notes"><p>This request is for a still capture-type
+use case.<wbr/></p>
+<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">VIDEO_RECORD</span>
+ <span class="entry_type_enum_notes"><p>This request is for a video recording
+use case.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span>
+ <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still
+image while recording video) use case.<wbr/></p>
+<p>The camera device should take the highest-quality image
+possible (given the other settings) without disrupting the
+frame rate of video recording.<wbr/> </p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the
+application will stream full-resolution images and
+reprocess one or several later for a final
+capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MANUAL</span>
+ <span class="entry_type_enum_notes"><p>This request is for manual capture use case where
+the applications want to directly control the capture parameters.<wbr/></p>
+<p>For example,<wbr/> the application may wish to manually control
+<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Information to the camera device 3A (auto-exposure,<wbr/>
+auto-focus,<wbr/> auto-white balance) routines about the purpose
+of this capture,<wbr/> to help the camera device to decide optimal 3A
+strategy.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control (except for MANUAL) is only effective if
+<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
+contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if
+<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are
+always supported.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.effectMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>effect<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MONO</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into
+a single color.<wbr/></p>
+<p>This will typically be grayscale.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NEGATIVE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors
+are inverted.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SOLARIZE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the
+image is wholly or partially reversed in
+tone.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SEPIA</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm
+gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">POSTERIZE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses
+discrete regions of tone rather than a continuous
+gradient of tones.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">WHITEBOARD</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed
+as regions of white,<wbr/> with black or grey details.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BLACKBOARD</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed
+as regions of black,<wbr/> with white or grey details.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AQUA</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A special color effect to apply.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When this mode is set,<wbr/> a color effect will be applied
+to images produced by the camera device.<wbr/> The interpretation
+and implementation of these color effects is left to the
+implementor of the camera device,<wbr/> and should not be
+depended on to be consistent (or present) across all
+devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p>
+<p>All control by the device's metering and focusing (3A)
+routines is disabled,<wbr/> and no other settings in
+android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera
+device to select post-processing values for processing
+blocks that do not allow for manual control,<wbr/> or are not
+exposed by the camera API.<wbr/></p>
+<p>However,<wbr/> the camera device's 3A routines may continue to
+collect statistics and update their internal state so that
+when control is switched to AUTO mode,<wbr/> good control values
+can be immediately applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p>
+<p>Manual control of capture parameters is disabled.<wbr/> All
+controls in android.<wbr/>control.<wbr/>* besides sceneMode take
+effect.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">USE_SCENE_MODE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p>
+<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and
+control.<wbr/>afMode controls; the camera device will ignore
+those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for
+FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/>
+This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/>
+<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>
+contain some modes other than DISABLED).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">OFF_KEEP_STATE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be
+used by camera device background auto-exposure,<wbr/> auto-white balance and
+auto-focus algorithms (3A) to update their statistics.<wbr/></p>
+<p>Specifically,<wbr/> the 3A routines are locked to the last
+values set from a request with AUTO,<wbr/> OFF,<wbr/> or
+USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates
+collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be
+discarded by the camera device.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control
+routines.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control
+by the camera device is disabled.<wbr/> The application must set the fields for
+capture parameters itself.<wbr/></p>
+<p>When set to AUTO,<wbr/> the individual algorithm controls in
+android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p>
+<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in
+android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements
+one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY)
+as it wishes.<wbr/> The camera device scene mode 3A settings are provided by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p>
+<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference
+is that this frame will not be used by camera device background 3A statistics
+update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario
+where the application doesn't want a 3A manual control capture to affect
+the subsequent auto 3A capture results.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.sceneMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>scene<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">DISABLED</span>
+ <span class="entry_type_enum_value">0</span>
+ <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FACE_PRIORITY</span>
+ <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face
+detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and
+auto-exposure routines.<wbr/></p>
+<p>If face detection statistics are disabled
+(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/>
+this should still operate correctly (but will not return
+face detection statistics to the framework).<wbr/></p>
+<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ACTION</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p>
+<p>Similar to SPORTS.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PORTRAIT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">LANDSCAPE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NIGHT_PORTRAIT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light
+settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">THEATRE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must
+remain off.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BEACH</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SNOW</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SUNSET</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STEADYPHOTO</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of
+device motion (for example: due to hand shake).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FIREWORKS</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SPORTS</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p>
+<p>Similar to ACTION.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PARTY</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving
+people.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANDLELIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source
+is a flame.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BARCODE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode
+for use by camera applications that wish to read the
+barcode value.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span>
+ <span class="entry_type_enum_deprecated">[deprecated]</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
+and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>
+for high speed video recording.<wbr/></p>
+<p>Optimized for high speed video recording (frame rate >=60fps) use case.<wbr/></p>
+<p>The supported high speed video sizes and fps ranges are specified in
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired
+output frame rates,<wbr/> the application is only allowed to select video size
+and fps range combinations listed in this static metadata.<wbr/> The fps range
+can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
+<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
+ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
+controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
+and post-processing parameters is possible.<wbr/> All other controls operate the
+same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
+android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
+<ul>
+<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
+<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
+<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
+<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
+<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
+</ul>
+<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
+<ul>
+<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li>
+<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
+<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
+<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li>
+</ul>
+<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
+be lower than what camera can output,<wbr/> depending on the destination Surfaces for
+the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
+the application need check if the video encoder is capable of supporting the
+high frame rate for a given video size,<wbr/> or it will end up with lower recording
+frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame
+rate will be bounded by the screen refresh rate.<wbr/></p>
+<p>The camera device will only support up to 2 output high speed streams
+(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>)
+in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p>
+<ul>
+<li>The application created no more than maxNumHighSpeedStreams processed non-stalling
+format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as
+min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li>
+<li>The stream sizes are selected from the sizes reported by
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li>
+<li>No processed non-stalling or raw streams are configured.<wbr/></li>
+</ul>
+<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and
+<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/>
+the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/>
+and the returned capture result metadata will give the fps range choosen
+by the camera device.<wbr/></p>
+<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor
+reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
+the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HDR</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p>
+<p>In this scene mode,<wbr/> the camera device captures images
+that keep a larger range of scene illumination levels
+visible in the final image.<wbr/> For example,<wbr/> when taking a
+picture of a object in front of a bright window,<wbr/> both
+the object and the scene through the window may be
+visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/>
+one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/>
+HDR mode generally takes much longer to capture a single
+image,<wbr/> has no user control,<wbr/> and may have other artifacts
+depending on the HDR method used.<wbr/></p>
+<p>Therefore,<wbr/> HDR captures operate at a much slower rate
+than regular captures.<wbr/></p>
+<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request
+is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of
+STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image
+using a high dynamic range capture technique.<wbr/> On LEGACY
+devices,<wbr/> captures that target a JPEG-format output will
+be captured with HDR,<wbr/> and the capture intent is not
+relevant.<wbr/></p>
+<p>The HDR capture may involve the device capturing a burst
+of images internally and combining them into one,<wbr/> or it
+may involve the device using specialized high dynamic
+range capture hardware.<wbr/> In all cases,<wbr/> a single image is
+produced in response to a capture request submitted
+while in HDR mode.<wbr/></p>
+<p>Since substantial post-processing is generally needed to
+produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG
+outputs are supported for LIMITED/<wbr/>FULL device HDR
+captures,<wbr/> and only JPEG outputs are supported for LEGACY
+HDR captures.<wbr/> Using a RAW output for HDR capture is not
+supported.<wbr/></p>
+<p>Some devices may also support always-on HDR,<wbr/> which
+applies HDR processing at full frame rate.<wbr/> For these
+devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also
+produce an HDR output with no frame rate impact compared
+to normal operation,<wbr/> though the quality may be lower
+than for STILL_<wbr/>CAPTURE intents.<wbr/></p>
+<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types
+or capture intents,<wbr/> the images captured will be as if
+the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera
+device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
+under low light conditions.<wbr/></p>
+<p>The camera device may be tuned to expose the images in a reduced
+sensitivity range to produce the best quality images.<wbr/> For example,<wbr/>
+if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/>
+the camera device auto-exposure routine tuning process may limit the actual
+exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't
+exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under
+low light may be under-exposed when the sensor max exposure time (bounded by the
+<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the
+ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the
+camera device auto-exposure routine to increase the sensitivity up to the max
+sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too
+dark and the max exposure time is reached.<wbr/> The captured images may be noisier
+compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is
+recommended that the application only use this scene mode when it is capable of
+reducing the noise level of the captured images.<wbr/></p>
+<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_value">100</span>
+ <span class="entry_type_enum_notes"><p>Scene mode values within the range of
+<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
+customized scene modes.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_value">127</span>
+ <span class="entry_type_enum_notes"><p>Scene mode values within the range of
+<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
+customized scene modes.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Control for which scene mode is currently active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Scene modes are custom camera modes optimized for a certain set of conditions and
+capture settings.<wbr/></p>
+<p>This is the mode that that is active when
+<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will
+disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+while in use.<wbr/></p>
+<p>The interpretation and implementation of these scene modes is left
+to the implementor of the camera device.<wbr/> Their behavior will not be
+consistent across all devices,<wbr/> and any given device may only implement
+a subset of these modes.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL implementations that include scene modes are expected to provide
+the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in
+<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p>
+<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/>
+the HAL must list supported video size and fps range in
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/>
+1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming
+mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture
+requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/>
+This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO
+capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.videoStabilizationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether video stabilization is
+active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Video stabilization automatically warps images from
+the camera in order to stabilize motion between consecutive frames.<wbr/></p>
+<p>If enabled,<wbr/> video stabilization can modify the
+<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p>
+<p>Switching between different video stabilization modes may take several
+frames to initialize,<wbr/> the camera device will report the current mode
+in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/>
+the video stabilization modes in the first several capture results may
+still be "OFF",<wbr/> and it will become "ON" when the initialization is
+done.<wbr/></p>
+<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for
+stabilization by a device that reports stabilization support.<wbr/> It is guaranteed
+that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+the recording resolution is less than or equal to 1920 x 1080 (width less than
+or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording
+frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the CaptureResult
+<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return
+OFF if the recording output is not stabilized,<wbr/> or if there are no output
+Surface types that can be stabilized.<wbr/></p>
+<p>If a camera device supports both this mode and OIS
+(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may
+produce undesirable interaction,<wbr/> so it is recommended not to enable
+both at the same time.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.control.postRawSensitivityBoost">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of additional sensitivity boost applied to output images
+after RAW sensor data is captured.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Some camera devices support additional digital sensitivity boosting in the
+camera processing pipeline after sensor RAW image is captured.<wbr/>
+Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not
+have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p>
+<p>This key will be <code>null</code> for devices that do not support any RAW format
+outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
+present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
+list <code>100</code> in this key.<wbr/></p>
+<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the
+boost to the nearest supported value.<wbr/>
+The final boost value used will be available in the output capture result.<wbr/></p>
+<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images
+of such device will have the total sensitivity of
+<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code>
+The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.control.aeAvailableAntibandingModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of auto-exposure antibanding modes for <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not all of the auto-exposure anti-banding modes may be
+supported by a given camera device.<wbr/> This field lists the
+valid anti-banding modes that the application may request
+for this camera device with the
+<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> control.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.aeAvailableModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of auto-exposure modes for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not all the auto-exposure modes may be supported by a
+given camera device,<wbr/> especially if no flash unit is
+available.<wbr/> This entry lists the valid modes for
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> for this camera device.<wbr/></p>
+<p>All camera devices support ON,<wbr/> and all camera devices with flash
+units support ON_<wbr/>AUTO_<wbr/>FLASH and ON_<wbr/>ALWAYS_<wbr/>FLASH.<wbr/></p>
+<p>FULL mode camera devices always support OFF mode,<wbr/>
+which enables application control of camera exposure time,<wbr/>
+sensitivity,<wbr/> and frame duration.<wbr/></p>
+<p>LEGACY mode camera devices never support OFF mode.<wbr/>
+LIMITED mode devices support OFF if they support the MANUAL_<wbr/>SENSOR
+capability.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.aeAvailableTargetFpsRanges">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2 x n
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">list of pairs of frame rates</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of frame rate ranges for <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> supported by
+this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Frames per second (FPS)
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For devices at the LEGACY level or above:</p>
+<ul>
+<li>
+<p>For constant-framerate recording,<wbr/> for each normal
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/> that is,<wbr/> a
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#quality">quality</a> in
+the range [<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_LOW">QUALITY_<wbr/>LOW</a>,<wbr/>
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_2160P">QUALITY_<wbr/>2160P</a>],<wbr/> if the profile is
+supported by the device and has
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code>,<wbr/> this list will
+always include (<code>x</code>,<wbr/><code>x</code>).<wbr/></p>
+</li>
+<li>
+<p>Also,<wbr/> a camera device must either not support any
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/>
+or support at least one
+normal <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
+<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code> >= 24.<wbr/></p>
+</li>
+</ul>
+<p>For devices at the LIMITED level or above:</p>
+<ul>
+<li>For YUV_<wbr/>420_<wbr/>888 burst capture use case,<wbr/> this list will always include (<code>min</code>,<wbr/> <code>max</code>)
+and (<code>max</code>,<wbr/> <code>max</code>) where <code>min</code> <= 15 and <code>max</code> = the maximum output frame rate of the
+maximum YUV_<wbr/>420_<wbr/>888 output size.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.aeCompensationRange">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum and minimum exposure compensation values for
+<a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>,<wbr/> in counts of <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a>,<wbr/>
+that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Range [0,<wbr/>0] indicates that exposure compensation is not supported.<wbr/></p>
+<p>For LIMITED and FULL devices,<wbr/> range must follow below requirements if exposure
+compensation is supported (<code>range != [0,<wbr/> 0]</code>):</p>
+<p><code>Min.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> <= -2 EV</code></p>
+<p><code>Max.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> >= 2 EV</code></p>
+<p>LEGACY devices may support a smaller range than this.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.aeCompensationStep">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Smallest step by which the exposure compensation
+can be changed.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Exposure Value (EV)
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is the unit for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>.<wbr/> For example,<wbr/> if this key has
+a value of <code>1/<wbr/>2</code>,<wbr/> then a setting of <code>-2</code> for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> means
+that the target EV offset for the auto-exposure routine is -1 EV.<wbr/></p>
+<p>One unit of EV compensation changes the brightness of the captured image by a factor
+of two.<wbr/> +1 EV doubles the image brightness,<wbr/> while -1 EV halves the image brightness.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This must be less than or equal to 1/<wbr/>2.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.afAvailableModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of auto-focus (AF) modes for <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not all the auto-focus modes may be supported by a
+given camera device.<wbr/> This entry lists the valid modes for
+<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> for this camera device.<wbr/></p>
+<p>All LIMITED and FULL mode camera devices will support OFF mode,<wbr/> and all
+camera devices with adjustable focuser units
+(<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>) will support AUTO mode.<wbr/></p>
+<p>LEGACY devices will support OFF mode only if they support
+focusing to infinity (by also setting <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> to
+<code>0.<wbr/>0f</code>).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.availableEffects">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>available<wbr/>Effects
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>effect<wbr/>Mode).<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of color effects for <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This list contains the color effect modes that can be applied to
+images produced by the camera device.<wbr/>
+Implementations are not expected to be consistent across all devices.<wbr/>
+If no color effect modes are available for a device,<wbr/> this will only list
+OFF.<wbr/></p>
+<p>A color effect will only be applied if
+<a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF.<wbr/> OFF is always included in this list.<wbr/></p>
+<p>This control has no effect on the operation of other control routines such
+as auto-exposure,<wbr/> white balance,<wbr/> or focus.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.availableSceneModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>scene<wbr/>Mode).<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of scene modes for <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This list contains scene modes that can be set for the camera device.<wbr/>
+Only scene modes that have been fully implemented for the
+camera device may be included here.<wbr/> Implementations are not expected
+to be consistent across all devices.<wbr/></p>
+<p>If no scene modes are supported by the camera device,<wbr/> this
+will be set to DISABLED.<wbr/> Otherwise DISABLED will not be listed.<wbr/></p>
+<p>FACE_<wbr/>PRIORITY is always listed if face detection is
+supported (i.<wbr/>e.<wbr/><code><a href="#static_android.statistics.info.maxFaceCount">android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count</a> >
+0</code>).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.availableVideoStabilizationModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of video stabilization modes for <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>
+that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>OFF will always be listed.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.awbAvailableModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of auto-white-balance modes for <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> that are supported by this
+camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not all the auto-white-balance modes may be supported by a
+given camera device.<wbr/> This entry lists the valid modes for
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> for this camera device.<wbr/></p>
+<p>All camera devices will support ON mode.<wbr/></p>
+<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always support OFF
+mode,<wbr/> which enables application control of white balance,<wbr/> by using
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>(<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> must be set to TRANSFORM_<wbr/>MATRIX).<wbr/> This includes all FULL
+mode camera devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.maxRegions">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>control.<wbr/>max<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of the maximum number of regions that can be used for metering in
+auto-exposure (AE),<wbr/> auto-white balance (AWB),<wbr/> and auto-focus (AF);
+this corresponds to the the maximum number of elements in
+<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>,<wbr/> <a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>,<wbr/>
+and <a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Value must be >= 0 for each element.<wbr/> For full-capability devices
+this value must be >= 1 for AE and AF.<wbr/> The order of the elements is:
+<code>(AE,<wbr/> AWB,<wbr/> AF)</code>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.maxRegionsAe">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum number of metering regions that can be used by the auto-exposure (AE)
+routine.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Value will be >= 0.<wbr/> For FULL-capability devices,<wbr/> this
+value will be >= 1.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This corresponds to the the maximum allowed number of elements in
+<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is private to the framework.<wbr/> Fill in
+maxRegions to have this entry be automatically populated.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.maxRegionsAwb">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum number of metering regions that can be used by the auto-white balance (AWB)
+routine.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Value will be >= 0.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This corresponds to the the maximum allowed number of elements in
+<a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is private to the framework.<wbr/> Fill in
+maxRegions to have this entry be automatically populated.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.maxRegionsAf">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum number of metering regions that can be used by the auto-focus (AF) routine.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Value will be >= 0.<wbr/> For FULL-capability devices,<wbr/> this
+value will be >= 1.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This corresponds to the the maximum allowed number of elements in
+<a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is private to the framework.<wbr/> Fill in
+maxRegions to have this entry be automatically populated.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.sceneModeOverrides">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x length(availableSceneModes)
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Ordered list of auto-exposure,<wbr/> auto-white balance,<wbr/> and auto-focus
+settings to use with each available scene mode.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>For each available scene mode,<wbr/> the list must contain three
+entries containing the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values used
+by the camera device.<wbr/> The entry order is <code>(aeMode,<wbr/> awbMode,<wbr/> afMode)</code>
+where aeMode has the lowest index position.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When a scene mode is enabled,<wbr/> the camera device is expected
+to override <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/>
+and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> with its preferred settings for
+that scene mode.<wbr/></p>
+<p>The order of this list matches that of availableSceneModes,<wbr/>
+with 3 entries for each mode.<wbr/> The overrides listed
+for FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) are ignored,<wbr/>
+since for that mode the application-set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values are
+used instead,<wbr/> matching the behavior when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>
+is set to AUTO.<wbr/> It is recommended that the FACE_<wbr/>PRIORITY and
+FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) overrides should be set to 0.<wbr/></p>
+<p>For example,<wbr/> if availableSceneModes contains
+<code>(FACE_<wbr/>PRIORITY,<wbr/> ACTION,<wbr/> NIGHT)</code>,<wbr/> then the camera framework
+expects sceneModeOverrides to have 9 entries formatted like:
+<code>(0,<wbr/> 0,<wbr/> 0,<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> AUTO,<wbr/> CONTINUOUS_<wbr/>PICTURE,<wbr/>
+ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> INCANDESCENT,<wbr/> AUTO)</code>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>To maintain backward compatibility,<wbr/> this list will be made available
+in the static metadata of the camera service.<wbr/> The camera service will
+use these values to set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> when using a scene
+mode other than FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.availableHighSpeedVideoConfigurations">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x n
+ </span>
+ <span class="entry_type_visibility"> [hidden as highSpeedVideoConfiguration]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of available high speed video size,<wbr/> fps range and max batch size configurations
+supported by the camera device,<wbr/> in the format of (width,<wbr/> height,<wbr/> fps_<wbr/>min,<wbr/> fps_<wbr/>max,<wbr/> batch_<wbr/>size_<wbr/>max).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>For each configuration,<wbr/> the fps_<wbr/>max >= 120fps.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO is supported in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>,<wbr/>
+this metadata will list the supported high speed video size,<wbr/> fps range and max batch size
+configurations.<wbr/> All the sizes listed in this configuration will be a subset of the sizes
+reported by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a>
+for processed non-stalling formats.<wbr/></p>
+<p>For the high speed video use case,<wbr/> the application must
+select the video size and fps range from this metadata to configure the recording and
+preview streams and setup the recording requests.<wbr/> For example,<wbr/> if the application intends
+to do high speed recording,<wbr/> it can select the maximum size reported by this metadata to
+configure output streams.<wbr/> Once the size is selected,<wbr/> application can filter this metadata
+by selected size and get the supported fps ranges,<wbr/> and use these fps ranges to setup the
+recording requests.<wbr/> Note that for the use case of multiple output streams,<wbr/> application
+must select one unique size from this metadata to use (e.<wbr/>g.,<wbr/> preview and recording streams
+must have the same size).<wbr/> Otherwise,<wbr/> the high speed capture session creation will fail.<wbr/></p>
+<p>The min and max fps will be multiple times of 30fps.<wbr/></p>
+<p>High speed video streaming extends significant performance pressue to camera hardware,<wbr/>
+to achieve efficient high speed streaming,<wbr/> the camera device may have to aggregate
+multiple frames together and send to camera device for processing where the request
+controls are same for all the frames in this batch.<wbr/> Max batch size indicates
+the max possible number of frames the camera device will group together for this high
+speed stream configuration.<wbr/> This max batch size will be used to generate a high speed
+recording request list by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/>
+The max batch size for each configuration will satisfy below conditions:</p>
+<ul>
+<li>Each max batch size will be a divisor of its corresponding fps_<wbr/>max /<wbr/> 30.<wbr/> For example,<wbr/>
+if max_<wbr/>fps is 300,<wbr/> max batch size will only be 1,<wbr/> 2,<wbr/> 5,<wbr/> or 10.<wbr/></li>
+<li>The camera device may choose smaller internal batch size for each configuration,<wbr/> but
+the actual batch size will be a divisor of max batch size.<wbr/> For example,<wbr/> if the max batch
+size is 8,<wbr/> the actual batch size used by camera device will only be 1,<wbr/> 2,<wbr/> 4,<wbr/> or 8.<wbr/></li>
+<li>The max batch size in each configuration entry must be no larger than 32.<wbr/></li>
+</ul>
+<p>The camera device doesn't have to support batch mode to achieve high speed video recording,<wbr/>
+in such case,<wbr/> batch_<wbr/>size_<wbr/>max will be reported as 1 in each configuration entry.<wbr/></p>
+<p>This fps ranges in this configuration list can only be used to create requests
+that are submitted to a high speed camera capture session created by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/>
+The fps ranges reported in this metadata must not be used to setup capture requests for
+normal capture session,<wbr/> or it will cause request error.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All the sizes listed in this configuration will be a subset of the sizes reported by
+<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> for processed non-stalling output formats.<wbr/>
+Note that for all high speed video configurations,<wbr/> HAL must be able to support a minimum
+of two streams,<wbr/> though the application might choose to configure just one stream.<wbr/></p>
+<p>The HAL may support multiple sensor modes for high speed outputs,<wbr/> for example,<wbr/> 120fps
+sensor mode and 120fps recording,<wbr/> 240fps sensor mode for 240fps recording.<wbr/> The application
+usually starts preview first,<wbr/> then starts recording.<wbr/> To avoid sensor mode switch caused
+stutter when starting recording as much as possible,<wbr/> the application may want to ensure
+the same sensor mode is used for preview and recording.<wbr/> Therefore,<wbr/> The HAL must advertise
+the variable fps range [30,<wbr/> fps_<wbr/>max] for each fixed fps range in this configuration list.<wbr/>
+For example,<wbr/> if the HAL advertises [120,<wbr/> 120] and [240,<wbr/> 240],<wbr/> the HAL must also advertise
+[30,<wbr/> 120] and [30,<wbr/> 240] for each configuration.<wbr/> In doing so,<wbr/> if the application intends to
+do 120fps recording,<wbr/> it can select [30,<wbr/> 120] to start preview,<wbr/> and [120,<wbr/> 120] to start
+recording.<wbr/> For these variable fps ranges,<wbr/> it's up to the HAL to decide the actual fps
+values that are suitable for smooth preview streaming.<wbr/> If the HAL sees different max_<wbr/>fps
+values that fall into different sensor modes in a sequence of requests,<wbr/> the HAL must
+switch the sensor mode as quick as possible to minimize the mode switch caused stutter.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.aeLockAvailable">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device supports <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Devices with MANUAL_<wbr/>SENSOR capability or BURST_<wbr/>CAPTURE capability will always
+list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.awbLockAvailable">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device supports <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Devices with MANUAL_<wbr/>POST_<wbr/>PROCESSING capability or BURST_<wbr/>CAPTURE capability will
+always list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.availableModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>available<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>mode).<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of control modes for <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This list contains control modes that can be set for the camera device.<wbr/>
+LEGACY mode devices will always support AUTO mode.<wbr/> LIMITED and FULL
+devices will always support OFF,<wbr/> AUTO modes.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.control.postRawSensitivityBoostRange">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+
+
+ <div class="entry_type_notes">Range of supported post RAW sensitivitiy boosts</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Range of boosts for <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> supported
+by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Devices support post RAW sensitivity boost will advertise
+<a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> key for controling
+post RAW sensitivity boost.<wbr/></p>
+<p>This key will be <code>null</code> for devices that do not support any RAW format
+outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
+present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
+list <code>(100,<wbr/> 100)</code> in this key.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key is added in HAL3.<wbr/>4.<wbr/> For HAL3.<wbr/>3 or earlier devices,<wbr/> camera framework will
+generate this key as <code>(100,<wbr/> 100)</code> if device supports any of RAW output formats.<wbr/>
+All HAL3.<wbr/>4 and above devices should list this key if device supports any of RAW
+output formats.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.control.aePrecaptureId">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Id
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The ID sent with the latest
+CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING call</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Must be 0 if no
+CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING trigger received yet
+by HAL.<wbr/> Always updated even if AE algorithm ignores the
+trigger</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeAntibandingMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to
+avoid banding problems.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">50HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
+avoid banding problems with 50Hz illumination sources.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">60HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
+avoid banding problems with 60Hz illumination
+sources.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its
+antibanding routine to the current illumination
+condition.<wbr/> This is the default mode if AUTO is
+available on given camera device.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired setting for the camera device's auto-exposure
+algorithm's antibanding compensation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent
+lights,<wbr/> flicker at the rate of the power supply frequency
+(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is
+typically not noticeable to a person,<wbr/> it can be visible to
+a camera device.<wbr/> If a camera sets its exposure time to the
+wrong value,<wbr/> the flicker may become visible in the
+viewfinder as flicker or in a final captured image,<wbr/> as a
+set of variable-brightness bands across the image.<wbr/></p>
+<p>Therefore,<wbr/> the auto-exposure routines of camera devices
+include antibanding routines that ensure that the chosen
+exposure value will not cause such banding.<wbr/> The choice of
+exposure time depends on the rate of flicker,<wbr/> which the
+camera device can detect automatically,<wbr/> or the expected
+rate can be selected by the application using this
+control.<wbr/></p>
+<p>A given camera device may not support all of the possible
+options for the antibanding mode.<wbr/> The
+<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains
+the available modes for a given camera device.<wbr/></p>
+<p>AUTO mode is the default if it is available on given
+camera device.<wbr/> When AUTO mode is not available,<wbr/> the
+default will be either 50HZ or 60HZ,<wbr/> and both 50HZ
+and 60HZ will be available.<wbr/></p>
+<p>If manual exposure control is enabled (by setting
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
+then this setting has no effect,<wbr/> and the application must
+ensure it selects exposure times that do not cause banding
+issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist
+the application in this.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For all capture request templates,<wbr/> this field must be set
+to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/>
+the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and
+60HZ must be available.<wbr/></p>
+<p>If manual exposure control is enabled (by setting
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
+then the exposure values provided by the application must not be
+adjusted for antibanding.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeExposureCompensation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Adjustment to auto-exposure (AE) target image
+brightness.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Compensation steps
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The adjustment is measured as a count of steps,<wbr/> with the
+step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the
+allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p>
+<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6'
+will mean an exposure compensation of +2 EV; -3 will mean an
+exposure compensation of -1 EV.<wbr/> One EV represents a doubling
+of image brightness.<wbr/> Note that this control will only be
+effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control
+will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p>
+<p>In the event of exposure compensation value being changed,<wbr/> camera device
+may take several frames to reach the newly requested exposure target.<wbr/>
+During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING
+state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will
+change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or
+FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeLock">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm
+is free to update its parameters.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm
+must not update the exposure and sensitivity parameters
+while the lock is active.<wbr/></p>
+<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes
+will still take effect while auto-exposure is locked.<wbr/></p>
+<p>Some rare LEGACY devices may not support
+this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-exposure (AE) is currently locked to its latest
+calculated values.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/>
+and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
+<p>Note that even when AE is locked,<wbr/> the flash may be fired if
+the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/>
+ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p>
+<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock
+is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p>
+<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>)
+when AE is already locked,<wbr/> the camera device will not change the exposure time
+(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
+parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
+is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the
+<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/>
+Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p>
+<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock
+the AE if AE is locked by the camera device internally during precapture metering
+sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an
+ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence
+will never succeed in a sequence of preview requests where AE lock is always set
+to <code>false</code>.<wbr/></p>
+<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
+get locked do not necessarily correspond to the settings that were present in the
+latest capture result received from the camera device,<wbr/> since additional captures
+and AE updates may have occurred even before the result was sent out.<wbr/> If an
+application is switching between automatic and manual control and wishes to eliminate
+any flicker during the switch,<wbr/> the following procedure is recommended:</p>
+<ol>
+<li>Starting in auto-AE mode:</li>
+<li>Lock AE</li>
+<li>Wait for the first result to be output that has the AE locked</li>
+<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li>
+<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li>
+</ol>
+<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p>
+<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera
+device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's
+a flash unit for this camera device.<wbr/></p>
+<p>Note that auto-white balance (AWB) and auto-focus (AF)
+behavior is device dependent when AE is in OFF mode.<wbr/>
+To have consistent behavior across different devices,<wbr/>
+it is recommended to either set AWB and AF to OFF mode
+or lock AWB and AF before setting AE to OFF.<wbr/>
+See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
+for more details.<wbr/></p>
+<p>LEGACY devices do not support the OFF mode and will
+override attempts to use this value to ON.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/>
+with no flash control.<wbr/></p>
+<p>The application's values for
+<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The
+application has control over the various
+android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_AUTO_FLASH</span>
+ <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
+the camera's flash unit,<wbr/> firing it in low-light
+conditions.<wbr/></p>
+<p>The flash may be fired during a precapture sequence
+(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
+may be fired for captures for which the
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
+STILL_<wbr/>CAPTURE</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span>
+ <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
+the camera's flash unit,<wbr/> always firing it for still
+captures.<wbr/></p>
+<p>The flash may be fired during a precapture sequence
+(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
+will always be fired for captures for which the
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
+STILL_<wbr/>CAPTURE</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span>
+ <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye
+reduction.<wbr/></p>
+<p>If deemed necessary by the camera device,<wbr/> a red eye
+reduction flash will fire during the precapture
+sequence.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired mode for the camera device's
+auto-exposure routine.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is
+AUTO.<wbr/></p>
+<p>When set to any of the ON modes,<wbr/> the camera device's
+auto-exposure routine is enabled,<wbr/> overriding the
+application's selected exposure time,<wbr/> sensor sensitivity,<wbr/>
+and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes
+is selected,<wbr/> the camera device's flash unit controls are
+also overridden.<wbr/></p>
+<p>The FLASH modes are only available if the camera device
+has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p>
+<p>If flash TORCH mode is desired,<wbr/> this field must be set to
+ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p>
+<p>When set to any of the ON modes,<wbr/> the values chosen by the
+camera device auto-exposure routine for the overridden
+fields for a given capture will be available in its
+CaptureResult.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of regions supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one
+region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0
+weight is ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeTargetFpsRange">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Range over which the auto-exposure routine can
+adjust the capture frame rate to maintain good
+exposure.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Frames per second (FPS)
+ </td>
+
+ <td class="entry_range">
+ <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not
+manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aePrecaptureTrigger">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">IDLE</span>
+ <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">START</span>
+ <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started
+by the camera device.<wbr/></p>
+<p>The exact effect of the precapture trigger depends on
+the current AE mode and state.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANCEL</span>
+ <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed
+precapture metering sequence,<wbr/> the auto-exposure routine will return to its
+initial state.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will trigger a precapture
+metering sequence when it processes this request.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is normally set to IDLE,<wbr/> or is not
+included at all in the request settings.<wbr/> When included and
+set to START,<wbr/> the camera device will trigger the auto-exposure (AE)
+precapture metering sequence.<wbr/></p>
+<p>When set to CANCEL,<wbr/> the camera device will cancel any active
+precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/>
+If a precapture metering sequence is already completed,<wbr/> and the camera
+device has implicitly locked the AE for subsequent still capture,<wbr/> the
+CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p>
+<p>The precapture sequence should be triggered before starting a
+high-quality still capture for final metering decisions to
+be made,<wbr/> and for firing pre-capture flash pulses to estimate
+scene brightness and required final capture flash power,<wbr/> when
+the flash is enabled.<wbr/></p>
+<p>Normally,<wbr/> this entry should be set to START for only a
+single request,<wbr/> and the application should wait until the
+sequence completes before starting a new one.<wbr/></p>
+<p>When a precapture metering sequence is finished,<wbr/> the camera device
+may lock the auto-exposure routine internally to be able to accurately expose the
+subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/>
+For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is
+submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should
+submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request
+with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a
+still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for
+API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device
+internally locked AE if the application doesn't submit a still capture request after
+the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not
+be used in devices that have earlier API levels.<wbr/></p>
+<p>The exact effect of auto-exposure (AE) precapture trigger
+depends on the current AE mode and state; see
+<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition
+details.<wbr/></p>
+<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported;
+capturing a high-resolution JPEG image will automatically trigger a
+precapture sequence before the high-resolution capture,<wbr/> including
+potentially firing a pre-capture flash.<wbr/></p>
+<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
+simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
+the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
+focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
+trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
+changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for
+example.<wbr/></p>
+<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then
+the camera device will complete them in the optimal order for that device.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active
+(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/> It is acceptable for the HAL to
+treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
+AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
+to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.aeState">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>ae<wbr/>State
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">INACTIVE</span>
+ <span class="entry_type_enum_notes"><p>AE is off or recently reset.<wbr/></p>
+<p>When a camera device is opened,<wbr/> it starts in
+this state.<wbr/> This is a transient state,<wbr/> the camera device may skip reporting
+this state in capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SEARCHING</span>
+ <span class="entry_type_enum_notes"><p>AE doesn't yet have a good set of control values
+for the current scene.<wbr/></p>
+<p>This is a transient state,<wbr/> the camera device may skip
+reporting this state in capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONVERGED</span>
+ <span class="entry_type_enum_notes"><p>AE has a good set of control values for the
+current scene.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">LOCKED</span>
+ <span class="entry_type_enum_notes"><p>AE has been locked.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FLASH_REQUIRED</span>
+ <span class="entry_type_enum_notes"><p>AE has a good set of control values,<wbr/> but flash
+needs to be fired for good quality still
+capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PRECAPTURE</span>
+ <span class="entry_type_enum_notes"><p>AE has been asked to do a precapture sequence
+and is currently executing it.<wbr/></p>
+<p>Precapture can be triggered through setting
+<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to START.<wbr/> Currently
+active and completed (if it causes camera device internal AE lock) precapture
+metering sequence can be canceled through setting
+<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to CANCEL.<wbr/></p>
+<p>Once PRECAPTURE completes,<wbr/> AE will transition to CONVERGED
+or FLASH_<wbr/>REQUIRED as appropriate.<wbr/> This is a transient
+state,<wbr/> the camera device may skip reporting this state in
+capture result.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current state of the auto-exposure (AE) algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Switching between or enabling AE modes (<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>) always
+resets the AE state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
+or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
+the algorithm states to INACTIVE.<wbr/></p>
+<p>The camera device can do several state transitions between two results,<wbr/> if it is
+allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be
+seen in a result.<wbr/></p>
+<p>The state in the result is the state for this image (in sync with this image): if
+AE state becomes CONVERGED,<wbr/> then the image data associated with this result should
+be good to use.<wbr/></p>
+<p>Below are state transition tables for different AE modes.<wbr/></p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center"></td>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device auto exposure algorithm is disabled</td>
+</tr>
+</tbody>
+</table>
+<p>When <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is AE_<wbr/>MODE_<wbr/>ON_<wbr/>*:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device initiates AE scan</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values changing</td>
+</tr>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">SEARCHING</td>
+<td align="center">Camera device finishes AE scan</td>
+<td align="center">CONVERGED</td>
+<td align="center">Good values,<wbr/> not changing</td>
+</tr>
+<tr>
+<td align="center">SEARCHING</td>
+<td align="center">Camera device finishes AE scan</td>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Converged but too dark w/<wbr/>o flash</td>
+</tr>
+<tr>
+<td align="center">SEARCHING</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">CONVERGED</td>
+<td align="center">Camera device initiates AE scan</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values changing</td>
+</tr>
+<tr>
+<td align="center">CONVERGED</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Camera device initiates AE scan</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values changing</td>
+</tr>
+<tr>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values not good after unlock</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
+<td align="center">CONVERGED</td>
+<td align="center">Values good after unlock</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Exposure good,<wbr/> but too dark</td>
+</tr>
+<tr>
+<td align="center">PRECAPTURE</td>
+<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
+<td align="center">CONVERGED</td>
+<td align="center">Ready for high-quality capture</td>
+</tr>
+<tr>
+<td align="center">PRECAPTURE</td>
+<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Ready for high-quality capture</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
+<td align="center">LOCKED</td>
+<td align="center">Precapture trigger is ignored when AE is already locked</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
+<td align="center">LOCKED</td>
+<td align="center">Precapture trigger is ignored when AE is already locked</td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START</td>
+<td align="center">PRECAPTURE</td>
+<td align="center">Start AE precapture metering sequence</td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Currently active precapture metering sequence is canceled</td>
+</tr>
+</tbody>
+</table>
+<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
+without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
+can be skipped in that manner is called a transient state.<wbr/></p>
+<p>For example,<wbr/> for above AE modes (AE_<wbr/>MODE_<wbr/>ON_<wbr/>*),<wbr/> in addition to the state transitions
+listed in above table,<wbr/> it is also legal for the camera device to skip one or more
+transient states between two results.<wbr/> See below table for examples:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device finished AE scan</td>
+<td align="center">CONVERGED</td>
+<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td>
+<td align="center">CONVERGED</td>
+<td align="center">Converged after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence is canceled,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">Any state (excluding LOCKED)</td>
+<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td>
+<td align="center">CONVERGED</td>
+<td align="center">Converged after a precapture sequenceis canceled,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">CONVERGED</td>
+<td align="center">Camera device finished AE scan</td>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Converged but too dark w/<wbr/>o flash after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">FLASH_<wbr/>REQUIRED</td>
+<td align="center">Camera device finished AE scan</td>
+<td align="center">CONVERGED</td>
+<td align="center">Converged after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+</tbody>
+</table>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.afMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens;
+<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the
+application.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p>
+<p>In this mode,<wbr/> the lens does not move unless
+the autofocus trigger action is called.<wbr/> When that trigger
+is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
+the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p>
+<p>Always supported if lens is not fixed focus.<wbr/></p>
+<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens
+is fixed-focus.<wbr/></p>
+<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/>
+and sets the AF state to INACTIVE.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MACRO</span>
+ <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p>
+<p>In this mode,<wbr/> the lens does not move unless the
+autofocus trigger action is called.<wbr/> When that trigger is
+activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
+the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This
+mode is optimized for focusing on objects very close to
+the camera.<wbr/></p>
+<p>When that trigger is activated,<wbr/> AF will transition to
+ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or
+NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens
+position to default,<wbr/> and sets the AF state to
+INACTIVE.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span>
+ <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
+position continually to attempt to provide a
+constantly-in-focus image stream.<wbr/></p>
+<p>The focusing behavior should be suitable for good quality
+video recording; typically this means slower focus
+movement and no overshoots.<wbr/> When the AF trigger is not
+involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/>
+and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED
+states as appropriate.<wbr/> When the AF trigger is activated,<wbr/>
+the algorithm should immediately transition into
+AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
+lens position until a cancel AF trigger is received.<wbr/></p>
+<p>Once cancel is received,<wbr/> the algorithm should transition
+back to INACTIVE and resume passive scan.<wbr/> Note that this
+behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an
+ongoing PASSIVE_<wbr/>SCAN must immediately be
+canceled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span>
+ <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
+position continually to attempt to provide a
+constantly-in-focus image stream.<wbr/></p>
+<p>The focusing behavior should be suitable for still image
+capture; typically this means focusing as fast as
+possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF
+algorithm should start in INACTIVE state,<wbr/> and then
+transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as
+appropriate as it attempts to maintain focus.<wbr/> When the AF
+trigger is activated,<wbr/> the algorithm should finish its
+PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into
+AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
+lens position until a cancel AF trigger is received.<wbr/></p>
+<p>When the AF cancel trigger is activated,<wbr/> the algorithm
+should transition back to INACTIVE and then act as if it
+has just been started.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">EDOF</span>
+ <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p>
+<p>The camera device will produce images with an extended
+depth of field automatically; no special focusing
+operations need to be done before taking a picture.<wbr/></p>
+<p>AF triggers are ignored,<wbr/> and the AF state will always be
+INACTIVE.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what
+mode it is set to.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus
+(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>).<wbr/> Also note that
+when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device
+dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before
+setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p>
+<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/>
+the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>
+in result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a
+request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end
+up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see
+<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is
+locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move
+after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that
+the same focal plane remains in focus.<wbr/></p>
+<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF
+scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger
+(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the
+same lock behavior as above.<wbr/></p>
+<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the
+focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/>
+However,<wbr/> the lens must not move regardless of the camera movement for any focus distance
+manual control.<wbr/></p>
+<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on
+camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to
+remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/>
+by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue
+that will arise on camera modules with open-loop VCMs.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.afRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-focus.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of focus areas supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region
+is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is
+ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.afTrigger">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>af<wbr/>Trigger
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">IDLE</span>
+ <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">START</span>
+ <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANCEL</span>
+ <span class="entry_type_enum_notes"><p>Autofocus will return to its initial
+state,<wbr/> and cancel any currently active trigger.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will trigger autofocus for this request.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is normally set to IDLE,<wbr/> or is not
+included at all in the request settings.<wbr/></p>
+<p>When included and set to START,<wbr/> the camera device will trigger the
+autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p>
+<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/>
+and return to its initial AF state.<wbr/></p>
+<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a
+single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying
+START for multiple captures in a row means restarting the AF operation over
+and over again.<wbr/></p>
+<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p>
+<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
+simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
+the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
+focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
+trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
+changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active
+(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/> It is acceptable for the HAL to
+treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
+AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
+to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.afState">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>af<wbr/>State
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">INACTIVE</span>
+ <span class="entry_type_enum_notes"><p>AF is off or has not yet tried to scan/<wbr/>been asked
+to scan.<wbr/></p>
+<p>When a camera device is opened,<wbr/> it starts in this
+state.<wbr/> This is a transient state,<wbr/> the camera device may
+skip reporting this state in capture
+result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PASSIVE_SCAN</span>
+ <span class="entry_type_enum_notes"><p>AF is currently performing an AF scan initiated the
+camera device in a continuous autofocus mode.<wbr/></p>
+<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient
+state,<wbr/> the camera device may skip reporting this state in
+capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PASSIVE_FOCUSED</span>
+ <span class="entry_type_enum_notes"><p>AF currently believes it is in focus,<wbr/> but may
+restart scanning at any time.<wbr/></p>
+<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient
+state,<wbr/> the camera device may skip reporting this state in
+capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ACTIVE_SCAN</span>
+ <span class="entry_type_enum_notes"><p>AF is performing an AF scan because it was
+triggered by AF trigger.<wbr/></p>
+<p>Only used by AUTO or MACRO AF modes.<wbr/> This is a transient
+state,<wbr/> the camera device may skip reporting this state in
+capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FOCUSED_LOCKED</span>
+ <span class="entry_type_enum_notes"><p>AF believes it is focused correctly and has locked
+focus.<wbr/></p>
+<p>This state is reached only after an explicit START AF trigger has been
+sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus has been obtained.<wbr/></p>
+<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or
+a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NOT_FOCUSED_LOCKED</span>
+ <span class="entry_type_enum_notes"><p>AF has failed to focus successfully and has locked
+focus.<wbr/></p>
+<p>This state is reached only after an explicit START AF trigger has been
+sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus cannot be obtained.<wbr/></p>
+<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or
+a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PASSIVE_UNFOCUSED</span>
+ <span class="entry_type_enum_notes"><p>AF finished a passive scan without finding focus,<wbr/>
+and may restart scanning at any time.<wbr/></p>
+<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient state,<wbr/> the camera
+device may skip reporting this state in capture result.<wbr/></p>
+<p>LEGACY camera devices do not support this state.<wbr/> When a passive
+scan has finished,<wbr/> it will always go to PASSIVE_<wbr/>FOCUSED.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current state of auto-focus (AF) algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Switching between or enabling AF modes (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) always
+resets the AF state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
+or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
+the algorithm states to INACTIVE.<wbr/></p>
+<p>The camera device can do several state transitions between two results,<wbr/> if it is
+allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be
+seen in a result.<wbr/></p>
+<p>The state in the result is the state for this image (in sync with this image): if
+AF state becomes FOCUSED,<wbr/> then the image data associated with this result should
+be sharp.<wbr/></p>
+<p>Below are state transition tables for different AF modes.<wbr/></p>
+<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>OFF or AF_<wbr/>MODE_<wbr/>EDOF:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center"></td>
+<td align="center">INACTIVE</td>
+<td align="center">Never changes</td>
+</tr>
+</tbody>
+</table>
+<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>AUTO or AF_<wbr/>MODE_<wbr/>MACRO:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">Start AF sweep,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">AF sweep done</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Focused,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">AF sweep done</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Not focused,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Cancel/<wbr/>reset AF,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Cancel/<wbr/>reset AF</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">Start new sweep,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Cancel/<wbr/>reset AF</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">ACTIVE_<wbr/>SCAN</td>
+<td align="center">Start new sweep,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">Any state</td>
+<td align="center">Mode change</td>
+<td align="center">INACTIVE</td>
+<td align="center"></td>
+</tr>
+</tbody>
+</table>
+<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
+without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
+can be skipped in that manner is called a transient state.<wbr/></p>
+<p>For example,<wbr/> for these AF modes (AF_<wbr/>MODE_<wbr/>AUTO and AF_<wbr/>MODE_<wbr/>MACRO),<wbr/> in addition to the
+state transitions listed in above table,<wbr/> it is also legal for the camera device to skip
+one or more transient states between two results.<wbr/> See below table for examples:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td>
+</tr>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Focus failed after a scan,<wbr/> lens is now locked.<wbr/></td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Focus is good after a scan,<wbr/> lens is not locked.<wbr/></td>
+</tr>
+</tbody>
+</table>
+<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>VIDEO:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF state query,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Camera device completes current scan</td>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">End AF scan,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Camera device fails current scan</td>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">End AF scan,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate transition,<wbr/> if focus is good.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate transition,<wbr/> if focus is bad.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Reset lens position,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate transition,<wbr/> lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate transition,<wbr/> lens now locked</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">No effect</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Restart AF scan</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">No effect</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Restart AF scan</td>
+</tr>
+</tbody>
+</table>
+<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>PICTURE:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF state query,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Camera device completes current scan</td>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">End AF scan,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Camera device fails current scan</td>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">End AF scan,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Eventual transition once the focus is good.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Eventual transition if cannot find focus.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Reset lens position,<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">Camera device initiates new scan</td>
+<td align="center">PASSIVE_<wbr/>SCAN</td>
+<td align="center">Start AF scan,<wbr/> Lens now moving</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>FOCUSED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate trans.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">Immediate trans.<wbr/> Lens now locked</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">No effect</td>
+</tr>
+<tr>
+<td align="center">FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Restart AF scan</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>TRIGGER</td>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">No effect</td>
+</tr>
+<tr>
+<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
+<td align="center">AF_<wbr/>CANCEL</td>
+<td align="center">INACTIVE</td>
+<td align="center">Restart AF scan</td>
+</tr>
+</tbody>
+</table>
+<p>When switch between AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>* (CAF modes) and AF_<wbr/>MODE_<wbr/>AUTO/<wbr/>AF_<wbr/>MODE_<wbr/>MACRO
+(AUTO modes),<wbr/> the initial INACTIVE or PASSIVE_<wbr/>SCAN states may be skipped by the
+camera device.<wbr/> When a trigger is included in a mode switch request,<wbr/> the trigger
+will be evaluated in the context of the new mode in the request.<wbr/>
+See below table for examples:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">any state</td>
+<td align="center">CAF-->AUTO mode switch</td>
+<td align="center">INACTIVE</td>
+<td align="center">Mode switch without trigger,<wbr/> initial state must be INACTIVE</td>
+</tr>
+<tr>
+<td align="center">any state</td>
+<td align="center">CAF-->AUTO mode switch with AF_<wbr/>TRIGGER</td>
+<td align="center">trigger-reachable states from INACTIVE</td>
+<td align="center">Mode switch with trigger,<wbr/> INACTIVE is skipped</td>
+</tr>
+<tr>
+<td align="center">any state</td>
+<td align="center">AUTO-->CAF mode switch</td>
+<td align="center">passively reachable states from INACTIVE</td>
+<td align="center">Mode switch without trigger,<wbr/> passive transient state is skipped</td>
+</tr>
+</tbody>
+</table>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.afTriggerId">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>af<wbr/>Trigger<wbr/>Id
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The ID sent with the latest
+CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS call</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Must be 0 if no CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS trigger
+received yet by HAL.<wbr/> Always updated even if AF algorithm
+ignores the trigger</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.awbLock">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB
+algorithm is free to update its parameters if in AUTO
+mode.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB
+algorithm will not update its parameters while the lock
+is active.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-white balance (AWB) is currently locked to its
+latest calculated values.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/>
+and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
+<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
+get locked do not necessarily correspond to the settings that were present in the
+latest capture result received from the camera device,<wbr/> since additional captures
+and AWB updates may have occurred even before the result was sent out.<wbr/> If an
+application is switching between automatic and manual control and wishes to eliminate
+any flicker during the switch,<wbr/> the following procedure is recommended:</p>
+<ol>
+<li>Starting in auto-AWB mode:</li>
+<li>Lock AWB</li>
+<li>Wait for the first result to be output that has the AWB locked</li>
+<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li>
+<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li>
+</ol>
+<p>Note that AWB lock is only meaningful when
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/>
+AWB is already fixed to a specific setting.<wbr/></p>
+<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.awbMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p>
+<p>The application-selected color transform matrix
+(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains
+(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera
+device for manual white balance control.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">INCANDESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses incandescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant A.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FLUORESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses fluorescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant F2.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">WARM_FLUORESCENT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses warm fluorescent light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant F4.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DAYLIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses daylight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>While the exact white balance transforms are up to the
+camera device,<wbr/> they will approximately match the CIE
+standard illuminant D65.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses cloudy daylight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TWILIGHT</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses twilight light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SHADE</span>
+ <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
+the camera device uses shade light as the assumed scene
+illumination for white balance.<wbr/></p>
+<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
+and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
+For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
+values used by the camera device for the transform and gains
+will be available in the capture result for this request.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether auto-white balance (AWB) is currently setting the color
+transform fields,<wbr/> and what its illumination target
+is.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p>
+<p>When set to the ON mode,<wbr/> the camera device's auto-white balance
+routine is enabled,<wbr/> overriding the application's selected
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
+is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to
+also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before
+setting AE mode to OFF.<wbr/></p>
+<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance
+routine is disabled.<wbr/> The application manually controls the white
+balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>
+and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p>
+<p>When set to any other modes,<wbr/> the camera device's auto-white
+balance routine is disabled.<wbr/> The camera device uses each
+particular illumination target for white balance
+adjustment.<wbr/> The application's values for
+<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/>
+<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
+<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.awbRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>awb<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5 x area_count
+ </span>
+ <span class="entry_type_visibility"> [public as meteringRectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of metering areas to use for auto-white-balance illuminant
+estimation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/>
+Otherwise will always be present.<wbr/></p>
+<p>The maximum number of regions supported by the device is determined by the value
+of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p>
+<p>The coordinate system is based on the active pixel array,<wbr/>
+with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
+(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
+bottom-right pixel in the active pixel array.<wbr/></p>
+<p>The weight must range from 0 to 1000,<wbr/> and represents a weight
+for every pixel in the area.<wbr/> This means that a large metering area
+with the same weight as a smaller area will have more effect in
+the metering result.<wbr/> Metering areas can partially overlap and the
+camera device will add the weights in the overlap region.<wbr/></p>
+<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if
+only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with
+0 weight is ignored.<wbr/></p>
+<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
+camera device.<wbr/></p>
+<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
+capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
+region and output only the intersection rectangle as the metering region in the result
+metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
+not reported in the result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL level representation of MeteringRectangle[] is a
+int[5 * area_<wbr/>count].<wbr/>
+Every five elements represent a metering region of
+(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
+The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
+exclusive on xmax and ymax.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.captureIntent">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>capture<wbr/>Intent
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CUSTOM</span>
+ <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other
+categories.<wbr/> The camera device will default to preview-like
+behavior.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PREVIEW</span>
+ <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p>
+<p>The precapture trigger may be used to start off a metering
+w/<wbr/>flash sequence.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STILL_CAPTURE</span>
+ <span class="entry_type_enum_notes"><p>This request is for a still capture-type
+use case.<wbr/></p>
+<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">VIDEO_RECORD</span>
+ <span class="entry_type_enum_notes"><p>This request is for a video recording
+use case.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span>
+ <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still
+image while recording video) use case.<wbr/></p>
+<p>The camera device should take the highest-quality image
+possible (given the other settings) without disrupting the
+frame rate of video recording.<wbr/> </p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the
+application will stream full-resolution images and
+reprocess one or several later for a final
+capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MANUAL</span>
+ <span class="entry_type_enum_notes"><p>This request is for manual capture use case where
+the applications want to directly control the capture parameters.<wbr/></p>
+<p>For example,<wbr/> the application may wish to manually control
+<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Information to the camera device 3A (auto-exposure,<wbr/>
+auto-focus,<wbr/> auto-white balance) routines about the purpose
+of this capture,<wbr/> to help the camera device to decide optimal 3A
+strategy.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control (except for MANUAL) is only effective if
+<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
+contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if
+<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are
+always supported.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.awbState">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>awb<wbr/>State
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">INACTIVE</span>
+ <span class="entry_type_enum_notes"><p>AWB is not in auto mode,<wbr/> or has not yet started metering.<wbr/></p>
+<p>When a camera device is opened,<wbr/> it starts in this
+state.<wbr/> This is a transient state,<wbr/> the camera device may
+skip reporting this state in capture
+result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SEARCHING</span>
+ <span class="entry_type_enum_notes"><p>AWB doesn't yet have a good set of control
+values for the current scene.<wbr/></p>
+<p>This is a transient state,<wbr/> the camera device
+may skip reporting this state in capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONVERGED</span>
+ <span class="entry_type_enum_notes"><p>AWB has a good set of control values for the
+current scene.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">LOCKED</span>
+ <span class="entry_type_enum_notes"><p>AWB has been locked.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current state of auto-white balance (AWB) algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Switching between or enabling AWB modes (<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>) always
+resets the AWB state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
+or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
+the algorithm states to INACTIVE.<wbr/></p>
+<p>The camera device can do several state transitions between two results,<wbr/> if it is
+allowed by the state transition table.<wbr/> So INACTIVE may never actually be seen in
+a result.<wbr/></p>
+<p>The state in the result is the state for this image (in sync with this image): if
+AWB state becomes CONVERGED,<wbr/> then the image data associated with this result should
+be good to use.<wbr/></p>
+<p>Below are state transition tables for different AWB modes.<wbr/></p>
+<p>When <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != AWB_<wbr/>MODE_<wbr/>AUTO</code>:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center"></td>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device auto white balance algorithm is disabled</td>
+</tr>
+</tbody>
+</table>
+<p>When <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is AWB_<wbr/>MODE_<wbr/>AUTO:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device initiates AWB scan</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values changing</td>
+</tr>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">SEARCHING</td>
+<td align="center">Camera device finishes AWB scan</td>
+<td align="center">CONVERGED</td>
+<td align="center">Good values,<wbr/> not changing</td>
+</tr>
+<tr>
+<td align="center">SEARCHING</td>
+<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">CONVERGED</td>
+<td align="center">Camera device initiates AWB scan</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values changing</td>
+</tr>
+<tr>
+<td align="center">CONVERGED</td>
+<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
+<td align="center">LOCKED</td>
+<td align="center">Values locked</td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td>
+<td align="center">SEARCHING</td>
+<td align="center">Values not good after unlock</td>
+</tr>
+</tbody>
+</table>
+<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
+without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
+can be skipped in that manner is called a transient state.<wbr/></p>
+<p>For example,<wbr/> for this AWB mode (AWB_<wbr/>MODE_<wbr/>AUTO),<wbr/> in addition to the state transitions
+listed in above table,<wbr/> it is also legal for the camera device to skip one or more
+transient states between two results.<wbr/> See below table for examples:</p>
+<table>
+<thead>
+<tr>
+<th align="center">State</th>
+<th align="center">Transition Cause</th>
+<th align="center">New State</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">INACTIVE</td>
+<td align="center">Camera device finished AWB scan</td>
+<td align="center">CONVERGED</td>
+<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+<tr>
+<td align="center">LOCKED</td>
+<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td>
+<td align="center">CONVERGED</td>
+<td align="center">Values good after unlock,<wbr/> transient states are skipped by camera device.<wbr/></td>
+</tr>
+</tbody>
+</table>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.effectMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>effect<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MONO</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into
+a single color.<wbr/></p>
+<p>This will typically be grayscale.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NEGATIVE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors
+are inverted.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SOLARIZE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the
+image is wholly or partially reversed in
+tone.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SEPIA</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm
+gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">POSTERIZE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses
+discrete regions of tone rather than a continuous
+gradient of tones.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">WHITEBOARD</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed
+as regions of white,<wbr/> with black or grey details.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BLACKBOARD</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed
+as regions of black,<wbr/> with white or grey details.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AQUA</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A special color effect to apply.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When this mode is set,<wbr/> a color effect will be applied
+to images produced by the camera device.<wbr/> The interpretation
+and implementation of these color effects is left to the
+implementor of the camera device,<wbr/> and should not be
+depended on to be consistent (or present) across all
+devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p>
+<p>All control by the device's metering and focusing (3A)
+routines is disabled,<wbr/> and no other settings in
+android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera
+device to select post-processing values for processing
+blocks that do not allow for manual control,<wbr/> or are not
+exposed by the camera API.<wbr/></p>
+<p>However,<wbr/> the camera device's 3A routines may continue to
+collect statistics and update their internal state so that
+when control is switched to AUTO mode,<wbr/> good control values
+can be immediately applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">AUTO</span>
+ <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p>
+<p>Manual control of capture parameters is disabled.<wbr/> All
+controls in android.<wbr/>control.<wbr/>* besides sceneMode take
+effect.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">USE_SCENE_MODE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p>
+<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and
+control.<wbr/>afMode controls; the camera device will ignore
+those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for
+FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/>
+This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/>
+<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>
+contain some modes other than DISABLED).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">OFF_KEEP_STATE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be
+used by camera device background auto-exposure,<wbr/> auto-white balance and
+auto-focus algorithms (3A) to update their statistics.<wbr/></p>
+<p>Specifically,<wbr/> the 3A routines are locked to the last
+values set from a request with AUTO,<wbr/> OFF,<wbr/> or
+USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates
+collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be
+discarded by the camera device.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control
+routines.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control
+by the camera device is disabled.<wbr/> The application must set the fields for
+capture parameters itself.<wbr/></p>
+<p>When set to AUTO,<wbr/> the individual algorithm controls in
+android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p>
+<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in
+android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements
+one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY)
+as it wishes.<wbr/> The camera device scene mode 3A settings are provided by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p>
+<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference
+is that this frame will not be used by camera device background 3A statistics
+update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario
+where the application doesn't want a 3A manual control capture to affect
+the subsequent auto 3A capture results.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.sceneMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>scene<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">DISABLED</span>
+ <span class="entry_type_enum_value">0</span>
+ <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FACE_PRIORITY</span>
+ <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face
+detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and
+auto-exposure routines.<wbr/></p>
+<p>If face detection statistics are disabled
+(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/>
+this should still operate correctly (but will not return
+face detection statistics to the framework).<wbr/></p>
+<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ACTION</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p>
+<p>Similar to SPORTS.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PORTRAIT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">LANDSCAPE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">NIGHT_PORTRAIT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light
+settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">THEATRE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must
+remain off.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BEACH</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SNOW</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SUNSET</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STEADYPHOTO</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of
+device motion (for example: due to hand shake).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FIREWORKS</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SPORTS</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p>
+<p>Similar to ACTION.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PARTY</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving
+people.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CANDLELIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source
+is a flame.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BARCODE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode
+for use by camera applications that wish to read the
+barcode value.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span>
+ <span class="entry_type_enum_deprecated">[deprecated]</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
+and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>
+for high speed video recording.<wbr/></p>
+<p>Optimized for high speed video recording (frame rate >=60fps) use case.<wbr/></p>
+<p>The supported high speed video sizes and fps ranges are specified in
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired
+output frame rates,<wbr/> the application is only allowed to select video size
+and fps range combinations listed in this static metadata.<wbr/> The fps range
+can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
+<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
+ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
+controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
+and post-processing parameters is possible.<wbr/> All other controls operate the
+same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
+android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
+<ul>
+<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
+<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
+<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
+<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
+<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
+</ul>
+<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
+<ul>
+<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li>
+<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
+<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
+<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li>
+</ul>
+<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
+be lower than what camera can output,<wbr/> depending on the destination Surfaces for
+the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
+the application need check if the video encoder is capable of supporting the
+high frame rate for a given video size,<wbr/> or it will end up with lower recording
+frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame
+rate will be bounded by the screen refresh rate.<wbr/></p>
+<p>The camera device will only support up to 2 output high speed streams
+(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>)
+in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p>
+<ul>
+<li>The application created no more than maxNumHighSpeedStreams processed non-stalling
+format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as
+min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li>
+<li>The stream sizes are selected from the sizes reported by
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li>
+<li>No processed non-stalling or raw streams are configured.<wbr/></li>
+</ul>
+<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and
+<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/>
+the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/>
+and the returned capture result metadata will give the fps range choosen
+by the camera device.<wbr/></p>
+<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor
+reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
+the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HDR</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p>
+<p>In this scene mode,<wbr/> the camera device captures images
+that keep a larger range of scene illumination levels
+visible in the final image.<wbr/> For example,<wbr/> when taking a
+picture of a object in front of a bright window,<wbr/> both
+the object and the scene through the window may be
+visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/>
+one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/>
+HDR mode generally takes much longer to capture a single
+image,<wbr/> has no user control,<wbr/> and may have other artifacts
+depending on the HDR method used.<wbr/></p>
+<p>Therefore,<wbr/> HDR captures operate at a much slower rate
+than regular captures.<wbr/></p>
+<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request
+is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of
+STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image
+using a high dynamic range capture technique.<wbr/> On LEGACY
+devices,<wbr/> captures that target a JPEG-format output will
+be captured with HDR,<wbr/> and the capture intent is not
+relevant.<wbr/></p>
+<p>The HDR capture may involve the device capturing a burst
+of images internally and combining them into one,<wbr/> or it
+may involve the device using specialized high dynamic
+range capture hardware.<wbr/> In all cases,<wbr/> a single image is
+produced in response to a capture request submitted
+while in HDR mode.<wbr/></p>
+<p>Since substantial post-processing is generally needed to
+produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG
+outputs are supported for LIMITED/<wbr/>FULL device HDR
+captures,<wbr/> and only JPEG outputs are supported for LEGACY
+HDR captures.<wbr/> Using a RAW output for HDR capture is not
+supported.<wbr/></p>
+<p>Some devices may also support always-on HDR,<wbr/> which
+applies HDR processing at full frame rate.<wbr/> For these
+devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also
+produce an HDR output with no frame rate impact compared
+to normal operation,<wbr/> though the quality may be lower
+than for STILL_<wbr/>CAPTURE intents.<wbr/></p>
+<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types
+or capture intents,<wbr/> the images captured will be as if
+the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera
+device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
+under low light conditions.<wbr/></p>
+<p>The camera device may be tuned to expose the images in a reduced
+sensitivity range to produce the best quality images.<wbr/> For example,<wbr/>
+if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/>
+the camera device auto-exposure routine tuning process may limit the actual
+exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't
+exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under
+low light may be under-exposed when the sensor max exposure time (bounded by the
+<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the
+ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the
+camera device auto-exposure routine to increase the sensitivity up to the max
+sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too
+dark and the max exposure time is reached.<wbr/> The captured images may be noisier
+compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is
+recommended that the application only use this scene mode when it is capable of
+reducing the noise level of the captured images.<wbr/></p>
+<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_value">100</span>
+ <span class="entry_type_enum_notes"><p>Scene mode values within the range of
+<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
+customized scene modes.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_hidden">[hidden]</span>
+ <span class="entry_type_enum_value">127</span>
+ <span class="entry_type_enum_notes"><p>Scene mode values within the range of
+<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
+customized scene modes.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Control for which scene mode is currently active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Scene modes are custom camera modes optimized for a certain set of conditions and
+capture settings.<wbr/></p>
+<p>This is the mode that that is active when
+<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will
+disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
+while in use.<wbr/></p>
+<p>The interpretation and implementation of these scene modes is left
+to the implementor of the camera device.<wbr/> Their behavior will not be
+consistent across all devices,<wbr/> and any given device may only implement
+a subset of these modes.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL implementations that include scene modes are expected to provide
+the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in
+<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p>
+<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/>
+the HAL must list supported video size and fps range in
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/>
+1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming
+mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture
+requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/>
+This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement
+<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO
+capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.videoStabilizationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether video stabilization is
+active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Video stabilization automatically warps images from
+the camera in order to stabilize motion between consecutive frames.<wbr/></p>
+<p>If enabled,<wbr/> video stabilization can modify the
+<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p>
+<p>Switching between different video stabilization modes may take several
+frames to initialize,<wbr/> the camera device will report the current mode
+in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/>
+the video stabilization modes in the first several capture results may
+still be "OFF",<wbr/> and it will become "ON" when the initialization is
+done.<wbr/></p>
+<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for
+stabilization by a device that reports stabilization support.<wbr/> It is guaranteed
+that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+the recording resolution is less than or equal to 1920 x 1080 (width less than
+or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording
+frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the CaptureResult
+<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return
+OFF if the recording output is not stabilized,<wbr/> or if there are no output
+Surface types that can be stabilized.<wbr/></p>
+<p>If a camera device supports both this mode and OIS
+(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may
+produce undesirable interaction,<wbr/> so it is recommended not to enable
+both at the same time.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.control.postRawSensitivityBoost">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of additional sensitivity boost applied to output images
+after RAW sensor data is captured.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Some camera devices support additional digital sensitivity boosting in the
+camera processing pipeline after sensor RAW image is captured.<wbr/>
+Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not
+have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p>
+<p>This key will be <code>null</code> for devices that do not support any RAW format
+outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
+present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
+list <code>100</code> in this key.<wbr/></p>
+<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the
+boost to the nearest supported value.<wbr/>
+The final boost value used will be available in the output capture result.<wbr/></p>
+<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images
+of such device will have the total sensitivity of
+<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code>
+The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_demosaic" class="section">demosaic</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.demosaic.mode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>demosaic.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Minimal or no slowdown of frame rate compared to
+Bayer RAW output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Improved processing quality but the frame rate might be slowed down
+relative to raw output.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Controls the quality of the demosaicing
+processing.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_edge" class="section">edge</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.edge.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>edge.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate
+relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will
+slow down frame rate relative to sensor.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/>
+based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have
+edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement
+applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that
+frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it
+is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p>
+<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
+with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
+high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
+produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the
+high-resolution buffers must not have edge enhancement applied to maximize efficiency of
+preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution
+buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for
+reasonable preview quality.<wbr/></p>
+<p>This mode is guaranteed to be supported by devices that support either the
+YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
+(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
+be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operation mode for edge
+enhancement.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means
+no enhancement will be applied by the camera device.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement
+will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the
+camera device will use the highest-quality enhancement algorithms,<wbr/>
+even if it slows down capture rate.<wbr/> FAST means the camera device will
+not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if
+edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar
+amount of enhancement applied.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
+buffer of high-resolution images during preview and reprocess image(s) from that buffer
+into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
+edge enhancement to low-resolution streams (below maximum recording resolution) to
+maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/>
+since those will be reprocessed later if necessary.<wbr/></p>
+<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera
+device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/>
+The camera device may adjust its internal edge enhancement parameters for best
+image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
+adjust the internal edge enhancement reduction parameters appropriately to get the best
+quality images.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.edge.strength">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>edge.<wbr/>strength
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Control the amount of edge enhancement
+applied to the images</p>
+ </td>
+
+ <td class="entry_units">
+ 1-10; 10 is maximum sharpening
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.edge.availableEdgeModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of edge enhancement modes for <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Full-capability camera devices must always support OFF; camera devices that support
+YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will list ZERO_<wbr/>SHUTTER_<wbr/>LAG; all devices will
+list FAST.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if edge enhancement control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.edge.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>edge.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate
+relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will
+slow down frame rate relative to sensor.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/>
+based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have
+edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement
+applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that
+frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it
+is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p>
+<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
+with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
+high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
+produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the
+high-resolution buffers must not have edge enhancement applied to maximize efficiency of
+preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution
+buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for
+reasonable preview quality.<wbr/></p>
+<p>This mode is guaranteed to be supported by devices that support either the
+YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
+(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
+be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operation mode for edge
+enhancement.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means
+no enhancement will be applied by the camera device.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement
+will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the
+camera device will use the highest-quality enhancement algorithms,<wbr/>
+even if it slows down capture rate.<wbr/> FAST means the camera device will
+not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if
+edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar
+amount of enhancement applied.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
+buffer of high-resolution images during preview and reprocess image(s) from that buffer
+into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
+edge enhancement to low-resolution streams (below maximum recording resolution) to
+maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/>
+since those will be reprocessed later if necessary.<wbr/></p>
+<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera
+device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/>
+The camera device may adjust its internal edge enhancement parameters for best
+image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
+adjust the internal edge enhancement reduction parameters appropriately to get the best
+quality images.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_flash" class="section">flash</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.flash.firingPower">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>firing<wbr/>Power
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Power for flash firing/<wbr/>torch</p>
+ </td>
+
+ <td class="entry_units">
+ 10 is max power; 0 is no flash.<wbr/> Linear
+ </td>
+
+ <td class="entry_range">
+ <p>0 - 10</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Power for snapshot may use a different scale than
+for torch mode.<wbr/> Only one entry for torch mode will be
+used</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.flash.firingTime">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>firing<wbr/>Time
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Firing time of flash relative to start of
+exposure</p>
+ </td>
+
+ <td class="entry_units">
+ nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>0-(exposure time-flash duration)</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Clamped to (0,<wbr/> exposure time - flash
+duration).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.flash.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SINGLE</span>
+ <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash
+for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TORCH</span>
+ <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired mode for for the camera device's flash control.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective when flash unit is available
+(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p>
+<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/>
+Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/>
+ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p>
+<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p>
+<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera
+device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this
+control should be used along with auto-exposure (AE) precapture metering sequence
+(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p>
+<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used
+for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p>
+<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.flash.info.available">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>info.<wbr/>available
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether this camera device has a
+flash unit.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Will be <code>false</code> if no flash is available.<wbr/></p>
+<p>If there is no flash unit,<wbr/> none of the flash controls do
+anything.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.flash.info.chargeDuration">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>info.<wbr/>charge<wbr/>Duration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Time taken before flash can fire
+again</p>
+ </td>
+
+ <td class="entry_units">
+ nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>0-1e9</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>1 second too long/<wbr/>too short for recharge? Should
+this be power-dependent?</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+
+
+ <tr class="entry" id="static_android.flash.colorTemperature">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>flash.<wbr/>color<wbr/>Temperature
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The x,<wbr/>y whitepoint of the
+flash</p>
+ </td>
+
+ <td class="entry_units">
+ pair of floats
+ </td>
+
+ <td class="entry_range">
+ <p>0-1 for both</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.flash.maxEnergy">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>flash.<wbr/>max<wbr/>Energy
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Max energy output of the flash for a full
+power single flash</p>
+ </td>
+
+ <td class="entry_units">
+ lumen-seconds
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.flash.firingPower">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>firing<wbr/>Power
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Power for flash firing/<wbr/>torch</p>
+ </td>
+
+ <td class="entry_units">
+ 10 is max power; 0 is no flash.<wbr/> Linear
+ </td>
+
+ <td class="entry_range">
+ <p>0 - 10</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Power for snapshot may use a different scale than
+for torch mode.<wbr/> Only one entry for torch mode will be
+used</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.flash.firingTime">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>firing<wbr/>Time
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Firing time of flash relative to start of
+exposure</p>
+ </td>
+
+ <td class="entry_units">
+ nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>0-(exposure time-flash duration)</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Clamped to (0,<wbr/> exposure time - flash
+duration).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.flash.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SINGLE</span>
+ <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash
+for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TORCH</span>
+ <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired mode for for the camera device's flash control.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control is only effective when flash unit is available
+(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p>
+<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/>
+Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/>
+ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p>
+<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p>
+<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera
+device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this
+control should be used along with auto-exposure (AE) precapture metering sequence
+(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p>
+<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used
+for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p>
+<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.flash.state">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>state
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">UNAVAILABLE</span>
+ <span class="entry_type_enum_notes"><p>No flash on camera.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CHARGING</span>
+ <span class="entry_type_enum_notes"><p>Flash is charging and cannot be fired.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">READY</span>
+ <span class="entry_type_enum_notes"><p>Flash is ready to fire.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FIRED</span>
+ <span class="entry_type_enum_notes"><p>Flash fired for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PARTIAL</span>
+ <span class="entry_type_enum_notes"><p>Flash partially illuminated this frame.<wbr/></p>
+<p>This is usually due to the next or previous frame having
+the flash fire,<wbr/> and the flash spilling into this capture
+due to hardware limitations.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current state of the flash
+unit.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When the camera device doesn't have flash unit
+(i.<wbr/>e.<wbr/> <code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == false</code>),<wbr/> this state will always be UNAVAILABLE.<wbr/>
+Other states indicate the current flash status.<wbr/></p>
+<p>In certain conditions,<wbr/> this will be available on LEGACY devices:</p>
+<ul>
+<li>Flash-less cameras always return UNAVAILABLE.<wbr/></li>
+<li>Using <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> ON_<wbr/>ALWAYS_<wbr/>FLASH
+ will always return FIRED.<wbr/></li>
+<li>Using <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> TORCH
+ will always return FIRED.<wbr/></li>
+</ul>
+<p>In all other conditions the state will not be available on
+LEGACY devices (i.<wbr/>e.<wbr/> it will be <code>null</code>).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_hotPixel" class="section">hotPixel</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.hotPixel.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>hot<wbr/>Pixel.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p>
+<p>The frame rate must not be reduced relative to sensor raw output
+for this option.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame
+rate relative to sensor raw output.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost
+of possibly reduced frame rate relative to sensor raw output.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operational mode for hot pixel correction.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels
+that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that
+are stuck at an arbitrary value or are oversensitive).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.hotPixel.availableHotPixelModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of hot pixel correction modes for <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a> that are supported by this
+camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>FULL mode camera devices will always support FAST.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>To avoid performance issues,<wbr/> there will be significantly fewer hot
+pixels than actual pixels on the camera sensor.<wbr/>
+HAL must support both FAST and HIGH_<wbr/>QUALITY if hot pixel correction control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.hotPixel.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>hot<wbr/>Pixel.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p>
+<p>The frame rate must not be reduced relative to sensor raw output
+for this option.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame
+rate relative to sensor raw output.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost
+of possibly reduced frame rate relative to sensor raw output.<wbr/></p>
+<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operational mode for hot pixel correction.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels
+that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that
+are stuck at an arbitrary value or are oversensitive).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_jpeg" class="section">jpeg</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.jpeg.gpsLocation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Location
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [java_public as location]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A location object to use when generating image GPS metadata.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Setting a location object in a request will include the GPS coordinates of the location
+into any JPEG images captured based on the request.<wbr/> These coordinates can then be
+viewed by anyone who receives the JPEG image.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.gpsCoordinates">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">double</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>GPS coordinates to include in output JPEG
+EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.gpsProcessingMethod">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [ndk_public as string]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>32 characters describing GPS algorithm to
+include in EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ UTF-8 null-terminated string
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.gpsTimestamp">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Time GPS fix was made to include in
+EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ UTC in seconds since January 1,<wbr/> 1970
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.orientation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>orientation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The orientation for a JPEG image.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Degrees in multiples of 90
+ </td>
+
+ <td class="entry_range">
+ <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation
+to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed
+upright.<wbr/></p>
+<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or
+rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/>
+the thumbnail data will also be rotated.<wbr/></p>
+<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given
+by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p>
+<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following
+sample code may be used:</p>
+<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) {
+ if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0;
+ int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION);
+
+ //<wbr/> Round device orientation to a multiple of 90
+ deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90;
+
+ //<wbr/> Reverse device orientation for front-facing cameras
+ boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT;
+ if (facingFront) deviceOrientation = -deviceOrientation;
+
+ //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make
+ //<wbr/> the image upright relative to the device orientation
+ int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
+
+ return jpegOrientation;
+}
+</code></pre>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.quality">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>quality
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Compression quality of the final JPEG
+image.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>1-100; larger is higher quality</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>85-95 is typical usage range.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.thumbnailQuality">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Compression quality of JPEG
+thumbnail.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>1-100; larger is higher quality</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.jpeg.thumbnailSize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as size]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Resolution of embedded JPEG thumbnail.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/>
+but the captured JPEG will still be a valid image.<wbr/></p>
+<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected
+should have the same aspect ratio as the main JPEG output.<wbr/></p>
+<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
+ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/>
+For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has
+16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to
+generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field
+Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p>
+<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/>
+the camera device will handle thumbnail rotation in one of the following ways:</p>
+<ul>
+<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
+ and keep jpeg and thumbnail image data unrotated.<wbr/></li>
+<li>Rotate the jpeg and thumbnail image data and not set
+ <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this
+ case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in
+ capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree
+ orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail
+ size.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/>
+The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/>
+The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the
+thumbnail image cropping.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.jpeg.availableThumbnailSizes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2 x n
+ </span>
+ <span class="entry_type_visibility"> [public as size]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of JPEG thumbnail sizes for <a href="#controls_android.jpeg.thumbnailSize">android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size</a> supported by this
+camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This list will include at least one non-zero resolution,<wbr/> plus <code>(0,<wbr/>0)</code> for indicating no
+thumbnail should be generated.<wbr/></p>
+<p>Below condiditions will be satisfied for this size list:</p>
+<ul>
+<li>The sizes will be sorted by increasing pixel area (width x height).<wbr/>
+If several resolutions have the same area,<wbr/> they will be sorted by increasing width.<wbr/></li>
+<li>The aspect ratio of the largest thumbnail size will be same as the
+aspect ratio of largest JPEG output size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/>
+The largest size is defined as the size that has the largest pixel area
+in a given size list.<wbr/></li>
+<li>Each output JPEG size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have at least
+one corresponding size that has the same aspect ratio in availableThumbnailSizes,<wbr/>
+and vice versa.<wbr/></li>
+<li>All non-<code>(0,<wbr/> 0)</code> sizes will have non-zero widths and heights.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.jpeg.maxSize">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>max<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum size in bytes for the compressed
+JPEG buffer</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Must be large enough to fit any JPEG produced by
+the camera</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is used for sizing the gralloc buffers for
+JPEG</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.jpeg.gpsLocation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Location
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [java_public as location]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A location object to use when generating image GPS metadata.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Setting a location object in a request will include the GPS coordinates of the location
+into any JPEG images captured based on the request.<wbr/> These coordinates can then be
+viewed by anyone who receives the JPEG image.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.gpsCoordinates">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">double</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>GPS coordinates to include in output JPEG
+EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.gpsProcessingMethod">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [ndk_public as string]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>32 characters describing GPS algorithm to
+include in EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ UTF-8 null-terminated string
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.gpsTimestamp">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Time GPS fix was made to include in
+EXIF.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ UTC in seconds since January 1,<wbr/> 1970
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.orientation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>orientation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The orientation for a JPEG image.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Degrees in multiples of 90
+ </td>
+
+ <td class="entry_range">
+ <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation
+to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed
+upright.<wbr/></p>
+<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or
+rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/>
+the thumbnail data will also be rotated.<wbr/></p>
+<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given
+by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p>
+<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following
+sample code may be used:</p>
+<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) {
+ if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0;
+ int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION);
+
+ //<wbr/> Round device orientation to a multiple of 90
+ deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90;
+
+ //<wbr/> Reverse device orientation for front-facing cameras
+ boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT;
+ if (facingFront) deviceOrientation = -deviceOrientation;
+
+ //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make
+ //<wbr/> the image upright relative to the device orientation
+ int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
+
+ return jpegOrientation;
+}
+</code></pre>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.quality">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>quality
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Compression quality of the final JPEG
+image.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>1-100; larger is higher quality</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>85-95 is typical usage range.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.size">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>jpeg.<wbr/>size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The size of the compressed JPEG image,<wbr/> in
+bytes</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If no JPEG output is produced for the request,<wbr/>
+this must be 0.<wbr/></p>
+<p>Otherwise,<wbr/> this describes the real size of the compressed
+JPEG image placed in the output stream.<wbr/> More specifically,<wbr/>
+if <a href="#static_android.jpeg.maxSize">android.<wbr/>jpeg.<wbr/>max<wbr/>Size</a> = 1000000,<wbr/> and a specific capture
+has <a href="#dynamic_android.jpeg.size">android.<wbr/>jpeg.<wbr/>size</a> = 500000,<wbr/> then the output buffer from
+the JPEG stream will be 1000000 bytes,<wbr/> of which the first
+500000 make up the real data.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.thumbnailQuality">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Compression quality of JPEG
+thumbnail.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>1-100; larger is higher quality</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.jpeg.thumbnailSize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as size]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Resolution of embedded JPEG thumbnail.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/>
+but the captured JPEG will still be a valid image.<wbr/></p>
+<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected
+should have the same aspect ratio as the main JPEG output.<wbr/></p>
+<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
+ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/>
+For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has
+16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to
+generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field
+Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p>
+<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/>
+the camera device will handle thumbnail rotation in one of the following ways:</p>
+<ul>
+<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
+ and keep jpeg and thumbnail image data unrotated.<wbr/></li>
+<li>Rotate the jpeg and thumbnail image data and not set
+ <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this
+ case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in
+ capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree
+ orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail
+ size.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/>
+The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/>
+The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the
+thumbnail image cropping.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_lens" class="section">lens</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.lens.aperture">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>aperture
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the
+effective aperture diameter.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ The f-number (f/<wbr/>N)
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Setting this value is only supported on the camera devices that have a variable
+aperture lens.<wbr/></p>
+<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/>
+this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>
+to achieve manual exposure control.<wbr/></p>
+<p>The requested aperture value may take several frames to reach the
+requested value; the camera device will report the current (intermediate)
+aperture size in capture result metadata while the aperture is changing.<wbr/>
+While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
+<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of
+the ON modes,<wbr/> this will be overridden by the camera device
+auto-exposure algorithm,<wbr/> the overridden values are then provided
+back to the user in the corresponding result.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.lens.filterDensity">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>filter<wbr/>Density
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired setting for the lens neutral density filter(s).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Exposure Value (EV)
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control will not be supported on most camera devices.<wbr/></p>
+<p>Lens filters are typically used to lower the amount of light the
+sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV
+step is the standard logarithmic representation,<wbr/> which are
+non-negative,<wbr/> and inversely proportional to the amount of light
+hitting the sensor.<wbr/> For example,<wbr/> setting this to 0 would result
+in no reduction of the incoming light,<wbr/> and setting this to 2 would
+mean that the filter is set to reduce incoming light by two stops
+(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p>
+<p>It may take several frames before the lens filter density changes
+to the requested value.<wbr/> While the filter density is still changing,<wbr/>
+<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.lens.focalLength">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>focal<wbr/>Length
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired lens focal length; used for optical zoom.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Millimeters
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This setting controls the physical focal length of the camera
+device's lens.<wbr/> Changing the focal length changes the field of
+view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p>
+<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this
+setting won't be applied instantaneously,<wbr/> and it may take several
+frames before the lens can change to the requested focal length.<wbr/>
+While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will
+be set to MOVING.<wbr/></p>
+<p>Optical zoom will not be supported on most devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.lens.focusDistance">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>focus<wbr/>Distance
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Desired distance to plane of sharpest focus,<wbr/>
+measured from frontmost surface of the lens.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control can be used for setting manual focus,<wbr/> on devices that support
+the MANUAL_<wbr/>SENSOR capability and have a variable-focus lens (see
+<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>).<wbr/></p>
+<p>A value of <code>0.<wbr/>0f</code> means infinity focus.<wbr/> The value set will be clamped to
+<code>[0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>.<wbr/></p>
+<p>Like <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> this setting won't be applied
+instantaneously,<wbr/> and it may take several frames before the lens
+can move to the requested focus distance.<wbr/> While the lens is still moving,<wbr/>
+<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
+<p>LEGACY devices support at most setting this to <code>0.<wbr/>0f</code>
+for infinity focus.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.lens.opticalStabilizationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Sets whether the camera device uses optical image stabilization (OIS)
+when capturing images.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>OIS is used to compensate for motion blur due to small
+movements of the camera during capture.<wbr/> Unlike digital image
+stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS
+makes use of mechanical elements to stabilize the camera
+sensor,<wbr/> and thus allows for longer exposure times before
+camera shake becomes apparent.<wbr/></p>
+<p>Switching between different optical stabilization modes may take several
+frames to initialize,<wbr/> the camera device will report the current mode in
+capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the
+optical stabilization modes in the first several capture results may still
+be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p>
+<p>If a camera device supports both OIS and digital image stabilization
+(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable
+interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p>
+<p>Not all devices will support OIS; see
+<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for
+available controls.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.lens.info.availableApertures">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of aperture size values for <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ The aperture f-number
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the camera device doesn't support a variable lens aperture,<wbr/>
+this list will contain only one value,<wbr/> which is the fixed aperture size.<wbr/></p>
+<p>If the camera device supports a variable aperture,<wbr/> the aperture values
+in this list will be sorted in ascending order.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.availableFilterDensities">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of neutral density filter values for
+<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Exposure value (EV)
+ </td>
+
+ <td class="entry_range">
+ <p>Values are >= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If a neutral density filter is not supported by this camera device,<wbr/>
+this list will contain only 0.<wbr/> Otherwise,<wbr/> this list will include every
+filter density supported by the camera device,<wbr/> in ascending order.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.availableFocalLengths">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">The list of available focal lengths</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of focal lengths for <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Millimeters
+ </td>
+
+ <td class="entry_range">
+ <p>Values are > 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If optical zoom is not supported,<wbr/> this list will only contain
+a single value corresponding to the fixed focal length of the
+device.<wbr/> Otherwise,<wbr/> this list will include every focal length supported
+by the camera device,<wbr/> in ascending order.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.availableOpticalStabilization">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of optical image stabilization (OIS) modes for
+<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If OIS is not supported by a given camera device,<wbr/> this list will
+contain only OFF.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.hyperfocalDistance">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Hyperfocal distance for this lens.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
+ </td>
+
+ <td class="entry_range">
+ <p>If lens is fixed focus,<wbr/> >= 0.<wbr/> If lens has focuser unit,<wbr/> the value is
+within <code>(0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the lens is not fixed focus,<wbr/> the camera device will report this
+field when <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> is APPROXIMATE or CALIBRATED.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.minimumFocusDistance">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Shortest distance from frontmost surface
+of the lens that can be brought into sharp focus.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the lens is fixed-focus,<wbr/> this will be
+0.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Mandatory for FULL devices; LIMITED devices
+must always set this value to 0 for fixed-focus; and may omit
+the minimum focus distance otherwise.<wbr/></p>
+<p>This field is also mandatory for all devices advertising
+the MANUAL_<wbr/>SENSOR capability.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.shadingMapSize">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as size]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">width and height (N,<wbr/> M) of lens shading map provided by the camera device.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Dimensions of lens shading map.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Both values >= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The map should be on the order of 30-40 rows and columns,<wbr/> and
+must be smaller than 64x64.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.info.focusDistanceCalibration">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">UNCALIBRATED</span>
+ <span class="entry_type_enum_notes"><p>The lens focus distance is not accurate,<wbr/> and the units used for
+<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> do not correspond to any physical units.<wbr/></p>
+<p>Setting the lens to the same focus distance on separate occasions may
+result in a different real focus distance,<wbr/> depending on factors such
+as the orientation of the device,<wbr/> the age of the focusing mechanism,<wbr/>
+and the device temperature.<wbr/> The focus distance value will still be
+in the range of <code>[0,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>,<wbr/> where 0
+represents the farthest focus.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">APPROXIMATE</span>
+ <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters.<wbr/></p>
+<p>However,<wbr/> setting the lens to the same focus distance
+on separate occasions may result in a different real
+focus distance,<wbr/> depending on factors such as the
+orientation of the device,<wbr/> the age of the focusing
+mechanism,<wbr/> and the device temperature.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CALIBRATED</span>
+ <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters,<wbr/> and
+is calibrated.<wbr/></p>
+<p>The lens mechanism is calibrated so that setting the
+same focus distance is repeatable on multiple
+occasions with good accuracy,<wbr/> and the focus distance
+corresponds to the real physical distance to the plane
+of best focus.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The lens focus distance calibration quality.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The lens focus distance calibration quality determines the reliability of
+focus related metadata entries,<wbr/> i.<wbr/>e.<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
+<a href="#dynamic_android.lens.focusRange">android.<wbr/>lens.<wbr/>focus<wbr/>Range</a>,<wbr/> <a href="#static_android.lens.info.hyperfocalDistance">android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance</a>,<wbr/> and
+<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>.<wbr/></p>
+<p>APPROXIMATE and CALIBRATED devices report the focus metadata in
+units of diopters (1/<wbr/>meter),<wbr/> so <code>0.<wbr/>0f</code> represents focusing at infinity,<wbr/>
+and increasing positive numbers represent focusing closer and closer
+to the camera device.<wbr/> The focus distance control also uses diopters
+on these devices.<wbr/></p>
+<p>UNCALIBRATED devices do not use units that are directly comparable
+to any real physical measurement,<wbr/> but <code>0.<wbr/>0f</code> still represents farthest
+focus,<wbr/> and <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> represents the
+nearest focus the device can achieve.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For devices advertise APPROXIMATE quality or higher,<wbr/> diopters 0 (infinity
+focus) must work.<wbr/> When autofocus is disabled (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> == OFF)
+and the lens focus distance is set to 0 diopters
+(<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> == 0),<wbr/> the lens will move to focus at infinity
+and is stably focused at infinity even if the device tilts.<wbr/> It may take the
+lens some time to move; during the move the lens state should be MOVING and
+the output diopter value should be changing toward 0.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+
+
+ <tr class="entry" id="static_android.lens.facing">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>lens.<wbr/>facing
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FRONT</span>
+ <span class="entry_type_enum_notes"><p>The camera device faces the same direction as the device's screen.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BACK</span>
+ <span class="entry_type_enum_notes"><p>The camera device faces the opposite direction as the device's screen.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">EXTERNAL</span>
+ <span class="entry_type_enum_notes"><p>The camera device is an external camera,<wbr/> and has no fixed facing relative to the
+device's screen.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Direction the camera faces relative to
+device screen.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.poseRotation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>pose<wbr/>Rotation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The orientation of the camera relative to the sensor
+coordinate system.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Quaternion coefficients
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The four coefficients that describe the quaternion
+rotation from the Android sensor coordinate system to a
+camera-aligned coordinate system where the X-axis is
+aligned with the long side of the image sensor,<wbr/> the Y-axis
+is aligned with the short side of the image sensor,<wbr/> and
+the Z-axis is aligned with the optical axis of the sensor.<wbr/></p>
+<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code>
+to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation
+amount <code>theta</code>,<wbr/> the following formulas can be used:</p>
+<pre><code> theta = 2 * acos(w)
+a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2)
+a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2)
+a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2)
+</code></pre>
+<p>To create a 3x3 rotation matrix that applies the rotation
+defined by this quaternion,<wbr/> the following matrix can be
+used:</p>
+<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/> 2xy - 2zw,<wbr/> 2xz + 2yw,<wbr/>
+ 2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/> 2yz - 2xw,<wbr/>
+ 2xz - 2yw,<wbr/> 2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ]
+</code></pre>
+<p>This matrix can then be used to apply the rotation to a
+ column vector point with</p>
+<p><code>p' = Rp</code></p>
+<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and
+ <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.poseTranslation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>pose<wbr/>Translation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Position of the camera optical center.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Meters
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The position of the camera device's lens optical center,<wbr/>
+as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the
+optical center of the largest camera device facing in the
+same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate
+axes</a>.<wbr/> Note that only the axis definitions are shared with
+the sensor coordinate system,<wbr/> but not the origin.<wbr/></p>
+<p>If this device is the largest or only camera device with a
+given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a
+camera device with a lens optical center located 3 cm from
+the main sensor along the +X axis (to the right from the
+user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p>
+<p>To transform a pixel coordinates between two cameras
+facing the same direction,<wbr/> first the source camera
+<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/> Then
+the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs
+to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a>
+of the source camera,<wbr/> the translation of the source camera
+relative to the destination camera,<wbr/> the
+<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and
+finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a>
+of the destination camera.<wbr/> This obtains a
+radial-distortion-free coordinate in the destination
+camera pixel coordinates.<wbr/></p>
+<p>To compare this against a real image from the destination
+camera,<wbr/> the destination camera image then needs to be
+corrected for radial distortion before comparison or
+sampling.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.intrinsicCalibration">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The parameters for this camera device's intrinsic
+calibration.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Pixels in the
+ android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
+ coordinate system.<wbr/>
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The five calibration parameters that describe the
+transform from camera-centric 3D coordinates to sensor
+pixel coordinates:</p>
+<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s]
+</code></pre>
+<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical
+focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical
+axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not
+being aligned with the lens plane.<wbr/></p>
+<p>These are typically used within a transformation matrix K:</p>
+<pre><code>K = [ f_<wbr/>x,<wbr/> s,<wbr/> c_<wbr/>x,<wbr/>
+ 0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/>
+ 0 0,<wbr/> 1 ]
+</code></pre>
+<p>which can then be combined with the camera pose rotation
+<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and
+<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the
+complete transform from world coordinates to pixel
+coordinates:</p>
+<pre><code>P = [ K 0 * [ R t
+ 0 1 ] 0 1 ]
+</code></pre>
+<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system
+and <code>p_<wbr/>s</code> being a point in the camera active pixel array
+coordinate system,<wbr/> and with the mapping including the
+homogeneous division by z:</p>
+<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w
+p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h
+</code></pre>
+<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world
+point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity
+(depth) in pixel coordinates.<wbr/></p>
+<p>Note that the coordinate system for this transform is the
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/>
+where <code>(0,<wbr/>0)</code> is the top-left of the
+preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and
+intrinsic calibration transforms have been applied to a
+world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>
+transform needs to be applied,<wbr/> and the result adjusted to
+be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate
+system (where <code>(0,<wbr/> 0)</code> is the top-left of the
+activeArraySize rectangle),<wbr/> to determine the final pixel
+coordinate of the world point for processed (non-RAW)
+output buffers.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.lens.radialDistortion">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>radial<wbr/>Distortion
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 6
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The correction coefficients to correct for this camera device's
+radial and tangential lens distortion.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Unitless coefficients.<wbr/>
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/>
+kappa_<wbr/>3]</code> and two tangential distortion coefficients
+<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the
+lens's geometric distortion with the mapping equations:</p>
+<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
+ kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 )
+ y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
+ kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 )
+</code></pre>
+<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the
+input image that correspond to the pixel values in the
+corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p>
+<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage)
+</code></pre>
+<p>The pixel coordinates are defined in a normalized
+coordinate system related to the
+<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/>
+Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the
+lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes
+of both x and y coordinates are normalized to be 1 at the
+edge further from the optical center,<wbr/> so the range
+for both dimensions is <code>-1 <= x <= 1</code>.<wbr/></p>
+<p>Finally,<wbr/> <code>r</code> represents the radial distance from the
+optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude
+is therefore no larger than <code>|<wbr/>r|<wbr/> <= sqrt(2)</code>.<wbr/></p>
+<p>The distortion model used is the Brown-Conrady model.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.lens.aperture">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>aperture
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the
+effective aperture diameter.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ The f-number (f/<wbr/>N)
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Setting this value is only supported on the camera devices that have a variable
+aperture lens.<wbr/></p>
+<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/>
+this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
+<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>
+to achieve manual exposure control.<wbr/></p>
+<p>The requested aperture value may take several frames to reach the
+requested value; the camera device will report the current (intermediate)
+aperture size in capture result metadata while the aperture is changing.<wbr/>
+While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
+<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of
+the ON modes,<wbr/> this will be overridden by the camera device
+auto-exposure algorithm,<wbr/> the overridden values are then provided
+back to the user in the corresponding result.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.filterDensity">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>filter<wbr/>Density
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired setting for the lens neutral density filter(s).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Exposure Value (EV)
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control will not be supported on most camera devices.<wbr/></p>
+<p>Lens filters are typically used to lower the amount of light the
+sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV
+step is the standard logarithmic representation,<wbr/> which are
+non-negative,<wbr/> and inversely proportional to the amount of light
+hitting the sensor.<wbr/> For example,<wbr/> setting this to 0 would result
+in no reduction of the incoming light,<wbr/> and setting this to 2 would
+mean that the filter is set to reduce incoming light by two stops
+(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p>
+<p>It may take several frames before the lens filter density changes
+to the requested value.<wbr/> While the filter density is still changing,<wbr/>
+<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.focalLength">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>focal<wbr/>Length
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired lens focal length; used for optical zoom.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Millimeters
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This setting controls the physical focal length of the camera
+device's lens.<wbr/> Changing the focal length changes the field of
+view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p>
+<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this
+setting won't be applied instantaneously,<wbr/> and it may take several
+frames before the lens can change to the requested focal length.<wbr/>
+While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will
+be set to MOVING.<wbr/></p>
+<p>Optical zoom will not be supported on most devices.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.focusDistance">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>focus<wbr/>Distance
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Desired distance to plane of sharpest focus,<wbr/>
+measured from frontmost surface of the lens.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Should be zero for fixed-focus cameras</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.focusRange">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>focus<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as pairFloatFloat]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+ <div class="entry_type_notes">Range of scene distances that are in focus</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The range of scene distances that are in
+sharp focus (depth of field).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ A pair of focus distances in diopters: (near,<wbr/>
+ far); see android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details.<wbr/>
+ </td>
+
+ <td class="entry_range">
+ <p>>=0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If variable focus not supported,<wbr/> can still report
+fixed depth of field range</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.opticalStabilizationMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Sets whether the camera device uses optical image stabilization (OIS)
+when capturing images.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>OIS is used to compensate for motion blur due to small
+movements of the camera during capture.<wbr/> Unlike digital image
+stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS
+makes use of mechanical elements to stabilize the camera
+sensor,<wbr/> and thus allows for longer exposure times before
+camera shake becomes apparent.<wbr/></p>
+<p>Switching between different optical stabilization modes may take several
+frames to initialize,<wbr/> the camera device will report the current mode in
+capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the
+optical stabilization modes in the first several capture results may still
+be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p>
+<p>If a camera device supports both OIS and digital image stabilization
+(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable
+interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p>
+<p>Not all devices will support OIS; see
+<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for
+available controls.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.state">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>state
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">STATIONARY</span>
+ <span class="entry_type_enum_notes"><p>The lens parameters (<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
+<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) are not changing.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MOVING</span>
+ <span class="entry_type_enum_notes"><p>One or several of the lens parameters
+(<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
+<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> or <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) is
+currently changing.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current lens status.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For lens parameters <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
+<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> when changes are requested,<wbr/>
+they may take several frames to reach the requested values.<wbr/> This state indicates
+the current status of the lens parameters.<wbr/></p>
+<p>When the state is STATIONARY,<wbr/> the lens parameters are not changing.<wbr/> This could be
+either because the parameters are all fixed,<wbr/> or because the lens has had enough
+time to reach the most recently-requested values.<wbr/>
+If all these lens parameters are not changable for a camera device,<wbr/> as listed below:</p>
+<ul>
+<li>Fixed focus (<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> == 0</code>),<wbr/> which means
+<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> parameter will always be 0.<wbr/></li>
+<li>Fixed focal length (<a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a> contains single value),<wbr/>
+which means the optical zoom is not supported.<wbr/></li>
+<li>No ND filter (<a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a> contains only 0).<wbr/></li>
+<li>Fixed aperture (<a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a> contains single value).<wbr/></li>
+</ul>
+<p>Then this state will always be STATIONARY.<wbr/></p>
+<p>When the state is MOVING,<wbr/> it indicates that at least one of the lens parameters
+is changing.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.poseRotation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>pose<wbr/>Rotation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The orientation of the camera relative to the sensor
+coordinate system.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Quaternion coefficients
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The four coefficients that describe the quaternion
+rotation from the Android sensor coordinate system to a
+camera-aligned coordinate system where the X-axis is
+aligned with the long side of the image sensor,<wbr/> the Y-axis
+is aligned with the short side of the image sensor,<wbr/> and
+the Z-axis is aligned with the optical axis of the sensor.<wbr/></p>
+<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code>
+to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation
+amount <code>theta</code>,<wbr/> the following formulas can be used:</p>
+<pre><code> theta = 2 * acos(w)
+a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2)
+a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2)
+a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2)
+</code></pre>
+<p>To create a 3x3 rotation matrix that applies the rotation
+defined by this quaternion,<wbr/> the following matrix can be
+used:</p>
+<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/> 2xy - 2zw,<wbr/> 2xz + 2yw,<wbr/>
+ 2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/> 2yz - 2xw,<wbr/>
+ 2xz - 2yw,<wbr/> 2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ]
+</code></pre>
+<p>This matrix can then be used to apply the rotation to a
+ column vector point with</p>
+<p><code>p' = Rp</code></p>
+<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and
+ <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.poseTranslation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>pose<wbr/>Translation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Position of the camera optical center.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Meters
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The position of the camera device's lens optical center,<wbr/>
+as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the
+optical center of the largest camera device facing in the
+same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate
+axes</a>.<wbr/> Note that only the axis definitions are shared with
+the sensor coordinate system,<wbr/> but not the origin.<wbr/></p>
+<p>If this device is the largest or only camera device with a
+given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a
+camera device with a lens optical center located 3 cm from
+the main sensor along the +X axis (to the right from the
+user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p>
+<p>To transform a pixel coordinates between two cameras
+facing the same direction,<wbr/> first the source camera
+<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/> Then
+the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs
+to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a>
+of the source camera,<wbr/> the translation of the source camera
+relative to the destination camera,<wbr/> the
+<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and
+finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a>
+of the destination camera.<wbr/> This obtains a
+radial-distortion-free coordinate in the destination
+camera pixel coordinates.<wbr/></p>
+<p>To compare this against a real image from the destination
+camera,<wbr/> the destination camera image then needs to be
+corrected for radial distortion before comparison or
+sampling.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.intrinsicCalibration">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 5
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The parameters for this camera device's intrinsic
+calibration.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Pixels in the
+ android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
+ coordinate system.<wbr/>
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The five calibration parameters that describe the
+transform from camera-centric 3D coordinates to sensor
+pixel coordinates:</p>
+<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s]
+</code></pre>
+<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical
+focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical
+axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not
+being aligned with the lens plane.<wbr/></p>
+<p>These are typically used within a transformation matrix K:</p>
+<pre><code>K = [ f_<wbr/>x,<wbr/> s,<wbr/> c_<wbr/>x,<wbr/>
+ 0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/>
+ 0 0,<wbr/> 1 ]
+</code></pre>
+<p>which can then be combined with the camera pose rotation
+<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and
+<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the
+complete transform from world coordinates to pixel
+coordinates:</p>
+<pre><code>P = [ K 0 * [ R t
+ 0 1 ] 0 1 ]
+</code></pre>
+<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system
+and <code>p_<wbr/>s</code> being a point in the camera active pixel array
+coordinate system,<wbr/> and with the mapping including the
+homogeneous division by z:</p>
+<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w
+p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h
+</code></pre>
+<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world
+point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity
+(depth) in pixel coordinates.<wbr/></p>
+<p>Note that the coordinate system for this transform is the
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/>
+where <code>(0,<wbr/>0)</code> is the top-left of the
+preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and
+intrinsic calibration transforms have been applied to a
+world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>
+transform needs to be applied,<wbr/> and the result adjusted to
+be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate
+system (where <code>(0,<wbr/> 0)</code> is the top-left of the
+activeArraySize rectangle),<wbr/> to determine the final pixel
+coordinate of the world point for processed (non-RAW)
+output buffers.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.lens.radialDistortion">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>lens.<wbr/>radial<wbr/>Distortion
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 6
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The correction coefficients to correct for this camera device's
+radial and tangential lens distortion.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ Unitless coefficients.<wbr/>
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/>
+kappa_<wbr/>3]</code> and two tangential distortion coefficients
+<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the
+lens's geometric distortion with the mapping equations:</p>
+<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
+ kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 )
+ y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
+ kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 )
+</code></pre>
+<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the
+input image that correspond to the pixel values in the
+corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p>
+<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage)
+</code></pre>
+<p>The pixel coordinates are defined in a normalized
+coordinate system related to the
+<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/>
+Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the
+lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes
+of both x and y coordinates are normalized to be 1 at the
+edge further from the optical center,<wbr/> so the range
+for both dimensions is <code>-1 <= x <= 1</code>.<wbr/></p>
+<p>Finally,<wbr/> <code>r</code> represents the radial distance from the
+optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude
+is therefore no larger than <code>|<wbr/>r|<wbr/> <= sqrt(2)</code>.<wbr/></p>
+<p>The distortion model used is the Brown-Conrady model.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_noiseReduction" class="section">noiseReduction</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.noiseReduction.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>noise<wbr/>Reduction.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor
+output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate
+relative to sensor.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame
+rate relative to sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MINIMAL</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to
+sensor output.<wbr/> </p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/>
+based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise
+reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no
+noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction
+for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality
+is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/>
+quality may improve from FAST).<wbr/></p>
+<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
+with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
+high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
+produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the
+high-resolution buffers must not have noise reduction applied to maximize efficiency of
+preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while
+low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction
+applied for reasonable preview quality.<wbr/></p>
+<p>This mode is guaranteed to be supported by devices that support either the
+YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
+(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
+be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Mode of operation for the noise reduction algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The noise reduction algorithm attempts to improve image quality by removing
+excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p>
+<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and
+YUV domain.<wbr/></p>
+<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove
+demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/>
+This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check
+<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering
+will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device
+will use the highest-quality noise filtering algorithms,<wbr/>
+even if it slows down capture rate.<wbr/> FAST means the camera device will not
+slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if
+MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/>
+Every output stream will have a similar amount of enhancement applied.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
+buffer of high-resolution images during preview and reprocess image(s) from that buffer
+into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
+noise reduction to low-resolution streams (below maximum recording resolution) to maximize
+preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since
+those will be reprocessed later if necessary.<wbr/></p>
+<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device
+will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device
+may adjust the noise reduction parameters for best image quality based on the
+<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
+adjust the internal noise reduction parameters appropriately to get the best quality
+images.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.noiseReduction.strength">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>noise<wbr/>Reduction.<wbr/>strength
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Control the amount of noise reduction
+applied to the images</p>
+ </td>
+
+ <td class="entry_units">
+ 1-10; 10 is max noise reduction
+ </td>
+
+ <td class="entry_range">
+ <p>1 - 10</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.noiseReduction.availableNoiseReductionModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of noise reduction modes for <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> that are supported
+by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Full-capability camera devices will always support OFF and FAST.<wbr/></p>
+<p>Camera devices that support YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will support
+ZERO_<wbr/>SHUTTER_<wbr/>LAG.<wbr/></p>
+<p>Legacy-capability camera devices will only support FAST mode.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if noise reduction control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.noiseReduction.mode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>noise<wbr/>Reduction.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor
+output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate
+relative to sensor.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame
+rate relative to sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MINIMAL</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to
+sensor output.<wbr/> </p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/>
+based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise
+reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no
+noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction
+for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality
+is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/>
+quality may improve from FAST).<wbr/></p>
+<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
+with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
+high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
+produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the
+high-resolution buffers must not have noise reduction applied to maximize efficiency of
+preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while
+low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction
+applied for reasonable preview quality.<wbr/></p>
+<p>This mode is guaranteed to be supported by devices that support either the
+YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
+(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
+be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Mode of operation for the noise reduction algorithm.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The noise reduction algorithm attempts to improve image quality by removing
+excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p>
+<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and
+YUV domain.<wbr/></p>
+<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove
+demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/>
+This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check
+<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p>
+<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering
+will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device
+will use the highest-quality noise filtering algorithms,<wbr/>
+even if it slows down capture rate.<wbr/> FAST means the camera device will not
+slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if
+MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/>
+Every output stream will have a similar amount of enhancement applied.<wbr/></p>
+<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
+buffer of high-resolution images during preview and reprocess image(s) from that buffer
+into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
+noise reduction to low-resolution streams (below maximum recording resolution) to maximize
+preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since
+those will be reprocessed later if necessary.<wbr/></p>
+<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device
+will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device
+may adjust the noise reduction parameters for best image quality based on the
+<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
+adjust the internal noise reduction parameters appropriately to get the best quality
+images.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_quirks" class="section">quirks</td></tr>
+
+
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.quirks.meteringCropRegion">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>quirks.<wbr/>metering<wbr/>Crop<wbr/>Region
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>If set to 1,<wbr/> the camera service does not
+scale 'normalized' coordinates with respect to the crop
+region.<wbr/> This applies to metering input (a{e,<wbr/>f,<wbr/>wb}Region
+and output (face rectangles).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Normalized coordinates refer to those in the
+(-1000,<wbr/>1000) range mentioned in the
+android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p>
+<p>HAL implementations should instead always use and emit
+sensor array-relative coordinates for all region data.<wbr/> Does
+not need to be listed in static metadata.<wbr/> Support will be
+removed in future versions of camera service.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.quirks.triggerAfWithAuto">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>quirks.<wbr/>trigger<wbr/>Af<wbr/>With<wbr/>Auto
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>If set to 1,<wbr/> then the camera service always
+switches to FOCUS_<wbr/>MODE_<wbr/>AUTO before issuing a AF
+trigger.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL implementations should implement AF trigger
+modes for AUTO,<wbr/> MACRO,<wbr/> CONTINUOUS_<wbr/>FOCUS,<wbr/> and
+CONTINUOUS_<wbr/>PICTURE modes instead of using this flag.<wbr/> Does
+not need to be listed in static metadata.<wbr/> Support will be
+removed in future versions of camera service</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.quirks.useZslFormat">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>quirks.<wbr/>use<wbr/>Zsl<wbr/>Format
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>If set to 1,<wbr/> the camera service uses
+CAMERA2_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>ZSL instead of
+HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED for the zero
+shutter lag stream</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL implementations should use gralloc usage flags
+to determine that a stream will be used for
+zero-shutter-lag,<wbr/> instead of relying on an explicit
+format setting.<wbr/> Does not need to be listed in static
+metadata.<wbr/> Support will be removed in future versions of
+camera service.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.quirks.usePartialResult">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="5">
+ android.<wbr/>quirks.<wbr/>use<wbr/>Partial<wbr/>Result
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>If set to 1,<wbr/> the HAL will always split result
+metadata for a single capture into multiple buffers,<wbr/>
+returned using multiple process_<wbr/>capture_<wbr/>result calls.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Does not need to be listed in static
+metadata.<wbr/> Support for partial results will be reworked in
+future versions of camera service.<wbr/> This quirk will stop
+working at that point; DO NOT USE without careful
+consideration of future support.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code>
+for information on how to implement partial results.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.quirks.partialResult">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="5">
+ android.<wbr/>quirks.<wbr/>partial<wbr/>Result
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [hidden as boolean]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FINAL</span>
+ <span class="entry_type_enum_notes"><p>The last or only metadata result buffer
+for this capture.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PARTIAL</span>
+ <span class="entry_type_enum_notes"><p>A partial buffer of result metadata for this
+capture.<wbr/> More result buffers for this capture will be sent
+by the camera device,<wbr/> the last of which will be marked
+FINAL.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether a result given to the framework is the
+final one for the capture,<wbr/> or only a partial that contains a
+subset of the full set of dynamic metadata
+values.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>Optional.<wbr/> Default value is FINAL.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The entries in the result metadata buffers for a
+single capture may not overlap,<wbr/> except for this entry.<wbr/> The
+FINAL buffers must retain FIFO ordering relative to the
+requests that generate them,<wbr/> so the FINAL buffer for frame 3 must
+always be sent to the framework after the FINAL buffer for frame 2,<wbr/> and
+before the FINAL buffer for frame 4.<wbr/> PARTIAL buffers may be returned
+in any order relative to other frames,<wbr/> but all PARTIAL buffers for a given
+capture must arrive before the FINAL buffer for that capture.<wbr/> This entry may
+only be used by the camera device if quirks.<wbr/>usePartialResult is set to 1.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code>
+for information on how to implement partial results.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_request" class="section">request</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.request.frameCount">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>frame<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A frame counter set by the framework.<wbr/> Must
+be maintained unchanged in output frame.<wbr/> This value monotonically
+increases with every new result (that is,<wbr/> each new result has a unique
+frameCount value).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ incrementing integer
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>Any int.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.request.id">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>id
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>An application-specified ID for the current
+request.<wbr/> Must be maintained unchanged in output
+frame</p>
+ </td>
+
+ <td class="entry_units">
+ arbitrary integer assigned by application
+ </td>
+
+ <td class="entry_range">
+ <p>Any int</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.request.inputStreams">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>input<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List which camera reprocess stream is used
+for the source of reprocessing data.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ List of camera reprocess stream IDs
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>Typically,<wbr/> only one entry allowed,<wbr/> must be a valid reprocess stream ID.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only meaningful when <a href="#controls_android.request.type">android.<wbr/>request.<wbr/>type</a> ==
+REPROCESS.<wbr/> Ignored otherwise</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.request.metadataMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>metadata<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">NONE</span>
+ <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except
+for application-bound buffer data.<wbr/> If no
+application-bound streams exist,<wbr/> no frame should be
+placed in the output frame queue.<wbr/> If such streams
+exist,<wbr/> a frame should be placed on the output queue
+with null metadata but with the necessary output buffer
+information.<wbr/> Timestamp information should still be
+included with any output stream buffers</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FULL</span>
+ <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will
+only be produced if they are separately
+enabled</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>How much metadata to produce on
+output</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.request.outputStreams">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>output<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Lists which camera output streams image data
+from this capture must be sent to</p>
+ </td>
+
+ <td class="entry_units">
+ List of camera stream IDs
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>List must only include streams that have been
+created</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If no output streams are listed,<wbr/> then the image
+data should simply be discarded.<wbr/> The image data must
+still be captured for metadata and statistics production,<wbr/>
+and the lens and flash must operate as requested.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.request.type">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>type
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CAPTURE</span>
+ <span class="entry_type_enum_notes"><p>Capture a new image from the imaging hardware,<wbr/>
+and process it according to the
+settings</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">REPROCESS</span>
+ <span class="entry_type_enum_notes"><p>Process previously captured data; the
+<a href="#controls_android.request.inputStreams">android.<wbr/>request.<wbr/>input<wbr/>Streams</a> parameter determines the
+source reprocessing stream.<wbr/> TODO: Mark dynamic metadata
+needed for reprocessing with [RP]</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The type of the request; either CAPTURE or
+REPROCESS.<wbr/> For HAL3,<wbr/> this tag is redundant.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.request.maxNumOutputStreams">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum numbers of different types of output streams
+that can be configured and used simultaneously by a camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>For processed (and stalling) format streams,<wbr/> >= 1.<wbr/></p>
+<p>For Raw format (either stalling or non-stalling) streams,<wbr/> >= 0.<wbr/></p>
+<p>For processed (but not stalling) format streams,<wbr/> >= 3
+for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>);
+>= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is a 3 element tuple that contains the max number of output simultaneous
+streams for raw sensor,<wbr/> processed (but not stalling),<wbr/> and processed (and stalling)
+formats respectively.<wbr/> For example,<wbr/> assuming that JPEG is typically a processed and
+stalling stream,<wbr/> if max raw sensor format output stream number is 1,<wbr/> max YUV streams
+number is 3,<wbr/> and max JPEG stream number is 2,<wbr/> then this tuple should be <code>(1,<wbr/> 3,<wbr/> 2)</code>.<wbr/></p>
+<p>This lists the upper bound of the number of output streams supported by
+the camera device.<wbr/> Using more streams simultaneously may require more hardware and
+CPU resources that will consume more power.<wbr/> The image format for an output stream can
+be any supported format provided by <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/>
+The formats defined in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> can be catergorized
+into the 3 stream types as below:</p>
+<ul>
+<li>Processed (but stalling): any non-RAW format with a stallDurations > 0.<wbr/>
+ Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a>.<wbr/></li>
+<li>Raw formats: <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a>,<wbr/> or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a>.<wbr/></li>
+<li>Processed (but not-stalling): any non-RAW format without a stall duration.<wbr/>
+ Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a>,<wbr/>
+ <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>,<wbr/> or
+ <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.maxNumOutputRaw">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum numbers of different types of output streams
+that can be configured and used simultaneously by a camera device
+for any <code>RAW</code> formats.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value contains the max number of output simultaneous
+streams from the raw sensor.<wbr/></p>
+<p>This lists the upper bound of the number of output streams supported by
+the camera device.<wbr/> Using more streams simultaneously may require more hardware and
+CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
+be any <code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
+<p>In particular,<wbr/> a <code>RAW</code> format is typically one of:</p>
+<ul>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a></li>
+</ul>
+<p>LEGACY mode devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> LEGACY)
+never support raw streams.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.maxNumOutputProc">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum numbers of different types of output streams
+that can be configured and used simultaneously by a camera device
+for any processed (but not-stalling) formats.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 3
+for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>);
+>= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value contains the max number of output simultaneous
+streams for any processed (but not-stalling) formats.<wbr/></p>
+<p>This lists the upper bound of the number of output streams supported by
+the camera device.<wbr/> Using more streams simultaneously may require more hardware and
+CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
+be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
+<p>Processed (but not-stalling) is defined as any non-RAW format without a stall duration.<wbr/>
+Typically:</p>
+<ul>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a></li>
+<li>Implementation-defined formats,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#isOutputSupportedFor(Class)">StreamConfigurationMap#isOutputSupportedFor(Class)</a></li>
+</ul>
+<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a
+processed format -- it will return 0 for a non-stalling stream.<wbr/></p>
+<p>LEGACY devices will support at least 2 processing/<wbr/>non-stalling streams.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.maxNumOutputProcStalling">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc<wbr/>Stalling
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum numbers of different types of output streams
+that can be configured and used simultaneously by a camera device
+for any processed (and stalling) formats.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value contains the max number of output simultaneous
+streams for any processed (but not-stalling) formats.<wbr/></p>
+<p>This lists the upper bound of the number of output streams supported by
+the camera device.<wbr/> Using more streams simultaneously may require more hardware and
+CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
+be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
+<p>A processed and stalling format is defined as any non-RAW format with a stallDurations
+> 0.<wbr/> Typically only the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a> is a
+stalling format.<wbr/></p>
+<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a
+processed format -- it will return a non-0 value for a stalling stream.<wbr/></p>
+<p>LEGACY devices will support up to 1 processing/<wbr/>stalling stream.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.maxNumReprocessStreams">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Reprocess<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 1
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>How many reprocessing streams of any type
+can be allocated at the same time.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only used by HAL2.<wbr/>x.<wbr/></p>
+<p>When set to 0,<wbr/> it means no reprocess stream is supported.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.maxNumInputStreams">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum numbers of any type of input streams
+that can be configured and used simultaneously by a camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>0 or 1.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to 0,<wbr/> it means no input stream is supported.<wbr/></p>
+<p>The image format for a input stream can be any supported format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/> When using an
+input stream,<wbr/> there must be at least one output stream configured to to receive the
+reprocessed images.<wbr/></p>
+<p>When an input stream and some output streams are used in a reprocessing request,<wbr/>
+only the input buffer will be used to produce these output stream buffers,<wbr/> and a
+new sensor image will not be captured.<wbr/></p>
+<p>For example,<wbr/> for Zero Shutter Lag (ZSL) still capture use case,<wbr/> the input
+stream image format will be PRIVATE,<wbr/> the associated output stream image format
+should be JPEG.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For the reprocessing flow and controls,<wbr/> see
+hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more details.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.pipelineMaxDepth">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Specifies the number of maximum pipeline stages a frame
+has to go through from when it's exposed to when it's available
+to the framework.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A typical minimum value for this is 2 (one stage to expose,<wbr/>
+one stage to readout) from the sensor.<wbr/> The ISP then usually adds
+its own stages to do custom HW processing.<wbr/> Further stages may be
+added by SW processing.<wbr/></p>
+<p>Depending on what settings are used (e.<wbr/>g.<wbr/> YUV,<wbr/> JPEG) and what
+processing is enabled (e.<wbr/>g.<wbr/> face detection),<wbr/> the actual pipeline
+depth (specified by <a href="#dynamic_android.request.pipelineDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Depth</a>) may be less than
+the max pipeline depth.<wbr/></p>
+<p>A pipeline depth of X stages is equivalent to a pipeline latency of
+X frame intervals.<wbr/></p>
+<p>This value will normally be 8 or less,<wbr/> however,<wbr/> for high speed capture session,<wbr/>
+the max pipeline depth will be up to 8 x size of high speed capture request list.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value should be 4 or less,<wbr/> expect for the high speed recording session,<wbr/> where the
+max batch sizes may be larger than 1.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.partialResultCount">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>partial<wbr/>Result<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Defines how many sub-components
+a result will be composed of.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>In order to combat the pipeline latency,<wbr/> partial results
+may be delivered to the application layer from the camera device as
+soon as they are available.<wbr/></p>
+<p>Optional; defaults to 1.<wbr/> A value of 1 means that partial
+results are not supported,<wbr/> and only the final TotalCaptureResult will
+be produced by the camera device.<wbr/></p>
+<p>A typical use case for this might be: after requesting an
+auto-focus (AF) lock the new AF state might be available 50%
+of the way through the pipeline.<wbr/> The camera device could
+then immediately dispatch this state via a partial result to
+the application,<wbr/> and the rest of the metadata via later
+partial results.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.availableCapabilities">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>available<wbr/>Capabilities
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">BACKWARD_COMPATIBLE</span>
+ <span class="entry_type_enum_notes"><p>The minimal set of capabilities that every camera
+device (regardless of <a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>)
+supports.<wbr/></p>
+<p>This capability is listed by all normal devices,<wbr/> and
+indicates that the camera device has a feature set
+that's comparable to the baseline requirements for the
+older android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p>
+<p>Devices with the DEPTH_<wbr/>OUTPUT capability might not list this
+capability,<wbr/> indicating that they support only depth measurement,<wbr/>
+not standard color output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MANUAL_SENSOR</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device can be manually controlled (3A algorithms such
+as auto-exposure,<wbr/> and auto-focus can be bypassed).<wbr/>
+The camera device supports basic manual control of the sensor image
+acquisition related stages.<wbr/> This means the following controls are
+guaranteed to be supported:</p>
+<ul>
+<li>Manual frame duration control<ul>
+<li><a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a></li>
+<li><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li>
+</ul>
+</li>
+<li>Manual exposure control<ul>
+<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li>
+<li><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li>
+</ul>
+</li>
+<li>Manual sensitivity control<ul>
+<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li>
+<li><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></li>
+</ul>
+</li>
+<li>Manual lens control (if the lens is adjustable)<ul>
+<li>android.<wbr/>lens.<wbr/>*</li>
+</ul>
+</li>
+<li>Manual flash control (if a flash unit is present)<ul>
+<li>android.<wbr/>flash.<wbr/>*</li>
+</ul>
+</li>
+<li>Manual black level locking<ul>
+<li><a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a></li>
+</ul>
+</li>
+<li>Auto exposure lock<ul>
+<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
+</ul>
+</li>
+</ul>
+<p>If any of the above 3A algorithms are enabled,<wbr/> then the camera
+device will accurately report the values applied by 3A in the
+result.<wbr/></p>
+<p>A given camera device may also support additional manual sensor controls,<wbr/>
+but this capability only covers the above list of controls.<wbr/></p>
+<p>If this is supported,<wbr/> <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> will
+additionally return a min frame duration that is greater than
+zero for each supported size-format combination.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">MANUAL_POST_PROCESSING</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device post-processing stages can be manually controlled.<wbr/>
+The camera device supports basic manual control of the image post-processing
+stages.<wbr/> This means the following controls are guaranteed to be supported:</p>
+<ul>
+<li>
+<p>Manual tonemap control</p>
+<ul>
+<li><a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a></li>
+<li><a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></li>
+<li><a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></li>
+<li><a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a></li>
+<li><a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a></li>
+</ul>
+</li>
+<li>
+<p>Manual white balance control</p>
+<ul>
+<li><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a></li>
+<li><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a></li>
+</ul>
+</li>
+<li>Manual lens shading map control<ul>
+<li><a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></li>
+<li><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></li>
+<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a></li>
+<li><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a></li>
+</ul>
+</li>
+<li>Manual aberration correction control (if aberration correction is supported)<ul>
+<li><a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></li>
+<li><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></li>
+</ul>
+</li>
+<li>Auto white balance lock<ul>
+<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
+</ul>
+</li>
+</ul>
+<p>If auto white balance is enabled,<wbr/> then the camera device
+will accurately report the values applied by AWB in the result.<wbr/></p>
+<p>A given camera device may also support additional post-processing
+controls,<wbr/> but this capability only covers the above list of controls.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">RAW</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports outputting RAW buffers and
+metadata for interpreting them.<wbr/></p>
+<p>Devices supporting the RAW capability allow both for
+saving DNG files,<wbr/> and for direct application processing of
+raw sensor images.<wbr/></p>
+<ul>
+<li>RAW_<wbr/>SENSOR is supported as an output format.<wbr/></li>
+<li>The maximum available resolution for RAW_<wbr/>SENSOR streams
+ will match either the value in
+ <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or
+ <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
+<li>All DNG-related optional metadata entries are provided
+ by the camera device.<wbr/></li>
+</ul></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PRIVATE_REPROCESSING</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports the Zero Shutter Lag reprocessing use case.<wbr/></p>
+<ul>
+<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is supported as an output/<wbr/>input format,<wbr/>
+ that is,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is included in the lists of
+ formats returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a>
+ returns non empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li>
+<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">getInputSizes(ImageFormat.<wbr/>PRIVATE)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">getOutputSizes(ImageFormat.<wbr/>PRIVATE)</a></li>
+<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> does not cause a frame rate drop
+ relative to the sensor's maximum capture rate (at that resolution).<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> will be reprocessable into both
+ <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and
+ <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li>
+<li>The maximum available resolution for PRIVATE streams
+ (both input/<wbr/>output) will match the maximum available
+ resolution of JPEG streams.<wbr/></li>
+<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li>
+<li>Only below controls are effective for reprocessing requests and
+ will be present in capture results,<wbr/> other controls in reprocess
+ requests will be ignored by the camera device.<wbr/><ul>
+<li>android.<wbr/>jpeg.<wbr/>*</li>
+<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li>
+<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li>
+</ul>
+</li>
+<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and
+ <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li>
+</ul></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">READ_SENSOR_SETTINGS</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports accurately reporting the sensor settings for many of
+the sensor controls while the built-in 3A algorithm is running.<wbr/> This allows
+reporting of sensor settings even when these settings cannot be manually changed.<wbr/></p>
+<p>The values reported for the following controls are guaranteed to be available
+in the CaptureResult,<wbr/> including when 3A is enabled:</p>
+<ul>
+<li>Exposure control<ul>
+<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li>
+</ul>
+</li>
+<li>Sensitivity control<ul>
+<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li>
+</ul>
+</li>
+<li>Lens controls (if the lens is adjustable)<ul>
+<li><a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a></li>
+<li><a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a></li>
+</ul>
+</li>
+</ul>
+<p>This capability is a subset of the MANUAL_<wbr/>SENSOR control capability,<wbr/> and will
+always be included if the MANUAL_<wbr/>SENSOR capability is available.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BURST_CAPTURE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports capturing high-resolution images at >= 20 frames per
+second,<wbr/> in at least the uncompressed YUV format,<wbr/> when post-processing settings are set
+to FAST.<wbr/> Additionally,<wbr/> maximum-resolution images can be captured at >= 10 frames
+per second.<wbr/> Here,<wbr/> 'high resolution' means at least 8 megapixels,<wbr/> or the maximum
+resolution of the device,<wbr/> whichever is smaller.<wbr/></p>
+<p>More specifically,<wbr/> this means that a size matching the camera device's active array
+size is listed as a supported size for the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> format in either <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> or <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/>
+with a minimum frame duration for that format and size of either <= 1/<wbr/>20 s,<wbr/> or
+<= 1/<wbr/>10 s,<wbr/> respectively; and the <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a> entry
+lists at least one FPS range where the minimum FPS is >= 1 /<wbr/> minimumFrameDuration
+for the maximum-size YUV_<wbr/>420_<wbr/>888 format.<wbr/> If that maximum size is listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/>
+then the list of resolutions for YUV_<wbr/>420_<wbr/>888 from <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> contains at
+least one resolution >= 8 megapixels,<wbr/> with a minimum frame duration of <= 1/<wbr/>20
+s.<wbr/></p>
+<p>If the device supports the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">ImageFormat#RAW12</a>,<wbr/> then those can also be captured at the same rate
+as the maximum-size YUV_<wbr/>420_<wbr/>888 resolution is.<wbr/></p>
+<p>If the device supports the PRIVATE_<wbr/>REPROCESSING capability,<wbr/> then the same guarantees
+as for the YUV_<wbr/>420_<wbr/>888 format also apply to the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> format.<wbr/></p>
+<p>In addition,<wbr/> the <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> field is guaranted to have a value between 0
+and 4,<wbr/> inclusive.<wbr/> <a href="#static_android.control.aeLockAvailable">android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available</a> and <a href="#static_android.control.awbLockAvailable">android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available</a>
+are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
+consistent image output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">YUV_REPROCESSING</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports the YUV_<wbr/>420_<wbr/>888 reprocessing use case,<wbr/> similar as
+PRIVATE_<wbr/>REPROCESSING,<wbr/> This capability requires the camera device to support the
+following:</p>
+<ul>
+<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> is supported as an output/<wbr/>input format,<wbr/> that is,<wbr/>
+ YUV_<wbr/>420_<wbr/>888 is included in the lists of formats returned by
+ <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and
+ <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a>
+ returns non-empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li>
+<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">get<wbr/>Input<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">get<wbr/>Output<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a></li>
+<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> does not cause a frame rate drop
+ relative to the sensor's maximum capture rate (at that resolution).<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> will be reprocessable into both
+ <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li>
+<li>The maximum available resolution for <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> streams (both input/<wbr/>output) will match the
+ maximum available resolution of <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> streams.<wbr/></li>
+<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li>
+<li>Only the below controls are effective for reprocessing requests and will be present
+ in capture results.<wbr/> The reprocess requests are from the original capture results that
+ are associated with the intermediate <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a>
+ output buffers.<wbr/> All other controls in the reprocess requests will be ignored by the
+ camera device.<wbr/><ul>
+<li>android.<wbr/>jpeg.<wbr/>*</li>
+<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li>
+<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li>
+<li><a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a></li>
+</ul>
+</li>
+<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and
+ <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li>
+</ul></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DEPTH_OUTPUT</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The camera device can produce depth measurements from its field of view.<wbr/></p>
+<p>This capability requires the camera device to support the following:</p>
+<ul>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH16">ImageFormat#DEPTH16</a> is supported as an output format.<wbr/></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a> is optionally supported as an
+ output format.<wbr/></li>
+<li>This camera device,<wbr/> and all camera devices with the same <a href="#static_android.lens.facing">android.<wbr/>lens.<wbr/>facing</a>,<wbr/>
+ will list the following calibration entries in both
+ <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> and
+ <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>:<ul>
+<li><a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a></li>
+<li><a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a></li>
+<li><a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a></li>
+<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a></li>
+</ul>
+</li>
+<li>The <a href="#static_android.depth.depthIsExclusive">android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive</a> entry is listed by this device.<wbr/></li>
+<li>A LIMITED camera with only the DEPTH_<wbr/>OUTPUT capability does not have to support
+ normal YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> and PRIV-format outputs.<wbr/> It only has to support the DEPTH16
+ format.<wbr/></li>
+</ul>
+<p>Generally,<wbr/> depth output operates at a slower frame rate than standard color capture,<wbr/>
+so the DEPTH16 and DEPTH_<wbr/>POINT_<wbr/>CLOUD formats will commonly have a stall duration that
+should be accounted for (see
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>).<wbr/>
+On a device that supports both depth and color-based output,<wbr/> to enable smooth preview,<wbr/>
+using a repeating burst is recommended,<wbr/> where a depth-output target is only included
+once every N frames,<wbr/> where N is the ratio between preview output rate and depth output
+rate,<wbr/> including depth stall time.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CONSTRAINED_HIGH_SPEED_VIDEO</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>The device supports constrained high speed video recording (frame rate >=120fps)
+use case.<wbr/> The camera device will support high speed capture session created by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>,<wbr/> which
+only accepts high speed request lists created by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/></p>
+<p>A camera device can still support high speed video streaming by advertising the high speed
+FPS ranges in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a>.<wbr/> For this case,<wbr/> all normal
+capture request per frame control and synchronization requirements will apply to
+the high speed fps ranges,<wbr/> the same as all other fps ranges.<wbr/> This capability describes
+the capability of a specialized operating mode with many limitations (see below),<wbr/> which
+is only targeted at high speed video recording.<wbr/></p>
+<p>The supported high speed video sizes and fps ranges are specified in
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/>
+To get desired output frame rates,<wbr/> the application is only allowed to select video size
+and FPS range combinations provided by
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/>
+The fps range can be controlled via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
+<p>In this capability,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
+ON,<wbr/> AUTO,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
+controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
+and post-processing parameters is possible.<wbr/> All other controls operate the
+same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
+android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
+<ul>
+<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
+<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
+<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
+<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
+<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
+<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
+<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
+</ul>
+<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
+<ul>
+<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (TORCH mode only,<wbr/> automatic flash for still capture will not
+work since aeMode is ON)</li>
+<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
+<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
+<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> (if it is supported)</li>
+</ul>
+<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
+be lower than what camera can output,<wbr/> depending on the destination Surfaces for
+the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
+the application need check if the video encoder is capable of supporting the
+high frame rate for a given video size,<wbr/> or it will end up with lower recording
+frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the actual preview frame
+rate will be bounded by the screen refresh rate.<wbr/></p>
+<p>The camera device will only support up to 2 high speed simultaneous output surfaces
+(preview and recording surfaces)
+in this mode.<wbr/> Above controls will be effective only if all of below conditions are true:</p>
+<ul>
+<li>The application creates a camera capture session with no more than 2 surfaces via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/> The
+targeted surfaces must be preview surface (either from
+<a href="https://developer.android.com/reference/android/view/SurfaceView.html">SurfaceView</a> or <a href="https://developer.android.com/reference/android/graphics/SurfaceTexture.html">SurfaceTexture</a>) or
+recording surface(either from <a href="https://developer.android.com/reference/android/media/MediaRecorder.html#getSurface">MediaRecorder#getSurface</a> or
+<a href="https://developer.android.com/reference/android/media/MediaCodec.html#createInputSurface">MediaCodec#createInputSurface</a>).<wbr/></li>
+<li>The stream sizes are selected from the sizes reported by
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/></li>
+<li>The FPS ranges are selected from
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/></li>
+</ul>
+<p>When above conditions are NOT satistied,<wbr/>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
+will fail.<wbr/></p>
+<p>Switching to a FPS range that has different maximum FPS may trigger some camera device
+reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
+the application avoids unnecessary maximum target FPS changes as much as possible
+during high speed streaming.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of capabilities that this camera device
+advertises as fully supporting.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A capability is a contract that the camera device makes in order
+to be able to satisfy one or more use cases.<wbr/></p>
+<p>Listing a capability guarantees that the whole set of features
+required to support a common use will all be available.<wbr/></p>
+<p>Using a subset of the functionality provided by an unsupported
+capability may be possible on a specific camera device implementation;
+to do this query each of <a href="#static_android.request.availableRequestKeys">android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys</a>,<wbr/>
+<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a>,<wbr/>
+<a href="#static_android.request.availableCharacteristicsKeys">android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys</a>.<wbr/></p>
+<p>The following capabilities are guaranteed to be available on
+<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> FULL devices:</p>
+<ul>
+<li>MANUAL_<wbr/>SENSOR</li>
+<li>MANUAL_<wbr/>POST_<wbr/>PROCESSING</li>
+</ul>
+<p>Other capabilities may be available on either FULL or LIMITED
+devices,<wbr/> but the application should query this key to be sure.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Additional constraint details per-capability will be available
+in the Compatibility Test Suite.<wbr/></p>
+<p>Minimum baseline requirements required for the
+BACKWARD_<wbr/>COMPATIBLE capability are not explicitly listed.<wbr/>
+Instead refer to "BC" tags and the camera CTS tests in the
+android.<wbr/>hardware.<wbr/>camera2.<wbr/>cts package.<wbr/></p>
+<p>Listed controls that can be either request or result (e.<wbr/>g.<wbr/>
+<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) must be available both in the
+request and the result in order to be considered to be
+capability-compliant.<wbr/></p>
+<p>For example,<wbr/> if the HAL claims to support MANUAL control,<wbr/>
+then exposure time must be configurable via the request <em>and</em>
+the actual exposure applied must be available via
+the result.<wbr/></p>
+<p>If MANUAL_<wbr/>SENSOR is omitted,<wbr/> the HAL may choose to omit the
+<a href="#static_android.scaler.availableMinFrameDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations</a> static property entirely.<wbr/></p>
+<p>For PRIVATE_<wbr/>REPROCESSING and YUV_<wbr/>REPROCESSING capabilities,<wbr/> see
+hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more information.<wbr/></p>
+<p>Devices that support the MANUAL_<wbr/>SENSOR capability must support the
+CAMERA3_<wbr/>TEMPLATE_<wbr/>MANUAL template defined in camera3.<wbr/>h.<wbr/></p>
+<p>Devices that support the PRIVATE_<wbr/>REPROCESSING capability or the
+YUV_<wbr/>REPROCESSING capability must support the
+CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template defined in camera3.<wbr/>h.<wbr/></p>
+<p>For DEPTH_<wbr/>OUTPUT,<wbr/> the depth-format keys
+<a href="#static_android.depth.availableDepthStreamConfigurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations</a>,<wbr/>
+<a href="#static_android.depth.availableDepthMinFrameDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations</a>,<wbr/>
+<a href="#static_android.depth.availableDepthStallDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations</a> must be available,<wbr/> in
+addition to the other keys explicitly mentioned in the DEPTH_<wbr/>OUTPUT
+enum notes.<wbr/> The entry <a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a> must be available
+if the DEPTH_<wbr/>POINT_<wbr/>CLOUD format is supported (HAL pixel format BLOB,<wbr/> dataspace
+DEPTH).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.availableRequestKeys">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A list of all keys that the camera device has available
+to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html">CaptureRequest</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Attempting to set a key into a CaptureRequest that is not
+listed here will result in an invalid request and will be rejected
+by the camera device.<wbr/></p>
+<p>This field can be used to query the feature set of a camera device
+at a more granular level than capabilities.<wbr/> This is especially
+important for optional keys that are not listed under any capability
+in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
+extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
+<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
+vendor extensions API and not against this field.<wbr/></p>
+<p>The HAL must not consume any request tags that are not listed either
+here or in the vendor tag list.<wbr/></p>
+<p>The public camera2 API will always make the vendor tags visible
+via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.availableResultKeys">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A list of all keys that the camera device has available
+to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Attempting to get a key from a CaptureResult that is not
+listed here will always return a <code>null</code> value.<wbr/> Getting a key from
+a CaptureResult that is listed here will generally never return a <code>null</code>
+value.<wbr/></p>
+<p>The following keys may return <code>null</code> unless they are enabled:</p>
+<ul>
+<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> (non-null iff <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON)</li>
+</ul>
+<p>(Those sometimes-null keys will nevertheless be listed here
+if they are available.<wbr/>)</p>
+<p>This field can be used to query the feature set of a camera device
+at a more granular level than capabilities.<wbr/> This is especially
+important for optional keys that are not listed under any capability
+in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Tags listed here must always have an entry in the result metadata,<wbr/>
+even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/>
+matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p>
+<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
+extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
+<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
+vendor extensions API and not against this field.<wbr/></p>
+<p>The HAL must not produce any result tags that are not listed either
+here or in the vendor tag list.<wbr/></p>
+<p>The public camera2 API will always make the vendor tags visible via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.request.availableCharacteristicsKeys">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A list of all keys that the camera device has available
+to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry follows the same rules as
+<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a> (except that it applies for
+CameraCharacteristics instead of CaptureResult).<wbr/> See above for more
+details.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Keys listed here must always have an entry in the static info metadata,<wbr/>
+even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/>
+matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p>
+<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
+extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
+<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
+vendor extensions API and not against this field.<wbr/></p>
+<p>The HAL must not have any tags in its static info that are not listed
+either here or in the vendor tag list.<wbr/></p>
+<p>The public camera2 API will always make the vendor tags visible
+via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getKeys">CameraCharacteristics#getKeys</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.request.frameCount">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>frame<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A frame counter set by the framework.<wbr/> This value monotonically
+increases with every new result (that is,<wbr/> each new result has a unique
+frameCount value).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ count of frames
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>> 0</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Reset on release()</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.request.id">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>id
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>An application-specified ID for the current
+request.<wbr/> Must be maintained unchanged in output
+frame</p>
+ </td>
+
+ <td class="entry_units">
+ arbitrary integer assigned by application
+ </td>
+
+ <td class="entry_range">
+ <p>Any int</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.request.metadataMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>request.<wbr/>metadata<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">NONE</span>
+ <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except
+for application-bound buffer data.<wbr/> If no
+application-bound streams exist,<wbr/> no frame should be
+placed in the output frame queue.<wbr/> If such streams
+exist,<wbr/> a frame should be placed on the output queue
+with null metadata but with the necessary output buffer
+information.<wbr/> Timestamp information should still be
+included with any output stream buffers</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FULL</span>
+ <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will
+only be produced if they are separately
+enabled</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>How much metadata to produce on
+output</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.request.outputStreams">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>request.<wbr/>output<wbr/>Streams
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Lists which camera output streams image data
+from this capture must be sent to</p>
+ </td>
+
+ <td class="entry_units">
+ List of camera stream IDs
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>List must only include streams that have been
+created</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If no output streams are listed,<wbr/> then the image
+data should simply be discarded.<wbr/> The image data must
+still be captured for metadata and statistics production,<wbr/>
+and the lens and flash must operate as requested.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.request.pipelineDepth">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>request.<wbr/>pipeline<wbr/>Depth
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Specifies the number of pipeline stages the frame went
+through from when it was exposed to when the final completed result
+was available to the framework.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><= <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Depending on what settings are used in the request,<wbr/> and
+what streams are configured,<wbr/> the data may undergo less processing,<wbr/>
+and some pipeline stages skipped.<wbr/></p>
+<p>See <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> for more details.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value must always represent the accurate count of how many
+pipeline stages were actually used.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_scaler" class="section">scaler</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.scaler.cropRegion">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>crop<wbr/>Region
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rectangle]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired region of the sensor to read out for this capture.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates relative to
+ android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control can be used to implement digital zoom.<wbr/></p>
+<p>The crop region coordinate system is based off
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the
+top-left corner of the sensor active array.<wbr/></p>
+<p>Output streams use this rectangle to produce their output,<wbr/>
+cropping to a smaller region if necessary to maintain the
+stream's aspect ratio,<wbr/> then scaling the sensor input to
+match the output's configured resolution.<wbr/></p>
+<p>The crop region is applied after the RAW to other color
+space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams
+(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not
+croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p>
+<p>For non-raw streams,<wbr/> any additional per-stream cropping will
+be done to maximize the final pixel area of the stream.<wbr/></p>
+<p>For example,<wbr/> if the crop region is set to a 4:3 aspect
+ratio,<wbr/> then 4:3 streams will use the exact crop
+region.<wbr/> 16:9 streams will further crop vertically
+(letterbox).<wbr/></p>
+<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3
+outputs will crop horizontally (pillarbox),<wbr/> and 16:9
+streams will match exactly.<wbr/> These additional crops will
+be centered within the crop region.<wbr/></p>
+<p>The width and height of the crop region cannot
+be set to be smaller than
+<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and
+<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p>
+<p>The camera device may adjust the crop region to account
+for rounding and other hardware requirements; the final
+crop region used will be included in the output capture
+result.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The output streams must maintain square pixels at all
+times,<wbr/> no matter what the relative aspect ratios of the
+crop region and the stream are.<wbr/> Negative values for
+corner are allowed for raw output if full pixel array is
+larger than active pixel array.<wbr/> Width and height may be
+rounded to nearest larger supportable width,<wbr/> especially
+for raw output,<wbr/> where only a few fixed scales may be
+possible.<wbr/></p>
+<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller
+size than active array size,<wbr/> the HAL need follow below cropping rules:</p>
+<ul>
+<li>
+<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active
+array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p>
+<ol>
+<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor
+cropped pixel area by (tx,<wbr/> ty),<wbr/>
+where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code>
+and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The
+(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
+<li>Scale the width and height of requested cropRegion with scaling factor of
+sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height
+respectively.<wbr/>
+Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image
+with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need
+follow the general cropping rule for this new cropRegion and effective active
+array size.<wbr/></li>
+</ol>
+</li>
+<li>
+<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>
+The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/>
+The reported cropRegion may be slightly different with the requested cropRegion since
+the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other
+hardware limitations.<wbr/></p>
+</li>
+</ul>
+<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.scaler.availableFormats">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Formats
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [hidden as imageFormat]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">RAW16</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_value">0x20</span>
+ <span class="entry_type_enum_notes"><p>RAW16 is a standard,<wbr/> cross-platform format for raw image
+buffers with 16-bit pixels.<wbr/></p>
+<p>Buffers of this format are typically expected to have a
+Bayer Color Filter Array (CFA) layout,<wbr/> which is given in
+<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>.<wbr/> Sensors with
+CFAs that are not representable by a format in
+<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a> should not
+use this format.<wbr/></p>
+<p>Buffers of this format will also follow the constraints given for
+RAW_<wbr/>OPAQUE buffers,<wbr/> but with relaxed performance constraints.<wbr/></p>
+<p>This format is intended to give users access to the full contents
+of the buffers coming directly from the image sensor prior to any
+cropping or scaling operations,<wbr/> and all coordinate systems for
+metadata used for this format are relative to the size of the
+active region of the image sensor before any geometric distortion
+correction has been applied (i.<wbr/>e.<wbr/>
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>).<wbr/> Supported
+dimensions for this format are limited to the full dimensions of
+the sensor (e.<wbr/>g.<wbr/> either <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> will be the
+only supported output size).<wbr/></p>
+<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for
+the full set of performance guarantees.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">RAW_OPAQUE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_value">0x24</span>
+ <span class="entry_type_enum_notes"><p>RAW_<wbr/>OPAQUE (or
+<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_PRIVATE">RAW_<wbr/>PRIVATE</a>
+as referred in public API) is a format for raw image buffers
+coming from an image sensor.<wbr/></p>
+<p>The actual structure of buffers of this format is
+platform-specific,<wbr/> but must follow several constraints:</p>
+<ol>
+<li>No image post-processing operations may have been applied to
+buffers of this type.<wbr/> These buffers contain raw image data coming
+directly from the image sensor.<wbr/></li>
+<li>If a buffer of this format is passed to the camera device for
+reprocessing,<wbr/> the resulting images will be identical to the images
+produced if the buffer had come directly from the sensor and was
+processed with the same settings.<wbr/></li>
+</ol>
+<p>The intended use for this format is to allow access to the native
+raw format buffers coming directly from the camera sensor without
+any additional conversions or decrease in framerate.<wbr/></p>
+<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for the full set of
+performance guarantees.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">YV12</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_value">0x32315659</span>
+ <span class="entry_type_enum_notes"><p>YCrCb 4:2:0 Planar</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">YCrCb_420_SP</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_value">0x11</span>
+ <span class="entry_type_enum_notes"><p>NV21</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">IMPLEMENTATION_DEFINED</span>
+ <span class="entry_type_enum_value">0x22</span>
+ <span class="entry_type_enum_notes"><p>System internal format,<wbr/> not application-accessible</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">YCbCr_420_888</span>
+ <span class="entry_type_enum_value">0x23</span>
+ <span class="entry_type_enum_notes"><p>Flexible YUV420 Format</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BLOB</span>
+ <span class="entry_type_enum_value">0x21</span>
+ <span class="entry_type_enum_notes"><p>JPEG format</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The list of image formats that are supported by this
+camera device for output streams.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All camera devices will support JPEG and YUV_<wbr/>420_<wbr/>888 formats.<wbr/></p>
+<p>When set to YUV_<wbr/>420_<wbr/>888,<wbr/> application can access the YUV420 data directly.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>These format values are from HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>* in
+system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h.<wbr/></p>
+<p>When IMPLEMENTATION_<wbr/>DEFINED is used,<wbr/> the platform
+gralloc module will select a format based on the usage flags provided
+by the camera HAL device and the other endpoint of the stream.<wbr/> It is
+usually used by preview and recording streams,<wbr/> where the application doesn't
+need access the image data.<wbr/></p>
+<p>YCb<wbr/>Cr_<wbr/>420_<wbr/>888 format must be supported by the HAL.<wbr/> When an image stream
+needs CPU/<wbr/>application direct access,<wbr/> this format will be used.<wbr/></p>
+<p>The BLOB format must be supported by the HAL.<wbr/> This is used for the JPEG stream.<wbr/></p>
+<p>A RAW_<wbr/>OPAQUE buffer should contain only pixel data.<wbr/> It is strongly
+recommended that any information used by the camera device when
+processing images is fully expressed by the result metadata
+for that image buffer.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableJpegMinDurations">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Min<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The minimum frame duration that is supported
+for each resolution in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>TODO: Remove property.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This corresponds to the minimum steady-state frame duration when only
+that JPEG stream is active and captured in a burst,<wbr/> with all
+processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST.<wbr/></p>
+<p>When multiple streams are configured,<wbr/> the minimum
+frame duration will be >= max(individual stream min
+durations)</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableJpegSizes">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [hidden as size]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The JPEG resolutions that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ <p>TODO: Remove property.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/> All camera devices will support
+sensor maximum resolution (defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must include sensor maximum resolution
+(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>),<wbr/>
+and should include half/<wbr/>quarter of sensor maximum resolution.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableMaxDigitalZoom">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum ratio between both active area width
+and crop region width,<wbr/> and active area height and
+crop region height,<wbr/> for <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Zoom scale factor
+ </td>
+
+ <td class="entry_range">
+ <p>>=1</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This represents the maximum amount of zooming possible by
+the camera device,<wbr/> or equivalently,<wbr/> the minimum cropping
+window size.<wbr/></p>
+<p>Crop regions that have a width or height that is smaller
+than this ratio allows will be rounded up to the minimum
+allowed size by the camera device.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableProcessedMinDurations">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Min<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>For each available processed output size (defined in
+<a href="#static_android.scaler.availableProcessedSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes</a>),<wbr/> this property lists the
+minimum supportable frame duration for that size.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This should correspond to the frame duration when only that processed
+stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
+set to FAST.<wbr/></p>
+<p>When multiple streams are configured,<wbr/> the minimum frame duration will
+be >= max(individual stream min durations).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableProcessedSizes">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [hidden as size]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The resolutions available for use with
+processed output streams,<wbr/> such as YV12,<wbr/> NV12,<wbr/> and
+platform opaque YUV/<wbr/>RGB streams to the GPU or video
+encoders.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/></p>
+<p>For a given use case,<wbr/> the actual maximum supported resolution
+may be lower than what is listed here,<wbr/> depending on the destination
+Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
+the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
+smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
+can provide.<wbr/></p>
+<p>Please reference the documentation for the image data destination to
+check if it limits the maximum size for image data.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
+the HAL must include all JPEG sizes listed in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a>
+and each below resolution if it is smaller than or equal to the sensor
+maximum resolution (if they are not listed in JPEG sizes already):</p>
+<ul>
+<li>240p (320 x 240)</li>
+<li>480p (640 x 480)</li>
+<li>720p (1280 x 720)</li>
+<li>1080p (1920 x 1080)</li>
+</ul>
+<p>For LIMITED capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
+the HAL only has to list up to the maximum video size supported by the devices.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableRawMinDurations">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Min<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>For each available raw output size (defined in
+<a href="#static_android.scaler.availableRawSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes</a>),<wbr/> this property lists the minimum
+supportable frame duration for that size.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Should correspond to the frame duration when only the raw stream is
+active.<wbr/></p>
+<p>When multiple streams are configured,<wbr/> the minimum
+frame duration will be >= max(individual stream min
+durations)</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableRawSizes">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="1">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [system as size]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The resolutions available for use with raw
+sensor output streams,<wbr/> listed as width,<wbr/>
+height</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableInputOutputFormatsMap">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [hidden as reprocessFormatsMap]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The mapping of image formats that are supported by this
+camera device for input streams,<wbr/> to their corresponding output formats.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All camera devices with at least 1
+<a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> will have at least one
+available input format.<wbr/></p>
+<p>The camera device will support the following map of formats,<wbr/>
+if its dependent capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>) is supported:</p>
+<table>
+<thead>
+<tr>
+<th align="left">Input Format</th>
+<th align="left">Output Format</th>
+<th align="left">Capability</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="left">PRIVATE_<wbr/>REPROCESSING</td>
+</tr>
+<tr>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="left">PRIVATE_<wbr/>REPROCESSING</td>
+</tr>
+<tr>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="left">YUV_<wbr/>REPROCESSING</td>
+</tr>
+<tr>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="left">YUV_<wbr/>REPROCESSING</td>
+</tr>
+</tbody>
+</table>
+<p>PRIVATE refers to a device-internal format that is not directly application-visible.<wbr/> A
+PRIVATE input surface can be acquired by <a href="https://developer.android.com/reference/android/media/ImageReader.html#newInstance">ImageReader#newInstance</a>
+with <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> as the format.<wbr/></p>
+<p>For a PRIVATE_<wbr/>REPROCESSING-capable camera device,<wbr/> using the PRIVATE format as either input
+or output will never hurt maximum frame rate (i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">getOutputStallDuration(ImageFormat.<wbr/>PRIVATE,<wbr/> size)</a> is always 0),<wbr/></p>
+<p>Attempting to configure an input stream with output streams not
+listed as available in this map is not valid.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For the formats,<wbr/> see <code>system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h</code> for a definition
+of the image format enumerations.<wbr/> The PRIVATE format refers to the
+HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED format.<wbr/> The HAL could determine
+the actual format by using the gralloc usage flags.<wbr/>
+For ZSL use case in particular,<wbr/> the HAL could choose appropriate format (partially
+processed YUV or RAW based format) by checking the format and GRALLOC_<wbr/>USAGE_<wbr/>HW_<wbr/>CAMERA_<wbr/>ZSL.<wbr/>
+See camera3.<wbr/>h for more details.<wbr/></p>
+<p>This value is encoded as a variable-size array-of-arrays.<wbr/>
+The inner array always contains <code>[format,<wbr/> length,<wbr/> ...<wbr/>]</code> where
+<code>...<wbr/></code> has <code>length</code> elements.<wbr/> An inner array is followed by another
+inner array if the total metadata entry size hasn't yet been exceeded.<wbr/></p>
+<p>A code sample to read/<wbr/>write this encoding (with a device that
+supports reprocessing IMPLEMENTATION_<wbr/>DEFINED to YUV_<wbr/>420_<wbr/>888,<wbr/> and JPEG,<wbr/>
+and reprocessing YUV_<wbr/>420_<wbr/>888 to YUV_<wbr/>420_<wbr/>888 and JPEG):</p>
+<pre><code>//<wbr/> reading
+int32_<wbr/>t* contents = &entry.<wbr/>i32[0];
+for (size_<wbr/>t i = 0; i < entry.<wbr/>count; ) {
+ int32_<wbr/>t format = contents[i++];
+ int32_<wbr/>t length = contents[i++];
+ int32_<wbr/>t output_<wbr/>formats[length];
+ memcpy(&output_<wbr/>formats[0],<wbr/> &contents[i],<wbr/>
+ length * sizeof(int32_<wbr/>t));
+ i += length;
+}
+
+//<wbr/> writing (static example,<wbr/> PRIVATE_<wbr/>REPROCESSING + YUV_<wbr/>REPROCESSING)
+int32_<wbr/>t[] contents = {
+ IMPLEMENTATION_<wbr/>DEFINED,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/>
+ YUV_<wbr/>420_<wbr/>888,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/>
+};
+update_<wbr/>camera_<wbr/>metadata_<wbr/>entry(metadata,<wbr/> index,<wbr/> &contents[0],<wbr/>
+ sizeof(contents)/<wbr/>sizeof(contents[0]),<wbr/> &updated_<wbr/>entry);
+</code></pre>
+<p>If the HAL claims to support any of the capabilities listed in the
+above details,<wbr/> then it must also support all the input-output
+combinations listed for that capability.<wbr/> It can optionally support
+additional formats if it so chooses.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableStreamConfigurations">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 4
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OUTPUT</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">INPUT</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The available stream configurations that this
+camera device supports
+(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The configurations are listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code>
+tuples.<wbr/></p>
+<p>For a given use case,<wbr/> the actual maximum supported resolution
+may be lower than what is listed here,<wbr/> depending on the destination
+Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
+the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
+smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
+can provide.<wbr/></p>
+<p>Please reference the documentation for the image data destination to
+check if it limits the maximum size for image data.<wbr/></p>
+<p>Not all output formats may be supported in a configuration with
+an input stream of a particular format.<wbr/> For more details,<wbr/> see
+<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p>
+<p>The following table describes the minimum required output stream
+configurations based on the hardware level
+(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p>
+<table>
+<thead>
+<tr>
+<th align="center">Format</th>
+<th align="center">Size</th>
+<th align="center">Hardware Level</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">JPEG</td>
+<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></td>
+<td align="center">Any</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center">JPEG</td>
+<td align="center">1920x1080 (1080p)</td>
+<td align="center">Any</td>
+<td align="center">if 1080p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center">JPEG</td>
+<td align="center">1280x720 (720)</td>
+<td align="center">Any</td>
+<td align="center">if 720p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center">JPEG</td>
+<td align="center">640x480 (480p)</td>
+<td align="center">Any</td>
+<td align="center">if 480p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center">JPEG</td>
+<td align="center">320x240 (240p)</td>
+<td align="center">Any</td>
+<td align="center">if 240p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center">YUV_<wbr/>420_<wbr/>888</td>
+<td align="center">all output sizes available for JPEG</td>
+<td align="center">FULL</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center">YUV_<wbr/>420_<wbr/>888</td>
+<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td>
+<td align="center">LIMITED</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center">IMPLEMENTATION_<wbr/>DEFINED</td>
+<td align="center">same as YUV_<wbr/>420_<wbr/>888</td>
+<td align="center">Any</td>
+<td align="center"></td>
+</tr>
+</tbody>
+</table>
+<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> for additional
+mandatory stream configurations on a per-capability basis.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>It is recommended (but not mandatory) to also include half/<wbr/>quarter
+of sensor maximum resolution for JPEG formats (regardless of hardware
+level).<wbr/></p>
+<p>(The following is a rewording of the above required table):</p>
+<p>For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p>
+<ul>
+<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
+(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution
+(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/>
+it does not have to be included in the supported JPEG sizes.<wbr/></li>
+<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as
+the dimensions being a multiple of 16.<wbr/></li>
+</ul>
+<p>Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/>
+However,<wbr/> the largest JPEG size must be as close as possible to the sensor maximum
+resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/>
+additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/>
+if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect
+ratio 4:3,<wbr/> the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be
+3264x2448.<wbr/></p>
+<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
+the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed
+here as output streams.<wbr/></p>
+<p>It must also include each below resolution if it is smaller than or
+equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG
+formats),<wbr/> as output streams:</p>
+<ul>
+<li>240p (320 x 240)</li>
+<li>480p (640 x 480)</li>
+<li>720p (1280 x 720)</li>
+<li>1080p (1920 x 1080)</li>
+</ul>
+<p>For LIMITED capability devices
+(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
+the HAL only has to list up to the maximum video size
+supported by the device.<wbr/></p>
+<p>Regardless of hardware level,<wbr/> every output resolution available for
+YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p>
+<p>This supercedes the following fields,<wbr/> which are now deprecated:</p>
+<ul>
+<li>availableFormats</li>
+<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableMinFrameDurations">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This lists the minimum frame duration for each
+format/<wbr/>size combination.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This should correspond to the frame duration when only that
+stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
+set to either OFF or FAST.<wbr/></p>
+<p>When multiple streams are used in a request,<wbr/> the minimum frame
+duration will be max(individual stream min durations).<wbr/></p>
+<p>The minimum frame duration of a stream (of a particular format,<wbr/> size)
+is the same regardless of whether the stream is input or output.<wbr/></p>
+<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about
+calculating the max frame rate.<wbr/></p>
+<p>(Keep in sync with
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.availableStallDurations">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This lists the maximum stall duration for each
+output format/<wbr/>size combination.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A stall duration is how much extra time would get added
+to the normal minimum frame duration for a repeating request
+that has streams with non-zero stall.<wbr/></p>
+<p>For example,<wbr/> consider JPEG captures which have the following
+characteristics:</p>
+<ul>
+<li>JPEG streams act like processed YUV streams in requests for which
+they are not included; in requests in which they are directly
+referenced,<wbr/> they act as JPEG streams.<wbr/> This is because supporting a
+JPEG stream requires the underlying YUV data to always be ready for
+use by a JPEG encoder,<wbr/> but the encoder will only be used (and impact
+frame duration) on requests that actually reference a JPEG stream.<wbr/></li>
+<li>The JPEG processor can run concurrently to the rest of the camera
+pipeline,<wbr/> but cannot process more than 1 capture at a time.<wbr/></li>
+</ul>
+<p>In other words,<wbr/> using a repeating YUV request would result
+in a steady frame rate (let's say it's 30 FPS).<wbr/> If a single
+JPEG request is submitted periodically,<wbr/> the frame rate will stay
+at 30 FPS (as long as we wait for the previous JPEG to return each
+time).<wbr/> If we try to submit a repeating YUV + JPEG request,<wbr/> then
+the frame rate will drop from 30 FPS.<wbr/></p>
+<p>In general,<wbr/> submitting a new request with a non-0 stall time
+stream will <em>not</em> cause a frame rate drop unless there are still
+outstanding buffers for that stream from previous requests.<wbr/></p>
+<p>Submitting a repeating request with streams (call this <code>S</code>)
+is the same as setting the minimum frame duration from
+the normal minimum frame duration corresponding to <code>S</code>,<wbr/> added with
+the maximum stall duration for <code>S</code>.<wbr/></p>
+<p>If interleaving requests with and without a stall duration,<wbr/>
+a request will stall by the maximum of the remaining times
+for each can-stall stream with outstanding buffers.<wbr/></p>
+<p>This means that a stalling request will not have an exposure start
+until the stall has completed.<wbr/></p>
+<p>This should correspond to the stall duration when only that stream is
+active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST
+or OFF.<wbr/> Setting any of the processing modes to HIGH_<wbr/>QUALITY
+effectively results in an indeterminate stall duration for all
+streams in a request (the regular stall calculation rules are
+ignored).<wbr/></p>
+<p>The following formats may always have a stall duration:</p>
+<ul>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">ImageFormat#RAW_<wbr/>SENSOR</a></li>
+</ul>
+<p>The following formats will never have a stall duration:</p>
+<ul>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></li>
+<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a></li>
+</ul>
+<p>All other formats may or may not have an allowed stall duration on
+a per-capability basis; refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
+for more details.<wbr/></p>
+<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> for more information about
+calculating the max frame rate (absent stalls).<wbr/></p>
+<p>(Keep up to date with
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> )</p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If possible,<wbr/> it is recommended that all non-JPEG formats
+(such as RAW16) should not have a stall duration.<wbr/> RAW10,<wbr/> RAW12,<wbr/> RAW_<wbr/>OPAQUE
+and IMPLEMENTATION_<wbr/>DEFINED must not have stall durations.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.streamConfigurationMap">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public as streamConfigurationMap]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The available stream configurations that this
+camera device supports; also includes the minimum frame durations
+and the stall durations for each format/<wbr/>size combination.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All camera devices will support sensor maximum resolution (defined by
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) for the JPEG format.<wbr/></p>
+<p>For a given use case,<wbr/> the actual maximum supported resolution
+may be lower than what is listed here,<wbr/> depending on the destination
+Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
+the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
+smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
+can provide.<wbr/></p>
+<p>Please reference the documentation for the image data destination to
+check if it limits the maximum size for image data.<wbr/></p>
+<p>The following table describes the minimum required output stream
+configurations based on the hardware level
+(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p>
+<table>
+<thead>
+<tr>
+<th align="center">Format</th>
+<th align="center">Size</th>
+<th align="center">Hardware Level</th>
+<th align="center">Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> (*1)</td>
+<td align="center">Any</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="center">1920x1080 (1080p)</td>
+<td align="center">Any</td>
+<td align="center">if 1080p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="center">1280x720 (720p)</td>
+<td align="center">Any</td>
+<td align="center">if 720p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="center">640x480 (480p)</td>
+<td align="center">Any</td>
+<td align="center">if 480p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
+<td align="center">320x240 (240p)</td>
+<td align="center">Any</td>
+<td align="center">if 240p <= activeArraySize</td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="center">all output sizes available for JPEG</td>
+<td align="center">FULL</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
+<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td>
+<td align="center">LIMITED</td>
+<td align="center"></td>
+</tr>
+<tr>
+<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
+<td align="center">same as YUV_<wbr/>420_<wbr/>888</td>
+<td align="center">Any</td>
+<td align="center"></td>
+</tr>
+</tbody>
+</table>
+<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for additional mandatory
+stream configurations on a per-capability basis.<wbr/></p>
+<p>*1: For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p>
+<ul>
+<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
+(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution
+(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/>
+it does not have to be included in the supported JPEG sizes.<wbr/></li>
+<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as
+the dimensions being a multiple of 16.<wbr/>
+Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/>
+However,<wbr/> the largest JPEG size will be as close as possible to the sensor maximum
+resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/>
+additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/>
+if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect
+ratio 4:3,<wbr/> and the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be
+3264x2448.<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Do not set this property directly
+(it is synthetic and will not be available at the HAL layer);
+set the <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> instead.<wbr/></p>
+<p>Not all output formats may be supported in a configuration with
+an input stream of a particular format.<wbr/> For more details,<wbr/> see
+<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p>
+<p>It is recommended (but not mandatory) to also include half/<wbr/>quarter
+of sensor maximum resolution for JPEG formats (regardless of hardware
+level).<wbr/></p>
+<p>(The following is a rewording of the above required table):</p>
+<p>The HAL must include sensor maximum resolution (defined by
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p>
+<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
+the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed
+here as output streams.<wbr/></p>
+<p>It must also include each below resolution if it is smaller than or
+equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG
+formats),<wbr/> as output streams:</p>
+<ul>
+<li>240p (320 x 240)</li>
+<li>480p (640 x 480)</li>
+<li>720p (1280 x 720)</li>
+<li>1080p (1920 x 1080)</li>
+</ul>
+<p>For LIMITED capability devices
+(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
+the HAL only has to list up to the maximum video size
+supported by the device.<wbr/></p>
+<p>Regardless of hardware level,<wbr/> every output resolution available for
+YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p>
+<p>This supercedes the following fields,<wbr/> which are now deprecated:</p>
+<ul>
+<li>availableFormats</li>
+<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.scaler.croppingType">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>scaler.<wbr/>cropping<wbr/>Type
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CENTER_ONLY</span>
+ <span class="entry_type_enum_notes"><p>The camera device only supports centered crop regions.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FREEFORM</span>
+ <span class="entry_type_enum_notes"><p>The camera device supports arbitrarily chosen crop regions.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The crop type that this camera device supports.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When passing a non-centered crop region (<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>) to a camera
+device that only supports CENTER_<wbr/>ONLY cropping,<wbr/> the camera device will move the
+crop region to the center of the sensor active array (<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>)
+and keep the crop region width and height unchanged.<wbr/> The camera device will return the
+final used crop region in metadata result <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
+<p>Camera devices that support FREEFORM cropping will support any crop region that
+is inside of the active array.<wbr/> The camera device will apply the same crop region and
+return the final used crop region in capture result metadata <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
+<p>LEGACY capability devices will only support CENTER_<wbr/>ONLY cropping.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.scaler.cropRegion">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>scaler.<wbr/>crop<wbr/>Region
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rectangle]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The desired region of the sensor to read out for this capture.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates relative to
+ android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This control can be used to implement digital zoom.<wbr/></p>
+<p>The crop region coordinate system is based off
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the
+top-left corner of the sensor active array.<wbr/></p>
+<p>Output streams use this rectangle to produce their output,<wbr/>
+cropping to a smaller region if necessary to maintain the
+stream's aspect ratio,<wbr/> then scaling the sensor input to
+match the output's configured resolution.<wbr/></p>
+<p>The crop region is applied after the RAW to other color
+space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams
+(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not
+croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p>
+<p>For non-raw streams,<wbr/> any additional per-stream cropping will
+be done to maximize the final pixel area of the stream.<wbr/></p>
+<p>For example,<wbr/> if the crop region is set to a 4:3 aspect
+ratio,<wbr/> then 4:3 streams will use the exact crop
+region.<wbr/> 16:9 streams will further crop vertically
+(letterbox).<wbr/></p>
+<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3
+outputs will crop horizontally (pillarbox),<wbr/> and 16:9
+streams will match exactly.<wbr/> These additional crops will
+be centered within the crop region.<wbr/></p>
+<p>The width and height of the crop region cannot
+be set to be smaller than
+<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and
+<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p>
+<p>The camera device may adjust the crop region to account
+for rounding and other hardware requirements; the final
+crop region used will be included in the output capture
+result.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The output streams must maintain square pixels at all
+times,<wbr/> no matter what the relative aspect ratios of the
+crop region and the stream are.<wbr/> Negative values for
+corner are allowed for raw output if full pixel array is
+larger than active pixel array.<wbr/> Width and height may be
+rounded to nearest larger supportable width,<wbr/> especially
+for raw output,<wbr/> where only a few fixed scales may be
+possible.<wbr/></p>
+<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller
+size than active array size,<wbr/> the HAL need follow below cropping rules:</p>
+<ul>
+<li>
+<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active
+array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p>
+<ol>
+<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor
+cropped pixel area by (tx,<wbr/> ty),<wbr/>
+where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code>
+and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The
+(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
+<li>Scale the width and height of requested cropRegion with scaling factor of
+sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height
+respectively.<wbr/>
+Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image
+with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need
+follow the general cropping rule for this new cropRegion and effective active
+array size.<wbr/></li>
+</ol>
+</li>
+<li>
+<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>
+The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/>
+The reported cropRegion may be slightly different with the requested cropRegion since
+the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other
+hardware limitations.<wbr/></p>
+</li>
+</ul>
+<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_sensor" class="section">sensor</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.sensor.exposureTime">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>exposure<wbr/>Time
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Duration each pixel is exposed to
+light.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the
+duration exposed to the nearest possible value (rather than expose longer).<wbr/>
+The final exposure time used will be available in the output capture result.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.sensor.frameDuration">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>frame<wbr/>Duration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Duration from start of frame exposure to
+start of next frame exposure.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/>
+<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration
+is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The maximum frame rate that can be supported by a camera subsystem is
+a function of many factors:</p>
+<ul>
+<li>Requested resolutions of output image streams</li>
+<li>Availability of binning /<wbr/> skipping modes on the imager</li>
+<li>The bandwidth of the imager interface</li>
+<li>The bandwidth of the various ISP processing blocks</li>
+</ul>
+<p>Since these factors can vary greatly between different ISPs and
+sensors,<wbr/> the camera abstraction tries to represent the bandwidth
+restrictions with as simple a model as possible.<wbr/></p>
+<p>The model presented has the following characteristics:</p>
+<ul>
+<li>The image sensor is always configured to output the smallest
+resolution possible given the application's requested output stream
+sizes.<wbr/> The smallest resolution is defined as being at least as large
+as the largest requested output stream size; the camera pipeline must
+never digitally upsample sensor data when the crop region covers the
+whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream
+resolutions are configured,<wbr/> the sensor can provide a higher frame
+rate.<wbr/></li>
+<li>Since any request may use any or all the currently configured
+output streams,<wbr/> the sensor and ISP must be configured to support
+scaling a single capture to all the streams at the same time.<wbr/> This
+means the camera pipeline must be ready to produce the largest
+requested output size without any delay.<wbr/> Therefore,<wbr/> the overall
+frame rate of a given configured stream set is governed only by the
+largest requested stream resolution.<wbr/></li>
+<li>Using more than one output stream in a request does not affect the
+frame duration.<wbr/></li>
+<li>Certain format-streams may need to do additional background processing
+before data is consumed/<wbr/>produced by that stream.<wbr/> These processors
+can run concurrently to the rest of the camera pipeline,<wbr/> but
+cannot process more than 1 capture at a time.<wbr/></li>
+</ul>
+<p>The necessary information for the application,<wbr/> given the model above,<wbr/>
+is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/>
+These are used to determine the maximum frame rate /<wbr/> minimum frame
+duration that is possible for a given stream configuration.<wbr/></p>
+<p>Specifically,<wbr/> the application can use the following rules to
+determine the minimum frame duration it can request from the camera
+device:</p>
+<ol>
+<li>Let the set of currently configured input/<wbr/>output streams
+be called <code>S</code>.<wbr/></li>
+<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking
+it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
+(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be
+called <code>F</code>.<wbr/></li>
+<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed
+for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams
+used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li>
+</ol>
+<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>
+using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code>
+determines the steady state frame rate that the application will get
+if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of
+request be called <code>Rsimple</code>.<wbr/></p>
+<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+by a single capture of a new request <code>Rstall</code> (which has at least
+one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+same minimum frame duration this will not cause a frame rate loss
+if all buffers from the previous <code>Rstall</code> have already been
+delivered.<wbr/></p>
+<p>For more details about stalling,<wbr/> see
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For more details about stalling,<wbr/> see
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.sensor.sensitivity">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>sensitivity
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of gain applied to sensor data
+before processing.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ ISO arithmetic units
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The sensitivity is the standard ISO sensitivity value,<wbr/>
+as defined in ISO 12232:2006.<wbr/></p>
+<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and
+if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device
+is guaranteed to use only analog amplification for applying the gain.<wbr/></p>
+<p>If the camera device cannot apply the exact sensitivity
+requested,<wbr/> it will reduce the gain to the nearest supported
+value.<wbr/> The final sensitivity used will be available in the
+output capture result.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>ISO 12232:2006 REI method is acceptable.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.sensor.testPatternData">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern
+when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/>
+The camera device then uses the most significant X bits
+that correspond to how many bits are in its Bayer raw sensor
+output.<wbr/></p>
+<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the
+10 most significant bits from each color channel.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.sensor.testPatternMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera
+device returns captures from the image sensor.<wbr/></p>
+<p>This is the default if the key is not set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SOLID_COLOR</span>
+ <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its
+respective color channel provided in
+<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p>
+<p>For example:</p>
+<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0]
+</code></pre>
+<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p>
+<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0]
+</code></pre>
+<p>All red pixels are 100% red.<wbr/> Only the odd green pixels
+are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">COLOR_BARS</span>
+ <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p>
+<p>The vertical bars (left-to-right) are as follows:</p>
+<ul>
+<li>100% white</li>
+<li>yellow</li>
+<li>cyan</li>
+<li>green</li>
+<li>magenta</li>
+<li>red</li>
+<li>blue</li>
+<li>black</li>
+</ul>
+<p>In general the image would look like the following:</p>
+<pre><code>W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+
+(B = Blue,<wbr/> K = Black)
+</code></pre>
+<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/>
+When this is not possible,<wbr/> the bar size should be rounded
+down to the nearest integer and the pattern can repeat
+on the right side.<wbr/></p>
+<p>Each bar's height must always take up the full sensor
+pixel array height.<wbr/></p>
+<p>Each pixel in this test pattern must be set to either
+0% intensity or 100% intensity.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span>
+ <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that
+each bar should start at its specified color at the top,<wbr/>
+and fade to gray at the bottom.<wbr/></p>
+<p>Furthermore each bar is further subdivided into a left and
+right half.<wbr/> The left half should have a smooth gradient,<wbr/>
+and the right half should have a quantized gradient.<wbr/></p>
+<p>In particular,<wbr/> the right half's should consist of blocks of the
+same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p>
+<p>The least significant bits in the quantized gradient should
+be copied from the most significant bits of the smooth gradient.<wbr/></p>
+<p>The height of each bar should always be a multiple of 128.<wbr/>
+When this is not the case,<wbr/> the pattern should repeat at the bottom
+of the image.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PN9</span>
+ <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence
+generated from a PN9 512-bit sequence (typically implemented
+in hardware with a linear feedback shift register).<wbr/></p>
+<p>The generator should be reset at the beginning of each frame,<wbr/>
+and thus each subsequent raw frame with this test pattern should
+be exactly the same as the last.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CUSTOM1</span>
+ <span class="entry_type_enum_value">256</span>
+ <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are
+available only on this camera device are at least this numeric
+value.<wbr/></p>
+<p>All of the custom test patterns will be static
+(that is the raw image must not vary from frame to frame).<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>When enabled,<wbr/> the sensor sends a test pattern instead of
+doing a real exposure from the camera.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified
+by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should
+work as normal.<wbr/></p>
+<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still
+occur (and that the test pattern remain unmodified,<wbr/> since the flash
+would not actually affect it).<wbr/></p>
+<p>Defaults to OFF.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All test patterns are specified in the Bayer domain.<wbr/></p>
+<p>The HAL may choose to substitute test patterns from the sensor
+with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be
+indistinguishable to the ISP whether the data came from the
+sensor interconnect bus (such as CSI2) or memory.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.sensor.info.activeArraySize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rectangle]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">Four ints defining the active pixel rectangle</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The area of the image sensor which corresponds to active pixels after any geometric
+distortion correction has been applied.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates on the image sensor
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/>
+the region that actually receives light from the scene) after any geometric correction
+has been applied,<wbr/> and should be treated as the maximum size in pixels of any of the
+image output formats aside from the raw formats.<wbr/></p>
+<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of
+the full pixel array,<wbr/> and the size of the full pixel array is given by
+<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>The coordinate system for most other keys that list pixel coordinates,<wbr/> including
+<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>,<wbr/> is defined relative to the active array rectangle given in
+this field,<wbr/> with <code>(0,<wbr/> 0)</code> being the top-left of this rectangle.<wbr/></p>
+<p>The active array may be smaller than the full pixel array,<wbr/> since the full array may
+include black calibration pixels or other inactive regions,<wbr/> and geometric correction
+resulting in scaling or cropping may have been applied.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be
+>= <code>(0,<wbr/>0)</code>.<wbr/>
+The <code>(width,<wbr/> height)</code> must be <= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.sensitivityRange">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeInt]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">Range of supported sensitivities</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Range of sensitivities for <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> supported by this
+camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Min <= 100,<wbr/> Max >= 800</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The values are the standard ISO sensitivity values,<wbr/>
+as defined in ISO 12232:2006.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.colorFilterArrangement">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">RGGB</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">GRBG</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">GBRG</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">BGGR</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">RGB</span>
+ <span class="entry_type_enum_notes"><p>Sensor is not Bayer; output has 3 16-bit
+values for each pixel,<wbr/> instead of just 1 16-bit value
+per pixel.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The arrangement of color filters on sensor;
+represents the colors in the top-left 2x2 section of
+the sensor,<wbr/> in reading order.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.exposureTimeRange">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as rangeLong]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">nanoseconds</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The range of image exposure times for <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> supported
+by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>The minimum exposure time will be less than 100 us.<wbr/> For FULL
+capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
+the maximum exposure time will be greater than 100ms.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
+The maximum of the range SHOULD be at least 1 second (1e9),<wbr/> MUST be at least
+100ms.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.maxFrameDuration">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum possible frame duration (minimum frame rate) for
+<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> that is supported this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>For FULL capability devices
+(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> at least 100ms.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Attempting to use frame durations beyond the maximum will result in the frame
+duration being clipped to the maximum.<wbr/> See that control for a full definition of frame
+durations.<wbr/></p>
+<p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
+for the minimum frame duration values.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
+The maximum of the range SHOULD be at least
+1 second (1e9),<wbr/> MUST be at least 100ms (100e6).<wbr/></p>
+<p><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a> must be greater or
+equal to the <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a> max
+value (since exposure time overrides frame duration).<wbr/></p>
+<p>Available minimum frame durations for JPEG must be no greater
+than that of the YUV_<wbr/>420_<wbr/>888/<wbr/>IMPLEMENTATION_<wbr/>DEFINED
+minimum frame durations (for that respective size).<wbr/></p>
+<p>Since JPEG processing is considered offline and can take longer than
+a single uncompressed capture,<wbr/> refer to
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>
+for details about encoding this scenario.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.physicalSize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as sizeF]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">width x height</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The physical dimensions of the full pixel
+array.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Millimeters
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is the physical size of the sensor pixel
+array defined by <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Needed for FOV calculation for old API</p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.pixelArraySize">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [public as size]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Dimensions of the full pixel array,<wbr/> possibly
+including black calibration pixels.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixels
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The pixel count of the full pixel array of the image sensor,<wbr/> which covers
+<a href="#static_android.sensor.info.physicalSize">android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size</a> area.<wbr/> This represents the full pixel dimensions of
+the raw buffers produced by this sensor.<wbr/></p>
+<p>If a camera device supports raw sensor formats,<wbr/> either this or
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is the maximum dimensions for the raw
+output formats listed in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> (this depends on
+whether or not the image sensor returns buffers containing pixels that are not
+part of the active array region for blacklevel calibration or other purposes).<wbr/></p>
+<p>Some parts of the full pixel array may not receive light from the scene,<wbr/>
+or be otherwise inactive.<wbr/> The <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> key
+defines the rectangle of active pixels that will be included in processed image
+formats.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.whiteLevel">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum raw value output by sensor.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>> 255 (8-bit output)</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This specifies the fully-saturated encoding level for the raw
+sample values from the sensor.<wbr/> This is typically caused by the
+sensor becoming highly non-linear or clipping.<wbr/> The minimum for
+each channel is specified by the offset in the
+<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> key.<wbr/></p>
+<p>The white level is typically determined either by sensor bit depth
+(8-14 bits is expected),<wbr/> or by the point where the sensor response
+becomes too non-linear to be useful.<wbr/> The default value for this is
+maximum representable value for a 16-bit raw sample (2^16 - 1).<wbr/></p>
+<p>The white level values of captured images may vary for different
+capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key
+represents a coarse approximation for such case.<wbr/> It is recommended
+to use <a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> for captures when supported
+by the camera device,<wbr/> which provides more accurate white level values.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The full bit depth of the sensor must be available in the raw data,<wbr/>
+so the value for linear sensors should not be significantly lower
+than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.timestampSource">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">UNKNOWN</span>
+ <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in nanoseconds and monotonic,<wbr/>
+but can not be compared to timestamps from other subsystems
+(e.<wbr/>g.<wbr/> accelerometer,<wbr/> gyro etc.<wbr/>),<wbr/> or other instances of the same or different
+camera devices in the same system.<wbr/> Timestamps between streams and results for
+a single camera instance are comparable,<wbr/> and the timestamps for all buffers
+and the result metadata generated by a single capture are identical.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">REALTIME</span>
+ <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in the same timebase as
+<a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/>
+and they can be compared to other timestamps using that base.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The time base source for sensor capture start timestamps.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The timestamps provided for captures are always in nanoseconds and monotonic,<wbr/> but
+may not based on a time source that can be compared to other system time sources.<wbr/></p>
+<p>This characteristic defines the source for the timestamps,<wbr/> and therefore whether they
+can be compared against other system time sources/<wbr/>timestamps.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For camera devices implement UNKNOWN,<wbr/> the camera framework expects that the timestamp
+source to be SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC.<wbr/> For camera devices implement REALTIME,<wbr/> the camera
+framework expects that the timestamp source to be SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> See
+system/<wbr/>core/<wbr/>include/<wbr/>utils/<wbr/>Timers.<wbr/>h for the definition of SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC and
+SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> Note that HAL must follow above expectation; otherwise video
+recording might suffer unexpected behavior.<wbr/></p>
+<p>Also,<wbr/> camera devices implements REALTIME must pass the ITS sensor fusion test which
+tests the alignment between camera timestamps and gyro sensor timestamps.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.lensShadingApplied">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the RAW images output from this camera device are subject to
+lens shading correction.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If TRUE,<wbr/> all images produced by the camera device in the RAW image formats will
+have lens shading correction already applied to it.<wbr/> If FALSE,<wbr/> the images will
+not be adjusted for lens shading correction.<wbr/>
+See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image formats.<wbr/></p>
+<p>This key will be <code>null</code> for all devices do not report this information.<wbr/>
+Devices with RAW capability will always report this information in this key.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.info.preCorrectionActiveArraySize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as rectangle]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">Four ints defining the active pixel rectangle</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The area of the image sensor which corresponds to active pixels prior to the
+application of any geometric distortion correction.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Pixel coordinates on the image sensor
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/>
+the region that actually receives light from the scene) before any geometric correction
+has been applied,<wbr/> and should be treated as the active region rectangle for any of the
+raw formats.<wbr/> All metadata associated with raw processing (e.<wbr/>g.<wbr/> the lens shading
+correction map,<wbr/> and radial distortion fields) treats the top,<wbr/> left of this rectangle as
+the origin,<wbr/> (0,<wbr/>0).<wbr/></p>
+<p>The size of this region determines the maximum field of view and the maximum number of
+pixels that an image from this sensor can contain,<wbr/> prior to the application of
+geometric distortion correction.<wbr/> The effective maximum pixel dimensions of a
+post-distortion-corrected image is given by the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>
+field,<wbr/> and the effective maximum field of view for a post-distortion-corrected image
+can be calculated by applying the geometric distortion correction fields to this
+rectangle,<wbr/> and cropping to the rectangle given in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>E.<wbr/>g.<wbr/> to calculate position of a pixel,<wbr/> (x,<wbr/>y),<wbr/> in a processed YUV output image with the
+dimensions in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> given the position of a pixel,<wbr/>
+(x',<wbr/> y'),<wbr/> in the raw pixel array with dimensions give in
+<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>:</p>
+<ol>
+<li>Choose a pixel (x',<wbr/> y') within the active array region of the raw buffer given in
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>,<wbr/> otherwise this pixel is considered
+to be outside of the FOV,<wbr/> and will not be shown in the processed output image.<wbr/></li>
+<li>Apply geometric distortion correction to get the post-distortion pixel coordinate,<wbr/>
+(x_<wbr/>i,<wbr/> y_<wbr/>i).<wbr/> When applying geometric correction metadata,<wbr/> note that metadata for raw
+buffers is defined relative to the top,<wbr/> left of the
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> rectangle.<wbr/></li>
+<li>If the resulting corrected pixel coordinate is within the region given in
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> then the position of this pixel in the
+processed output image buffer is <code>(x_<wbr/>i - activeArray.<wbr/>left,<wbr/> y_<wbr/>i - activeArray.<wbr/>top)</code>,<wbr/>
+when the top,<wbr/> left coordinate of that buffer is treated as (0,<wbr/> 0).<wbr/></li>
+</ol>
+<p>Thus,<wbr/> for pixel x',<wbr/>y' = (25,<wbr/> 25) on a sensor where <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>
+is (100,<wbr/>100),<wbr/> <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is (10,<wbr/> 10,<wbr/> 100,<wbr/> 100),<wbr/>
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> is (20,<wbr/> 20,<wbr/> 80,<wbr/> 80),<wbr/> and the geometric distortion
+correction doesn't change the pixel coordinate,<wbr/> the resulting pixel selected in
+pixel coordinates would be x,<wbr/>y = (25,<wbr/> 25) relative to the top,<wbr/>left of the raw buffer
+with dimensions given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>,<wbr/> and would be (5,<wbr/> 5)
+relative to the top,<wbr/>left of post-processed YUV output buffer with dimensions given in
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>The currently supported fields that correct for geometric distortion are:</p>
+<ol>
+<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>.<wbr/></li>
+</ol>
+<p>If all of the geometric distortion fields are no-ops,<wbr/> this rectangle will be the same
+as the post-distortion-corrected rectangle given in
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of
+the full pixel array,<wbr/> and the size of the full pixel array is given by
+<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>The pre-correction active array may be smaller than the full pixel array,<wbr/> since the
+full array may include black calibration pixels or other inactive regions.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be
+>= <code>(0,<wbr/>0)</code>.<wbr/>
+The <code>(width,<wbr/> height)</code> must be <= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p>
+<p>If omitted by the HAL implementation,<wbr/> the camera framework will assume that this is
+the same as the post-correction active array region given in
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+
+
+ <tr class="entry" id="static_android.sensor.referenceIlluminant1">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">DAYLIGHT</span>
+ <span class="entry_type_enum_value">1</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FLUORESCENT</span>
+ <span class="entry_type_enum_value">2</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TUNGSTEN</span>
+ <span class="entry_type_enum_value">3</span>
+ <span class="entry_type_enum_notes"><p>Incandescent light</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FLASH</span>
+ <span class="entry_type_enum_value">4</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FINE_WEATHER</span>
+ <span class="entry_type_enum_value">9</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CLOUDY_WEATHER</span>
+ <span class="entry_type_enum_value">10</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SHADE</span>
+ <span class="entry_type_enum_value">11</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DAYLIGHT_FLUORESCENT</span>
+ <span class="entry_type_enum_value">12</span>
+ <span class="entry_type_enum_notes"><p>D 5700 - 7100K</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">DAY_WHITE_FLUORESCENT</span>
+ <span class="entry_type_enum_value">13</span>
+ <span class="entry_type_enum_notes"><p>N 4600 - 5400K</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">COOL_WHITE_FLUORESCENT</span>
+ <span class="entry_type_enum_value">14</span>
+ <span class="entry_type_enum_notes"><p>W 3900 - 4500K</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">WHITE_FLUORESCENT</span>
+ <span class="entry_type_enum_value">15</span>
+ <span class="entry_type_enum_notes"><p>WW 3200 - 3700K</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STANDARD_A</span>
+ <span class="entry_type_enum_value">17</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STANDARD_B</span>
+ <span class="entry_type_enum_value">18</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">STANDARD_C</span>
+ <span class="entry_type_enum_value">19</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">D55</span>
+ <span class="entry_type_enum_value">20</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">D65</span>
+ <span class="entry_type_enum_value">21</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">D75</span>
+ <span class="entry_type_enum_value">22</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">D50</span>
+ <span class="entry_type_enum_value">23</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ISO_STUDIO_TUNGSTEN</span>
+ <span class="entry_type_enum_value">24</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The standard reference illuminant used as the scene light source when
+calculating the <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/>
+<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and
+<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> matrices.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The values in this key correspond to the values defined for the
+EXIF LightSource tag.<wbr/> These illuminants are standard light sources
+that are often used calibrating camera devices.<wbr/></p>
+<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/>
+<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and
+<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> will also be present.<wbr/></p>
+<p>Some devices may choose to provide a second set of calibration
+information for improved quality,<wbr/> including
+<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> and its corresponding matrices.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>)
+and corresponding matrices must be present to support the RAW capability
+and DNG output.<wbr/></p>
+<p>When producing raw images with a color profile that has only been
+calibrated against a single light source,<wbr/> it is valid to omit
+<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> along with the
+<a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/> <a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/>
+and <a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p>
+<p>If only <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> is included,<wbr/> it should be
+chosen so that it is representative of typical scene lighting.<wbr/> In
+general,<wbr/> D50 or DAYLIGHT will be chosen for this case.<wbr/></p>
+<p>If both <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> and
+<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> are included,<wbr/> they should be
+chosen to represent the typical range of scene lighting conditions.<wbr/>
+In general,<wbr/> low color temperature illuminant such as Standard-A will
+be chosen for the first reference illuminant and a higher color
+temperature illuminant such as D65 will be chosen for the second
+reference illuminant.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.referenceIlluminant2">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The standard reference illuminant used as the scene light source when
+calculating the <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/>
+<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and
+<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>See <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> for more details.<wbr/></p>
+<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/>
+<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and
+<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> will also be present.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.calibrationTransform1">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A per-device calibration transform matrix that maps from the
+reference sensor colorspace to the actual device sensor colorspace.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to correct for per-device variations in the
+sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p>
+<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
+contains a per-device calibration transform that maps colors
+from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module"
+colorspace) into this camera device's native sensor color
+space under the first reference illuminant
+(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.calibrationTransform2">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A per-device calibration transform matrix that maps from the
+reference sensor colorspace to the actual device sensor colorspace
+(this is the colorspace of the raw buffer data).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to correct for per-device variations in the
+sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p>
+<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
+contains a per-device calibration transform that maps colors
+from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module"
+colorspace) into this camera device's native sensor color
+space under the second reference illuminant
+(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p>
+<p>This matrix will only be present if the second reference
+illuminant is present.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.colorTransform1">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>color<wbr/>Transform1
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A matrix that transforms color values from CIE XYZ color space to
+reference sensor color space.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to convert from the standard CIE XYZ color
+space to the reference sensor colorspace,<wbr/> and is used when processing
+raw buffer data.<wbr/></p>
+<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
+contains a color transform matrix that maps colors from the CIE
+XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the
+"golden module" colorspace) under the first reference illuminant
+(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p>
+<p>The white points chosen in both the reference sensor color space
+and the CIE XYZ colorspace when calculating this transform will
+match the standard white point for the first reference illuminant
+(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.colorTransform2">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>color<wbr/>Transform2
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A matrix that transforms color values from CIE XYZ color space to
+reference sensor color space.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to convert from the standard CIE XYZ color
+space to the reference sensor colorspace,<wbr/> and is used when processing
+raw buffer data.<wbr/></p>
+<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
+contains a color transform matrix that maps colors from the CIE
+XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the
+"golden module" colorspace) under the second reference illuminant
+(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p>
+<p>The white points chosen in both the reference sensor color space
+and the CIE XYZ colorspace when calculating this transform will
+match the standard white point for the second reference illuminant
+(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p>
+<p>This matrix will only be present if the second reference
+illuminant is present.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.forwardMatrix1">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A matrix that transforms white balanced camera colors from the reference
+sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and
+is used when processing raw buffer data.<wbr/></p>
+<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains
+a color transform matrix that maps white balanced colors from the
+reference sensor color space to the CIE XYZ color space with a D50 white
+point.<wbr/></p>
+<p>Under the first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>)
+this matrix is chosen so that the standard white point for this reference
+illuminant in the reference sensor colorspace is mapped to D50 in the
+CIE XYZ colorspace.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.forwardMatrix2">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
+
+
+
+
+ <div class="entry_type_notes">3x3 matrix in row-major-order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A matrix that transforms white balanced camera colors from the reference
+sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and
+is used when processing raw buffer data.<wbr/></p>
+<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains
+a color transform matrix that maps white balanced colors from the
+reference sensor color space to the CIE XYZ color space with a D50 white
+point.<wbr/></p>
+<p>Under the second reference illuminant (<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>)
+this matrix is chosen so that the standard white point for this reference
+illuminant in the reference sensor colorspace is mapped to D50 in the
+CIE XYZ colorspace.<wbr/></p>
+<p>This matrix will only be present if the second reference
+illuminant is present.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.baseGainFactor">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>sensor.<wbr/>base<wbr/>Gain<wbr/>Factor
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Gain factor from electrons to raw units when
+ISO=100</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.blackLevelPattern">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public as blackLevelPattern]</span>
+
+
+
+
+ <div class="entry_type_notes">2x2 raw count block</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A fixed black level offset for each of the color filter arrangement
+(CFA) mosaic channels.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0 for each.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key specifies the zero light value for each of the CFA mosaic
+channels in the camera sensor.<wbr/> The maximal value output by the
+sensor is represented by the value in <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>.<wbr/></p>
+<p>The values are given in the same order as channels listed for the CFA
+layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the
+nth value given corresponds to the black level offset for the nth
+color channel listed in the CFA.<wbr/></p>
+<p>The black level values of captured images may vary for different
+capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key
+represents a coarse approximation for such case.<wbr/> It is recommended to
+use <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> or use pixels from
+<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> directly for captures when
+supported by the camera device,<wbr/> which provides more accurate black
+level values.<wbr/> For raw capture in particular,<wbr/> it is recommended to use
+pixels from <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> to calculate black
+level values for each frame.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The values are given in row-column scan order,<wbr/> with the first value
+corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.maxAnalogSensitivity">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum sensitivity that is implemented
+purely through analog gain.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_FULL">FULL</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> values less than or
+equal to this,<wbr/> all applied gain must be analog.<wbr/> For
+values above this,<wbr/> the gain applied can be a mix of analog and
+digital.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.orientation">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>orientation
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Clockwise angle through which the output image needs to be rotated to be
+upright on the device screen in its native orientation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Degrees of clockwise rotation; always a multiple of
+ 90
+ </td>
+
+ <td class="entry_range">
+ <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Also defines the direction of rolling shutter readout,<wbr/> which is from top to bottom in
+the sensor's coordinate system.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.profileHueSatMapDimensions">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+ <div class="entry_type_notes">Number of samples for hue,<wbr/> saturation,<wbr/> and value</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The number of input samples for each dimension of
+<a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Hue >= 1,<wbr/>
+Saturation >= 2,<wbr/>
+Value >= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The number of input samples for the hue,<wbr/> saturation,<wbr/> and value
+dimension of <a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/> The order of the
+dimensions given is hue,<wbr/> saturation,<wbr/> value; where hue is the 0th
+element.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.availableTestPatternModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of sensor test pattern modes for <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a>
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Defaults to OFF,<wbr/> and always includes OFF if defined.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All custom modes must be >= CUSTOM1.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.opticalBlackRegions">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x num_regions
+ </span>
+ <span class="entry_type_visibility"> [public as rectangle]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of disjoint rectangles indicating the sensor
+optically shielded black pixel regions.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>In most camera sensors,<wbr/> the active array is surrounded by some
+optically shielded pixel areas.<wbr/> By blocking light,<wbr/> these pixels
+provides a reliable black reference for black level compensation
+in active array region.<wbr/></p>
+<p>This key provides a list of disjoint rectangles specifying the
+regions of optically shielded (with metal shield) black pixel
+regions if the camera device is capable of reading out these black
+pixels in the output raw images.<wbr/> In comparison to the fixed black
+level values reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a>,<wbr/> this key
+may provide a more accurate way for the application to calculate
+black level of each captured raw images.<wbr/></p>
+<p>When this key is reported,<wbr/> the <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> and
+<a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> will also be reported.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This array contains (xmin,<wbr/> ymin,<wbr/> width,<wbr/> height).<wbr/> The (xmin,<wbr/> ymin)
+must be >= (0,<wbr/>0) and <=
+<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> The (width,<wbr/> height) must be
+<= <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> Each region must be
+outside the region reported by
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>The HAL must report minimal number of disjoint regions for the
+optically shielded back pixel regions.<wbr/> For example,<wbr/> if a region can
+be covered by one rectangle,<wbr/> the HAL must not split this region into
+multiple rectangles.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.sensor.opaqueRawSize">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>opaque<wbr/>Raw<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 3
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Size in bytes for all the listed opaque RAW buffer sizes</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Must be large enough to fit the opaque RAW of corresponding size produced by
+the camera</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This configurations are listed as <code>(width,<wbr/> height,<wbr/> size_<wbr/>in_<wbr/>bytes)</code> tuples.<wbr/>
+This is used for sizing the gralloc buffers for opaque RAW buffers.<wbr/>
+All RAW_<wbr/>OPAQUE output stream configuration listed in
+<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have a corresponding tuple in
+this key.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key is added in HAL3.<wbr/>4.<wbr/>
+For HAL3.<wbr/>4 or above: devices advertising RAW_<wbr/>OPAQUE format output must list this key.<wbr/>
+For HAL3.<wbr/>3 or earlier devices: if RAW_<wbr/>OPAQUE ouput is advertised,<wbr/> camera framework
+will derive this key by assuming each pixel takes two bytes and no padding bytes
+between rows.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.sensor.exposureTime">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>exposure<wbr/>Time
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Duration each pixel is exposed to
+light.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the
+duration exposed to the nearest possible value (rather than expose longer).<wbr/>
+The final exposure time used will be available in the output capture result.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.frameDuration">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>frame<wbr/>Duration
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Duration from start of frame exposure to
+start of next frame exposure.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/>
+<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration
+is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The maximum frame rate that can be supported by a camera subsystem is
+a function of many factors:</p>
+<ul>
+<li>Requested resolutions of output image streams</li>
+<li>Availability of binning /<wbr/> skipping modes on the imager</li>
+<li>The bandwidth of the imager interface</li>
+<li>The bandwidth of the various ISP processing blocks</li>
+</ul>
+<p>Since these factors can vary greatly between different ISPs and
+sensors,<wbr/> the camera abstraction tries to represent the bandwidth
+restrictions with as simple a model as possible.<wbr/></p>
+<p>The model presented has the following characteristics:</p>
+<ul>
+<li>The image sensor is always configured to output the smallest
+resolution possible given the application's requested output stream
+sizes.<wbr/> The smallest resolution is defined as being at least as large
+as the largest requested output stream size; the camera pipeline must
+never digitally upsample sensor data when the crop region covers the
+whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream
+resolutions are configured,<wbr/> the sensor can provide a higher frame
+rate.<wbr/></li>
+<li>Since any request may use any or all the currently configured
+output streams,<wbr/> the sensor and ISP must be configured to support
+scaling a single capture to all the streams at the same time.<wbr/> This
+means the camera pipeline must be ready to produce the largest
+requested output size without any delay.<wbr/> Therefore,<wbr/> the overall
+frame rate of a given configured stream set is governed only by the
+largest requested stream resolution.<wbr/></li>
+<li>Using more than one output stream in a request does not affect the
+frame duration.<wbr/></li>
+<li>Certain format-streams may need to do additional background processing
+before data is consumed/<wbr/>produced by that stream.<wbr/> These processors
+can run concurrently to the rest of the camera pipeline,<wbr/> but
+cannot process more than 1 capture at a time.<wbr/></li>
+</ul>
+<p>The necessary information for the application,<wbr/> given the model above,<wbr/>
+is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/>
+These are used to determine the maximum frame rate /<wbr/> minimum frame
+duration that is possible for a given stream configuration.<wbr/></p>
+<p>Specifically,<wbr/> the application can use the following rules to
+determine the minimum frame duration it can request from the camera
+device:</p>
+<ol>
+<li>Let the set of currently configured input/<wbr/>output streams
+be called <code>S</code>.<wbr/></li>
+<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking
+it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
+(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be
+called <code>F</code>.<wbr/></li>
+<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed
+for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams
+used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li>
+</ol>
+<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>
+using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code>
+determines the steady state frame rate that the application will get
+if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of
+request be called <code>Rsimple</code>.<wbr/></p>
+<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+by a single capture of a new request <code>Rstall</code> (which has at least
+one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+same minimum frame duration this will not cause a frame rate loss
+if all buffers from the previous <code>Rstall</code> have already been
+delivered.<wbr/></p>
+<p>For more details about stalling,<wbr/> see
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For more details about stalling,<wbr/> see
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.sensitivity">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>sensitivity
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of gain applied to sensor data
+before processing.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ ISO arithmetic units
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The sensitivity is the standard ISO sensitivity value,<wbr/>
+as defined in ISO 12232:2006.<wbr/></p>
+<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and
+if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device
+is guaranteed to use only analog amplification for applying the gain.<wbr/></p>
+<p>If the camera device cannot apply the exact sensitivity
+requested,<wbr/> it will reduce the gain to the nearest supported
+value.<wbr/> The final sensitivity used will be available in the
+output capture result.<wbr/></p>
+<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
+OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>ISO 12232:2006 REI method is acceptable.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.timestamp">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>timestamp
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Time at start of exposure of first
+row of the image sensor active array,<wbr/> in nanoseconds.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>> 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The timestamps are also included in all image
+buffers produced for the same capture,<wbr/> and will be identical
+on all the outputs.<wbr/></p>
+<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> UNKNOWN,<wbr/>
+the timestamps measure time since an unspecified starting point,<wbr/>
+and are monotonically increasing.<wbr/> They can be compared with the
+timestamps for other captures from the same camera device,<wbr/> but are
+not guaranteed to be comparable to any other time source.<wbr/></p>
+<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/> the
+timestamps measure time in the same timebase as <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/> and they can
+be compared to other timestamps from other subsystems that
+are using that base.<wbr/></p>
+<p>For reprocessing,<wbr/> the timestamp will match the start of exposure of
+the input image,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/CaptureResult.html#SENSOR_TIMESTAMP">the
+timestamp</a> in the TotalCaptureResult that was used to create the
+reprocess capture request.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All timestamps must be in reference to the kernel's
+CLOCK_<wbr/>BOOTTIME monotonic clock,<wbr/> which properly accounts for
+time spent asleep.<wbr/> This allows for synchronization with
+sensors that continue to operate while the system is
+otherwise asleep.<wbr/></p>
+<p>If <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/>
+The timestamp must be synchronized with the timestamps from other
+sensor subsystems that are using the same timebase.<wbr/></p>
+<p>For reprocessing,<wbr/> the input image's start of exposure can be looked up
+with <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> from the metadata included in the
+capture request.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.temperature">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>sensor.<wbr/>temperature
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The temperature of the sensor,<wbr/> sampled at the time
+exposure began for this frame.<wbr/></p>
+<p>The thermal diode being queried should be inside the sensor PCB,<wbr/> or
+somewhere close to it.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Celsius
+ </td>
+
+ <td class="entry_range">
+ <p>Optional.<wbr/> This value is missing if no temperature is available.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.neutralColorPoint">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>neutral<wbr/>Color<wbr/>Point
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The estimated camera neutral color in the native sensor colorspace at
+the time of capture.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value gives the neutral color point encoded as an RGB value in the
+native sensor color space.<wbr/> The neutral color point indicates the
+currently estimated white point of the scene illumination.<wbr/> It can be
+used to interpolate between the provided color transforms when
+processing raw sensor data.<wbr/></p>
+<p>The order of the values is R,<wbr/> G,<wbr/> B; where R is in the lowest index.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.noiseProfile">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>noise<wbr/>Profile
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">double</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2 x CFA Channels
+ </span>
+ <span class="entry_type_visibility"> [public as pairDoubleDouble]</span>
+
+
+
+
+ <div class="entry_type_notes">Pairs of noise model coefficients</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Noise model coefficients for each CFA mosaic channel.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key contains two noise model coefficients for each CFA channel
+corresponding to the sensor amplification (S) and sensor readout
+noise (O).<wbr/> These are given as pairs of coefficients for each channel
+in the same order as channels listed for the CFA layout key
+(see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>).<wbr/> This is
+represented as an array of Pair<Double,<wbr/> Double>,<wbr/> where
+the first member of the Pair at index n is the S coefficient and the
+second member is the O coefficient for the nth color channel in the CFA.<wbr/></p>
+<p>These coefficients are used in a two parameter noise model to describe
+the amount of noise present in the image for each CFA channel.<wbr/> The
+noise model used here is:</p>
+<p>N(x) = sqrt(Sx + O)</p>
+<p>Where x represents the recorded signal of a CFA channel normalized to
+the range [0,<wbr/> 1],<wbr/> and S and O are the noise model coeffiecients for
+that channel.<wbr/></p>
+<p>A more detailed description of the noise model can be found in the
+Adobe DNG specification for the NoiseProfile tag.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For a CFA layout of RGGB,<wbr/> the list of coefficients would be given as
+an array of doubles S0,<wbr/>O0,<wbr/>S1,<wbr/>O1,...,<wbr/> where S0 and O0 are the coefficients
+for the red channel,<wbr/> S1 and O1 are the coefficients for the first green
+channel,<wbr/> etc.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.profileHueSatMap">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ hue_samples x saturation_samples x value_samples x 3
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+ <div class="entry_type_notes">Mapping for hue,<wbr/> saturation,<wbr/> and value</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A mapping containing a hue shift,<wbr/> saturation scale,<wbr/> and value scale
+for each pixel.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+
+ The hue shift is given in degrees; saturation and value scale factors are
+ unitless and are between 0 and 1 inclusive
+
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>hue_<wbr/>samples,<wbr/> saturation_<wbr/>samples,<wbr/> and value_<wbr/>samples are given in
+<a href="#static_android.sensor.profileHueSatMapDimensions">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions</a>.<wbr/></p>
+<p>Each entry of this map contains three floats corresponding to the
+hue shift,<wbr/> saturation scale,<wbr/> and value scale,<wbr/> respectively; where the
+hue shift has the lowest index.<wbr/> The map entries are stored in the key
+in nested loop order,<wbr/> with the value divisions in the outer loop,<wbr/> the
+hue divisions in the middle loop,<wbr/> and the saturation divisions in the
+inner loop.<wbr/> All zero input saturation entries are required to have a
+value scale factor of 1.<wbr/>0.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.profileToneCurve">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>sensor.<wbr/>profile<wbr/>Tone<wbr/>Curve
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ samples x 2
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+ <div class="entry_type_notes">Samples defining a spline for a tone-mapping curve</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A list of x,<wbr/>y samples defining a tone-mapping curve for gamma adjustment.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Each sample has an input range of <code>[0,<wbr/> 1]</code> and an output range of
+<code>[0,<wbr/> 1]</code>.<wbr/> The first sample is required to be <code>(0,<wbr/> 0)</code>,<wbr/> and the last
+sample is required to be <code>(1,<wbr/> 1)</code>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This key contains a default tone curve that can be applied while
+processing the image as a starting point for user adjustments.<wbr/>
+The curve is specified as a list of value pairs in linear gamma.<wbr/>
+The curve is interpolated using a cubic spline.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.greenSplit">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>green<wbr/>Split
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The worst-case divergence between Bayer green channels.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value is an estimate of the worst case split between the
+Bayer green channels in the red and blue rows in the sensor color
+filter array.<wbr/></p>
+<p>The green split is calculated as follows:</p>
+<ol>
+<li>A 5x5 pixel (or larger) window W within the active sensor array is
+chosen.<wbr/> The term 'pixel' here is taken to mean a group of 4 Bayer
+mosaic channels (R,<wbr/> Gr,<wbr/> Gb,<wbr/> B).<wbr/> The location and size of the window
+chosen is implementation defined,<wbr/> and should be chosen to provide a
+green split estimate that is both representative of the entire image
+for this camera sensor,<wbr/> and can be calculated quickly.<wbr/></li>
+<li>The arithmetic mean of the green channels from the red
+rows (mean_<wbr/>Gr) within W is computed.<wbr/></li>
+<li>The arithmetic mean of the green channels from the blue
+rows (mean_<wbr/>Gb) within W is computed.<wbr/></li>
+<li>The maximum ratio R of the two means is computed as follows:
+<code>R = max((mean_<wbr/>Gr + 1)/<wbr/>(mean_<wbr/>Gb + 1),<wbr/> (mean_<wbr/>Gb + 1)/<wbr/>(mean_<wbr/>Gr + 1))</code></li>
+</ol>
+<p>The ratio R is the green split divergence reported for this property,<wbr/>
+which represents how much the green channels differ in the mosaic
+pattern.<wbr/> This value is typically used to determine the treatment of
+the green mosaic channels when demosaicing.<wbr/></p>
+<p>The green split value can be roughly interpreted as follows:</p>
+<ul>
+<li>R < 1.<wbr/>03 is a negligible split (<3% divergence).<wbr/></li>
+<li>1.<wbr/>20 <= R >= 1.<wbr/>03 will require some software
+correction to avoid demosaic errors (3-20% divergence).<wbr/></li>
+<li>R > 1.<wbr/>20 will require strong software correction to produce
+a usuable image (>20% divergence).<wbr/></li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The green split given may be a static value based on prior
+characterization of the camera sensor using the green split
+calculation method given here over a large,<wbr/> representative,<wbr/> sample
+set of images.<wbr/> Other methods of calculation that produce equivalent
+results,<wbr/> and can be interpreted in the same manner,<wbr/> may be used.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.testPatternData">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern
+when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/>
+The camera device then uses the most significant X bits
+that correspond to how many bits are in its Bayer raw sensor
+output.<wbr/></p>
+<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the
+10 most significant bits from each color channel.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.testPatternMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera
+device returns captures from the image sensor.<wbr/></p>
+<p>This is the default if the key is not set.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SOLID_COLOR</span>
+ <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its
+respective color channel provided in
+<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p>
+<p>For example:</p>
+<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0]
+</code></pre>
+<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p>
+<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0]
+</code></pre>
+<p>All red pixels are 100% red.<wbr/> Only the odd green pixels
+are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">COLOR_BARS</span>
+ <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p>
+<p>The vertical bars (left-to-right) are as follows:</p>
+<ul>
+<li>100% white</li>
+<li>yellow</li>
+<li>cyan</li>
+<li>green</li>
+<li>magenta</li>
+<li>red</li>
+<li>blue</li>
+<li>black</li>
+</ul>
+<p>In general the image would look like the following:</p>
+<pre><code>W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+W Y C G M R B K
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
+
+(B = Blue,<wbr/> K = Black)
+</code></pre>
+<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/>
+When this is not possible,<wbr/> the bar size should be rounded
+down to the nearest integer and the pattern can repeat
+on the right side.<wbr/></p>
+<p>Each bar's height must always take up the full sensor
+pixel array height.<wbr/></p>
+<p>Each pixel in this test pattern must be set to either
+0% intensity or 100% intensity.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span>
+ <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that
+each bar should start at its specified color at the top,<wbr/>
+and fade to gray at the bottom.<wbr/></p>
+<p>Furthermore each bar is further subdivided into a left and
+right half.<wbr/> The left half should have a smooth gradient,<wbr/>
+and the right half should have a quantized gradient.<wbr/></p>
+<p>In particular,<wbr/> the right half's should consist of blocks of the
+same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p>
+<p>The least significant bits in the quantized gradient should
+be copied from the most significant bits of the smooth gradient.<wbr/></p>
+<p>The height of each bar should always be a multiple of 128.<wbr/>
+When this is not the case,<wbr/> the pattern should repeat at the bottom
+of the image.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PN9</span>
+ <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence
+generated from a PN9 512-bit sequence (typically implemented
+in hardware with a linear feedback shift register).<wbr/></p>
+<p>The generator should be reset at the beginning of each frame,<wbr/>
+and thus each subsequent raw frame with this test pattern should
+be exactly the same as the last.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">CUSTOM1</span>
+ <span class="entry_type_enum_value">256</span>
+ <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are
+available only on this camera device are at least this numeric
+value.<wbr/></p>
+<p>All of the custom test patterns will be static
+(that is the raw image must not vary from frame to frame).<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>When enabled,<wbr/> the sensor sends a test pattern instead of
+doing a real exposure from the camera.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified
+by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should
+work as normal.<wbr/></p>
+<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still
+occur (and that the test pattern remain unmodified,<wbr/> since the flash
+would not actually affect it).<wbr/></p>
+<p>Defaults to OFF.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>All test patterns are specified in the Bayer domain.<wbr/></p>
+<p>The HAL may choose to substitute test patterns from the sensor
+with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be
+indistinguishable to the ISP whether the data came from the
+sensor interconnect bus (such as CSI2) or memory.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.rollingShutterSkew">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>rolling<wbr/>Shutter<wbr/>Skew
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Duration between the start of first row exposure
+and the start of last row exposure.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Nanoseconds
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0 and <
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is the exposure time skew between the first and last
+row exposure start times.<wbr/> The first row and the last row are
+the first and last rows inside of the
+<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+<p>For typical camera sensors that use rolling shutters,<wbr/> this is also equivalent
+to the frame readout time.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The HAL must report <code>0</code> if the sensor is using global shutter,<wbr/> where all pixels begin
+exposure at the same time.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.dynamicBlackLevel">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+ <div class="entry_type_notes">2x2 raw count block</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A per-frame dynamic black level offset for each of the color filter
+arrangement (CFA) mosaic channels.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0 for each.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Camera sensor black levels may vary dramatically for different
+capture settings (e.<wbr/>g.<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> The fixed black
+level reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may be too
+inaccurate to represent the actual value on a per-frame basis.<wbr/> The
+camera device internal pipeline relies on reliable black level values
+to process the raw images appropriately.<wbr/> To get the best image
+quality,<wbr/> the camera device may choose to estimate the per frame black
+level values either based on optically shielded black regions
+(<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>) or its internal model.<wbr/></p>
+<p>This key reports the camera device estimated per-frame zero light
+value for each of the CFA mosaic channels in the camera sensor.<wbr/> The
+<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may only represent a coarse
+approximation of the actual black level values.<wbr/> This value is the
+black level used in camera device internal image processing pipeline
+and generally more accurate than the fixed black level values.<wbr/>
+However,<wbr/> since they are estimated values by the camera device,<wbr/> they
+may not be as accurate as the black level values calculated from the
+optical black pixels reported by <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>.<wbr/></p>
+<p>The values are given in the same order as channels listed for the CFA
+layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the
+nth value given corresponds to the black level offset for the nth
+color channel listed in the CFA.<wbr/></p>
+<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is
+available or the camera device advertises this key via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The values are given in row-column scan order,<wbr/> with the first value
+corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.sensor.dynamicWhiteLevel">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum raw value output by sensor for this frame.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Since the <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may change for different
+capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>),<wbr/> the white
+level will change accordingly.<wbr/> This key is similar to
+<a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>,<wbr/> but specifies the camera device
+estimated white level for each frame.<wbr/></p>
+<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is
+available or the camera device advertises this key via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The full bit depth of the sensor must be available in the raw data,<wbr/>
+so the value for linear sensors should not be significantly lower
+than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_shading" class="section">shading</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.shading.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>shading.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing
+frame rate relative to sensor raw output</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the
+cost of possibly reduced frame rate.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Quality of lens shading correction applied
+to the image data.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the
+camera device,<wbr/> and an identity lens shading map data will be provided
+if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens
+shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/>
+the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity
+map shown below:</p>
+<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
+</code></pre>
+<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera
+device.<wbr/> Applications can request lens shading map data by setting
+<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens
+shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map
+data will be the one applied by the camera device for this capture request.<wbr/></p>
+<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore
+the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and
+AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code>
+OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB
+to be converged before using the returned shading map data.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.shading.strength">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>shading.<wbr/>strength
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Control the amount of shading correction
+applied to the images</p>
+ </td>
+
+ <td class="entry_units">
+ unitless: 1-10; 10 is full shading
+ compensation
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.shading.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>shading.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing
+frame rate relative to sensor raw output</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the
+cost of possibly reduced frame rate.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Quality of lens shading correction applied
+to the image data.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the
+camera device,<wbr/> and an identity lens shading map data will be provided
+if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens
+shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/>
+the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity
+map shown below:</p>
+<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
+</code></pre>
+<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera
+device.<wbr/> Applications can request lens shading map data by setting
+<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens
+shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map
+data will be the one applied by the camera device for this capture request.<wbr/></p>
+<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore
+the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and
+AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code>
+OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB
+to be converged before using the returned shading map data.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.shading.availableModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>shading.<wbr/>available<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums (android.<wbr/>shading.<wbr/>mode).<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of lens shading modes for <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a> that are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This list contains lens shading modes that can be set for the camera device.<wbr/>
+Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always
+list OFF and FAST mode.<wbr/> This includes all FULL level devices.<wbr/>
+LEGACY devices will always only support FAST mode.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if lens shading correction control is
+available on the camera device,<wbr/> but the underlying implementation can be the same for
+both modes.<wbr/> That is,<wbr/> if the highest quality implementation on the camera device does not
+slow down capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_statistics" class="section">statistics</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.statistics.faceDetectMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture
+results.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SIMPLE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FULL</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Return all face
+metadata.<wbr/></p>
+<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for the face detector
+unit.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Whether face detection is enabled,<wbr/> and whether it
+should output just the basic fields or the full set of
+fields.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and
+<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/>
+FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and
+<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.statistics.histogramMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for histogram
+generation</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.statistics.sharpnessMapMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for sharpness map
+generation</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.statistics.hotPixelMapMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for hot pixel map generation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/>
+If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.statistics.lensShadingMapMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will output the lens
+shading map in output result metadata.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to ON,<wbr/>
+<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in
+the output result metadata.<wbr/></p>
+<p>ON is always supported on devices with the RAW capability.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.statistics.info.availableFaceDetectModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">List of enums from android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of face detection modes for <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>OFF is always supported.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.histogramBucketCount">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>histogram<wbr/>Bucket<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Number of histogram buckets
+supported</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>>= 64</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.maxFaceCount">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum number of simultaneously detectable
+faces.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>0 for cameras without available face detection; otherwise:
+<code>>=4</code> for LIMITED or FULL hwlevel devices or
+<code>>0</code> for LEGACY devices.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.maxHistogramCount">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Histogram<wbr/>Count
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum value possible for a histogram
+bucket</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.maxSharpnessMapValue">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Sharpness<wbr/>Map<wbr/>Value
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum value possible for a sharpness map
+region.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.sharpnessMapSize">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>sharpness<wbr/>Map<wbr/>Size
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2
+ </span>
+ <span class="entry_type_visibility"> [system as size]</span>
+
+
+
+
+ <div class="entry_type_notes">width x height</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Dimensions of the sharpness
+map</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Must be at least 32 x 32</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.availableHotPixelMapModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of hot pixel map output modes for <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a> that are
+supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If no hotpixel map output is available for this camera device,<wbr/> this will contain only
+<code>false</code>.<wbr/></p>
+<p>ON is always supported on devices with the RAW capability.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.statistics.info.availableLensShadingMapModes">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of lens shading map output modes for <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> that
+are supported by this camera device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If no lens shading map output is available for this camera device,<wbr/> this key will
+contain only OFF.<wbr/></p>
+<p>ON is always supported on devices with the RAW capability.<wbr/>
+LEGACY mode devices will always only support OFF.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.statistics.faceDetectMode">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture
+results.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">SIMPLE</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FULL</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Return all face
+metadata.<wbr/></p>
+<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for the face detector
+unit.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Whether face detection is enabled,<wbr/> and whether it
+should output just the basic fields or the full set of
+fields.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and
+<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/>
+FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and
+<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.faceIds">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Ids
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of unique IDs for detected faces.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Each detected face is given a unique ID that is valid for as long as the face is visible
+to the camera device.<wbr/> A face that leaves the field of view and later returns may be
+assigned a new ID.<wbr/></p>
+<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.faceLandmarks">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 6
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">(leftEyeX,<wbr/> leftEyeY,<wbr/> rightEyeX,<wbr/> rightEyeY,<wbr/> mouthX,<wbr/> mouthY)</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of landmarks for detected
+faces.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with
+<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p>
+<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.faceRectangles">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 4
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as rectangle]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+ <div class="entry_type_notes">(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax).<wbr/> (0,<wbr/>0) is top-left of active pixel area</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of the bounding rectangles for detected
+faces.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with
+<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p>
+<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.faceScores">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>statistics.<wbr/>face<wbr/>Scores
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of the face confidence scores for
+detected faces</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>1-100</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_BC">BC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The value should be meaningful (for example,<wbr/> setting 100 at
+all times is illegal).<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.faces">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>faces
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [java_public as face]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of the faces detected through camera face detection
+in this capture.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> <code>!=</code> OFF.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.histogram">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>histogram
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 3
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+ <div class="entry_type_notes">count of pixels for each color channel that fall into each histogram bucket,<wbr/> scaled to be between 0 and maxHistogramCount</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A 3-channel histogram based on the raw
+sensor data</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The k'th bucket (0-based) covers the input range
+(with w = <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>) of [ k * w/<wbr/>N,<wbr/>
+(k + 1) * w /<wbr/> N ).<wbr/> If only a monochrome sharpness map is
+supported,<wbr/> all channels should have the same data</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.histogramMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for histogram
+generation</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.sharpnessMap">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x m x 3
+ </span>
+ <span class="entry_type_visibility"> [system]</span>
+
+
+
+
+ <div class="entry_type_notes">estimated sharpness for each region of the input image.<wbr/> Normalized to be between 0 and maxSharpnessMapValue.<wbr/> Higher values mean sharper (better focused)</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A 3-channel sharpness map,<wbr/> based on the raw
+sensor data</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If only a monochrome sharpness map is supported,<wbr/>
+all channels should have the same data</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.sharpnessMapMode">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [system as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for sharpness map
+generation</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_FUTURE">FUTURE</a></li>
+ </ul>
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.lensShadingCorrectionMap">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+
+ <span class="entry_type_visibility"> [java_public as lensShadingMap]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The shading map is a low-resolution floating-point map
+that lists the coefficients used to correct for vignetting,<wbr/> for each
+Bayer color channel.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Each gain factor is >= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The map provided here is the same map that is used by the camera device to
+correct both color shading and vignetting for output non-RAW images.<wbr/></p>
+<p>When there is no lens shading correction applied to RAW
+output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code>
+false),<wbr/> this map is the complete lens shading correction
+map; when there is some lens shading correction applied to
+the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading
+correction map that needs to be applied to get shading
+corrected images that match the camera device's output for
+non-RAW formats.<wbr/></p>
+<p>For a complete shading correction map,<wbr/> the least shaded
+section of the image will have a gain factor of 1; all
+other sections will have gains above 1.<wbr/></p>
+<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map
+will take into account the colorCorrection settings.<wbr/></p>
+<p>The shading map is for the entire active pixel array,<wbr/> and is not
+affected by the crop region specified in the request.<wbr/> Each shading map
+entry is the value of the shading compensation map over a specific
+pixel on the sensor.<wbr/> Specifically,<wbr/> with a (N x M) resolution shading
+map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry
+(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at
+pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/>
+The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p>
+<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green
+channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/>
+The shading map is stored in a fully interleaved format.<wbr/></p>
+<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/>
+and will be smaller than 64x64.<wbr/></p>
+<p>As an example,<wbr/> given a very small map defined as:</p>
+<pre><code>width,<wbr/>height = [ 4,<wbr/> 3 ]
+values =
+[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/>
+ 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ]
+</code></pre>
+<p>The low-resolution scaling map images for each channel are
+(displayed using nearest-neighbor interpolation):</p>
+<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/>
+<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/>
+<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/>
+<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p>
+<p>As a visualization only,<wbr/> inverting the full-color map to recover an
+image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
+<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.lensShadingMap">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x n x m
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">2D array of float gain factors per channel to correct lens shading</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The shading map is a low-resolution floating-point map
+that lists the coefficients used to correct for vignetting and color shading,<wbr/>
+for each Bayer color channel of RAW image data.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Each gain factor is >= 1</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The map provided here is the same map that is used by the camera device to
+correct both color shading and vignetting for output non-RAW images.<wbr/></p>
+<p>When there is no lens shading correction applied to RAW
+output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code>
+false),<wbr/> this map is the complete lens shading correction
+map; when there is some lens shading correction applied to
+the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading
+correction map that needs to be applied to get shading
+corrected images that match the camera device's output for
+non-RAW formats.<wbr/></p>
+<p>For a complete shading correction map,<wbr/> the least shaded
+section of the image will have a gain factor of 1; all
+other sections will have gains above 1.<wbr/></p>
+<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map
+will take into account the colorCorrection settings.<wbr/></p>
+<p>The shading map is for the entire active pixel array,<wbr/> and is not
+affected by the crop region specified in the request.<wbr/> Each shading map
+entry is the value of the shading compensation map over a specific
+pixel on the sensor.<wbr/> Specifically,<wbr/> with a (N x M) resolution shading
+map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry
+(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at
+pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/>
+The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p>
+<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green
+channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/>
+The shading map is stored in a fully interleaved format,<wbr/> and its size
+is provided in the camera static metadata by <a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a>.<wbr/></p>
+<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/>
+and will be smaller than 64x64.<wbr/></p>
+<p>As an example,<wbr/> given a very small map defined as:</p>
+<pre><code><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a> = [ 4,<wbr/> 3 ]
+<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> =
+[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/>
+ 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/>
+ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/>
+ 1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ]
+</code></pre>
+<p>The low-resolution scaling map images for each channel are
+(displayed using nearest-neighbor interpolation):</p>
+<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/>
+<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/>
+<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/>
+<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p>
+<p>As a visualization only,<wbr/> inverting the full-color map to recover an
+image of a gray wall (using bicubic interpolation for visual quality)
+as captured by the sensor gives:</p>
+<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p>
+<p>Note that the RAW image data might be subject to lens shading
+correction not reported on this map.<wbr/> Query
+<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> to see if RAW image data has subject
+to lens shading correction.<wbr/> If <a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a>
+is TRUE,<wbr/> the RAW image data is subject to partial or full lens shading
+correction.<wbr/> In the case full lens shading correction is applied to RAW
+images,<wbr/> the gain factor map reported in this key will contain all 1.<wbr/>0 gains.<wbr/>
+In other words,<wbr/> the map reported in this key is the remaining lens shading
+that needs to be applied on the RAW image to get images without lens shading
+artifacts.<wbr/> See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image
+formats.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The lens shading map calculation may depend on exposure and white balance statistics.<wbr/>
+When AE and AWB are in AUTO modes
+(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code> OFF),<wbr/> the HAL
+may have all the information it need to generate most accurate lens shading map.<wbr/> When
+AE or AWB are in manual mode
+(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> OFF or <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>==</code> OFF),<wbr/> the shading map
+may be adversely impacted by manual exposure or white balance parameters.<wbr/> To avoid
+generating unreliable shading map data,<wbr/> the HAL may choose to lock the shading map with
+the latest known good map generated when the AE and AWB are in AUTO modes.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.predictedColorGains">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Gains
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4
+ </span>
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+ <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The best-fit color channel gains calculated
+by the camera device's statistics units for the current output frame.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This may be different than the gains used for this frame,<wbr/>
+since statistics processing on data from a new frame
+typically completes after the transform has already been
+applied to that frame.<wbr/></p>
+<p>The 4 channel gains are defined in Bayer domain,<wbr/>
+see <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> for details.<wbr/></p>
+<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/>
+regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.predictedColorTransform">
+ <td class="entry_name
+ entry_name_deprecated
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Transform
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">rational</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 3 x 3
+ </span>
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+ <span class="entry_type_deprecated">[deprecated] </span>
+
+ <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The best-fit color transform matrix estimate
+calculated by the camera device's statistics units for the current
+output frame.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The camera device will provide the estimate from its
+statistics unit on the white balance transforms to use
+for the next frame.<wbr/> These are the values the camera device believes
+are the best fit for the current output frame.<wbr/> This may
+be different than the transform used for this frame,<wbr/> since
+statistics processing on data from a new frame typically
+completes after the transform has already been applied to
+that frame.<wbr/></p>
+<p>These estimates must be provided for all frames,<wbr/> even if
+capture settings and color transforms are set by the application.<wbr/></p>
+<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/>
+regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.sceneFlicker">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">NONE</span>
+ <span class="entry_type_enum_notes"><p>The camera device does not detect any flickering illumination
+in the current scene.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">50HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 50Hz
+in the current scene.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">60HZ</span>
+ <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 60Hz
+in the current scene.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The camera device estimated scene illumination lighting
+frequency.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Many light sources,<wbr/> such as most fluorescent lights,<wbr/> flicker at a rate
+that depends on the local utility power standards.<wbr/> This flicker must be
+accounted for by auto-exposure routines to avoid artifacts in captured images.<wbr/>
+The camera device uses this entry to tell the application what the scene
+illuminant frequency is.<wbr/></p>
+<p>When manual exposure control is enabled
+(<code><a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> == OFF</code> or <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> ==
+OFF</code>),<wbr/> the <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> doesn't perform
+antibanding,<wbr/> and the application can ensure it selects
+exposure times that do not cause banding issues by looking
+into this metadata field.<wbr/> See
+<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> for more details.<wbr/></p>
+<p>Reports NONE if there doesn't appear to be flickering illumination.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.hotPixelMapMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Operating mode for hot pixel map generation.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/>
+If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.hotPixelMap">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 2 x n
+ </span>
+ <span class="entry_type_visibility"> [public as point]</span>
+
+
+
+
+ <div class="entry_type_notes">list of coordinates based on android.<wbr/>sensor.<wbr/>pixel<wbr/>Array<wbr/>Size</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of <code>(x,<wbr/> y)</code> coordinates of hot/<wbr/>defective pixels on the sensor.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>n <= number of pixels on the sensor.<wbr/>
+The <code>(x,<wbr/> y)</code> coordinates must be bounded by
+<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A coordinate <code>(x,<wbr/> y)</code> must lie between <code>(0,<wbr/> 0)</code>,<wbr/> and
+<code>(width - 1,<wbr/> height - 1)</code> (inclusive),<wbr/> which are the top-left and
+bottom-right of the pixel array,<wbr/> respectively.<wbr/> The width and
+height dimensions are given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/>
+This may include hot pixels that lie outside of the active array
+bounds given by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A hotpixel map contains the coordinates of pixels on the camera
+sensor that do report valid values (usually due to defects in
+the camera sensor).<wbr/> This includes pixels that are stuck at certain
+values,<wbr/> or have a response that does not accuractly encode the
+incoming light from the scene.<wbr/></p>
+<p>To avoid performance issues,<wbr/> there should be significantly fewer hot
+pixels than actual pixels on the camera sensor.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.lensShadingMapMode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether the camera device will output the lens
+shading map in output result metadata.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_RAW">RAW</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to ON,<wbr/>
+<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in
+the output result metadata.<wbr/></p>
+<p>ON is always supported on devices with the RAW capability.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_tonemap" class="section">tonemap</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.tonemap.curveBlue">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.curveGreen">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Green
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.curveRed">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Red
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>0-1 on both input and output coordinates,<wbr/> normalized
+as a floating-point value such that 0 == black and 1 == white.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Each channel's curve is defined by an array of control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> =
+ [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ]
+2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
+<p>These are sorted in order of increasing <code>Pin</code>; it is
+required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
+define a complete mapping.<wbr/> For input values between control points,<wbr/>
+the camera device must linearly interpolate between the control
+points.<wbr/></p>
+<p>Each curve can have an independent number of points,<wbr/> and the number
+of points can be less than max (that is,<wbr/> the request doesn't have to
+always provide a curve with number of points equivalent to
+<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
+<p>A few examples,<wbr/> and their corresponding graphical mappings; these
+only specify the red channel and the precision is limited to 4
+digits,<wbr/> for conciseness.<wbr/></p>
+<p>Linear mapping:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
+</code></pre>
+<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
+<p>Invert mapping:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ]
+</code></pre>
+<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
+<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
+ 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/>
+ 0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/>
+ 0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/>
+ 0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
+</code></pre>
+<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
+<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
+ 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/>
+ 0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/>
+ 0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/>
+ 0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
+</code></pre>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For good quality of mapping,<wbr/> at least 128 control points are
+preferred.<wbr/></p>
+<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many
+control points used as are available.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.curve">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>curve
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [java_public as tonemapCurve]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a>
+is CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue
+channels respectively.<wbr/> The following example uses the red channel as an
+example.<wbr/> The same logic applies to green and blue channel.<wbr/>
+Each channel's curve is defined by an array of control points:</p>
+<pre><code>curveRed =
+ [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ]
+2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
+<p>These are sorted in order of increasing <code>Pin</code>; it is always
+guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
+define a complete mapping.<wbr/> For input values between control points,<wbr/>
+the camera device must linearly interpolate between the control
+points.<wbr/></p>
+<p>Each curve can have an independent number of points,<wbr/> and the number
+of points can be less than max (that is,<wbr/> the request doesn't have to
+always provide a curve with number of points equivalent to
+<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
+<p>A few examples,<wbr/> and their corresponding graphical mappings; these
+only specify the red channel and the precision is limited to 4
+digits,<wbr/> for conciseness.<wbr/></p>
+<p>Linear mapping:</p>
+<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ]
+</code></pre>
+<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
+<p>Invert mapping:</p>
+<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ]
+</code></pre>
+<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
+<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
+<pre><code>curveRed = [
+ (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/>
+ (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/>
+ (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/>
+ (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
+</code></pre>
+<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
+<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
+<pre><code>curveRed = [
+ (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/>
+ (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/>
+ (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/>
+ (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
+</code></pre>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and
+curveBlue entries.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CONTRAST_CURVE</span>
+ <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in
+the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by
+<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw
+sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without
+reducing frame rate compared to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at
+the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">GAMMA_VALUE</span>
+ <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform
+tonemapping.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PRESET_CURVE</span>
+ <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in
+<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by
+<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When switching to an application-defined contrast curve by setting
+<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined
+per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the
+mapping from input high-bit-depth pixel value to the output
+low-bit-depth value.<wbr/> Since the actual pixel ranges of both input
+and output may change depending on the camera pipeline,<wbr/> the values
+are specified by normalized floating-point numbers.<wbr/></p>
+<p>More-complex color mapping operations such as 3D color look-up
+tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color
+transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will
+emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/>
+These values are always available,<wbr/> and as close as possible to the
+actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p>
+<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's
+provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be
+roughly the same.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.gamma">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>gamma
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+GAMMA_<wbr/>VALUE</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemap curve will be defined the following formula:
+* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma)
+where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/>
+pow is the power function and gamma is the gamma value specified by this
+key.<wbr/></p>
+<p>The same curve will be applied to all color channels.<wbr/> The camera device
+may clip the input gamma value to its supported range.<wbr/> The actual applied
+value will be returned in capture result.<wbr/></p>
+<p>The valid range of gamma value varies on different devices,<wbr/> but values
+within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="controls_android.tonemap.presetCurve">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">SRGB</span>
+ <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">REC709</span>
+ <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+PRESET_<wbr/>CURVE</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemap curve will be defined by specified standard.<wbr/></p>
+<p>sRGB (approximated by 16 control points):</p>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+<p>Rec.<wbr/> 709 (approximated by 16 control points):</p>
+<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p>
+<p>Note that above figures show a 16 control points approximation of preset
+curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.tonemap.maxCurvePoints">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum number of supported points in the
+tonemap curve that can be used for <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If the actual number of points provided by the application (in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>*) is
+less than this maximum,<wbr/> the camera device will resample the curve to its internal
+representation,<wbr/> using linear interpolation.<wbr/></p>
+<p>The output curves in the result metadata may have a different number
+of points than the input curves,<wbr/> and will represent the actual
+hardware curves used as closely as possible when linearly interpolated.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This value must be at least 64.<wbr/> This should be at least 128.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.tonemap.availableToneMapModes">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [public as enumList]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">list of enums</div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>List of tonemapping modes for <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> that are supported by this camera
+device.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Any value listed in <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always contain
+at least one of below mode combinations:</p>
+<ul>
+<li>CONTRAST_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li>
+<li>GAMMA_<wbr/>VALUE,<wbr/> PRESET_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li>
+</ul>
+<p>This includes all FULL level devices.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if automatic tonemap control is available
+on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
+That is,<wbr/> if the highest quality implementation on the camera device does not slow down
+capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.tonemap.curveBlue">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.curveGreen">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Green
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.curveRed">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>curve<wbr/>Red
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 2
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+ <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red
+channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>0-1 on both input and output coordinates,<wbr/> normalized
+as a floating-point value such that 0 == black and 1 == white.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Each channel's curve is defined by an array of control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> =
+ [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ]
+2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
+<p>These are sorted in order of increasing <code>Pin</code>; it is
+required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
+define a complete mapping.<wbr/> For input values between control points,<wbr/>
+the camera device must linearly interpolate between the control
+points.<wbr/></p>
+<p>Each curve can have an independent number of points,<wbr/> and the number
+of points can be less than max (that is,<wbr/> the request doesn't have to
+always provide a curve with number of points equivalent to
+<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
+<p>A few examples,<wbr/> and their corresponding graphical mappings; these
+only specify the red channel and the precision is limited to 4
+digits,<wbr/> for conciseness.<wbr/></p>
+<p>Linear mapping:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
+</code></pre>
+<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
+<p>Invert mapping:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ]
+</code></pre>
+<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
+<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
+ 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/>
+ 0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/>
+ 0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/>
+ 0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
+</code></pre>
+<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
+<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
+<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
+ 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/>
+ 0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/>
+ 0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/>
+ 0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
+</code></pre>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For good quality of mapping,<wbr/> at least 128 control points are
+preferred.<wbr/></p>
+<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many
+control points used as are available.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.curve">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>tonemap.<wbr/>curve
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [java_public as tonemapCurve]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a>
+is CONTRAST_<wbr/>CURVE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue
+channels respectively.<wbr/> The following example uses the red channel as an
+example.<wbr/> The same logic applies to green and blue channel.<wbr/>
+Each channel's curve is defined by an array of control points:</p>
+<pre><code>curveRed =
+ [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ]
+2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
+<p>These are sorted in order of increasing <code>Pin</code>; it is always
+guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
+define a complete mapping.<wbr/> For input values between control points,<wbr/>
+the camera device must linearly interpolate between the control
+points.<wbr/></p>
+<p>Each curve can have an independent number of points,<wbr/> and the number
+of points can be less than max (that is,<wbr/> the request doesn't have to
+always provide a curve with number of points equivalent to
+<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
+<p>A few examples,<wbr/> and their corresponding graphical mappings; these
+only specify the red channel and the precision is limited to 4
+digits,<wbr/> for conciseness.<wbr/></p>
+<p>Linear mapping:</p>
+<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ]
+</code></pre>
+<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
+<p>Invert mapping:</p>
+<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ]
+</code></pre>
+<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
+<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
+<pre><code>curveRed = [
+ (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/>
+ (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/>
+ (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/>
+ (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
+</code></pre>
+<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
+<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
+<pre><code>curveRed = [
+ (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/>
+ (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/>
+ (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/>
+ (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
+</code></pre>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and
+curveBlue entries.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.mode">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>mode
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CONTRAST_CURVE</span>
+ <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in
+the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by
+<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw
+sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FAST</span>
+ <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without
+reducing frame rate compared to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">HIGH_QUALITY</span>
+ <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at
+the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">GAMMA_VALUE</span>
+ <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform
+tonemapping.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">PRESET_CURVE</span>
+ <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in
+<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p>
+<p>All color enhancement and tonemapping must be disabled,<wbr/> except
+for applying the tonemapping curve specified by
+<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p>
+<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When switching to an application-defined contrast curve by setting
+<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined
+per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the
+mapping from input high-bit-depth pixel value to the output
+low-bit-depth value.<wbr/> Since the actual pixel ranges of both input
+and output may change depending on the camera pipeline,<wbr/> the values
+are specified by normalized floating-point numbers.<wbr/></p>
+<p>More-complex color mapping operations such as 3D color look-up
+tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color
+transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+CONTRAST_<wbr/>CURVE.<wbr/></p>
+<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will
+emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/>
+These values are always available,<wbr/> and as close as possible to the
+actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p>
+<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's
+provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be
+roughly the same.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.gamma">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>gamma
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+GAMMA_<wbr/>VALUE</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemap curve will be defined the following formula:
+* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma)
+where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/>
+pow is the power function and gamma is the gamma value specified by this
+key.<wbr/></p>
+<p>The same curve will be applied to all color channels.<wbr/> The camera device
+may clip the input gamma value to its supported range.<wbr/> The actual applied
+value will be returned in capture result.<wbr/></p>
+<p>The valid range of gamma value varies on different devices,<wbr/> but values
+within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.tonemap.presetCurve">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">SRGB</span>
+ <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">REC709</span>
+ <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
+PRESET_<wbr/>CURVE</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The tonemap curve will be defined by specified standard.<wbr/></p>
+<p>sRGB (approximated by 16 control points):</p>
+<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
+<p>Rec.<wbr/> 709 (approximated by 16 control points):</p>
+<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p>
+<p>Note that above figures show a 16 control points approximation of preset
+curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_led" class="section">led</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.led.transmit">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>led.<wbr/>transmit
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [hidden as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This LED is nominally used to indicate to the user
+that the camera is powered on and may be streaming images back to the
+Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may
+disable this when video is processed locally and not transmitted to
+any untrusted applications.<wbr/></p>
+<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be
+transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever
+data is stored locally on the device.<wbr/></p>
+<p>The LED <em>may</em> be off if a trusted application is using the data that
+doesn't violate the above rules.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.led.transmit">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>led.<wbr/>transmit
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [hidden as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This LED is nominally used to indicate to the user
+that the camera is powered on and may be streaming images back to the
+Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may
+disable this when video is processed locally and not transmitted to
+any untrusted applications.<wbr/></p>
+<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be
+transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever
+data is stored locally on the device.<wbr/></p>
+<p>The LED <em>may</em> be off if a trusted application is using the data that
+doesn't violate the above rules.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.led.availableLeds">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>led.<wbr/>available<wbr/>Leds
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n
+ </span>
+ <span class="entry_type_visibility"> [hidden]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">TRANSMIT</span>
+ <span class="entry_type_enum_notes"><p><a href="#controls_android.led.transmit">android.<wbr/>led.<wbr/>transmit</a> control is used.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>A list of camera LEDs that are available on this system.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_info" class="section">info</td></tr>
+
+
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.info.supportedHardwareLevel">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">LIMITED</span>
+ <span class="entry_type_enum_notes"><p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
+better.<wbr/></p>
+<p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p>
+<p>All <code>LIMITED</code> devices support the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability,<wbr/> indicating basic
+support for color image capture.<wbr/> The only exception is that the device may
+alternatively support only the <code>DEPTH_<wbr/>OUTPUT</code> capability,<wbr/> if it can only output depth
+measurements and not color images.<wbr/></p>
+<p><code>LIMITED</code> devices and above require the use of <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
+to lock exposure metering (and calculate flash power,<wbr/> for cameras with flash) before
+capturing a high-quality still image.<wbr/></p>
+<p>A <code>LIMITED</code> device that only lists the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability is only
+required to support full-automatic operation and post-processing (<code>OFF</code> is not
+supported for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/> or
+<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>)</p>
+<p>Additional capabilities may optionally be supported by a <code>LIMITED</code>-level device,<wbr/> and
+can be checked for in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">FULL</span>
+ <span class="entry_type_enum_notes"><p>This camera device is capable of supporting advanced imaging applications.<wbr/></p>
+<p>The stream configurations listed in the <code>FULL</code>,<wbr/> <code>LEGACY</code> and <code>LIMITED</code> tables in the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p>
+<p>A <code>FULL</code> device will support below capabilities:</p>
+<ul>
+<li><code>BURST_<wbr/>CAPTURE</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
+ <code>BURST_<wbr/>CAPTURE</code>)</li>
+<li>Per frame control (<a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> <code>==</code> PER_<wbr/>FRAME_<wbr/>CONTROL)</li>
+<li>Manual sensor control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains <code>MANUAL_<wbr/>SENSOR</code>)</li>
+<li>Manual post-processing control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
+ <code>MANUAL_<wbr/>POST_<wbr/>PROCESSING</code>)</li>
+<li>The required exposure time range defined in <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li>
+<li>The required maxFrameDuration defined in <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li>
+</ul>
+<p>Note:
+Pre-API level 23,<wbr/> FULL devices also supported arbitrary cropping region
+(<a href="#static_android.scaler.croppingType">android.<wbr/>scaler.<wbr/>cropping<wbr/>Type</a> <code>== FREEFORM</code>); this requirement was relaxed in API level
+23,<wbr/> and <code>FULL</code> devices may only support <code>CENTERED</code> cropping.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">LEGACY</span>
+ <span class="entry_type_enum_notes"><p>This camera device is running in backward compatibility mode.<wbr/></p>
+<p>Only the stream configurations listed in the <code>LEGACY</code> table in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a>
+documentation are supported.<wbr/></p>
+<p>A <code>LEGACY</code> device does not support per-frame control,<wbr/> manual sensor control,<wbr/> manual
+post-processing,<wbr/> arbitrary cropping regions,<wbr/> and has relaxed performance constraints.<wbr/>
+No additional capabilities beyond <code>BACKWARD_<wbr/>COMPATIBLE</code> will ever be listed by a
+<code>LEGACY</code> device in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
+<p>In addition,<wbr/> the <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is not functional on <code>LEGACY</code>
+devices.<wbr/> Instead,<wbr/> every request that includes a JPEG-format output target is treated
+as triggering a still capture,<wbr/> internally executing a precapture trigger.<wbr/> This may
+fire the flash for flash power metering during precapture,<wbr/> and then fire the flash
+for the final capture,<wbr/> if a flash is available on the device and the AE mode is set to
+enable the flash.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">3</span>
+ <span class="entry_type_enum_notes"><p>This camera device is capable of YUV reprocessing and RAW data capture,<wbr/> in addition to
+FULL-level capabilities.<wbr/></p>
+<p>The stream configurations listed in the <code>LEVEL_<wbr/>3</code>,<wbr/> <code>RAW</code>,<wbr/> <code>FULL</code>,<wbr/> <code>LEGACY</code> and
+<code>LIMITED</code> tables in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a>
+documentation are guaranteed to be supported.<wbr/></p>
+<p>The following additional capabilities are guaranteed to be supported:</p>
+<ul>
+<li><code>YUV_<wbr/>REPROCESSING</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
+ <code>YUV_<wbr/>REPROCESSING</code>)</li>
+<li><code>RAW</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
+ <code>RAW</code>)</li>
+</ul></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Generally classifies the overall set of the camera device functionality.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The supported hardware level is a high-level description of the camera device's
+capabilities,<wbr/> summarizing several capabilities into one field.<wbr/> Each level adds additional
+features to the previous one,<wbr/> and is always a strict superset of the previous level.<wbr/>
+The ordering is <code>LEGACY < LIMITED < FULL < LEVEL_<wbr/>3</code>.<wbr/></p>
+<p>Starting from <code>LEVEL_<wbr/>3</code>,<wbr/> the level enumerations are guaranteed to be in increasing
+numerical value as well.<wbr/> To check if a given device is at least at a given hardware level,<wbr/>
+the following code snippet can be used:</p>
+<pre><code>//<wbr/> Returns true if the device supports the required hardware level,<wbr/> or better.<wbr/>
+boolean isHardwareLevelSupported(CameraCharacteristics c,<wbr/> int requiredLevel) {
+ int deviceLevel = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL);
+ if (deviceLevel == Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL_<wbr/>LEGACY) {
+ return requiredLevel == deviceLevel;
+ }
+ //<wbr/> deviceLevel is not LEGACY,<wbr/> can use numerical sort
+ return requiredLevel <= deviceLevel;
+}
+</code></pre>
+<p>At a high level,<wbr/> the levels are:</p>
+<ul>
+<li><code>LEGACY</code> devices operate in a backwards-compatibility mode for older
+ Android devices,<wbr/> and have very limited capabilities.<wbr/></li>
+<li><code>LIMITED</code> devices represent the
+ baseline feature set,<wbr/> and may also include additional capabilities that are
+ subsets of <code>FULL</code>.<wbr/></li>
+<li><code>FULL</code> devices additionally support per-frame manual control of sensor,<wbr/> flash,<wbr/> lens and
+ post-processing settings,<wbr/> and image capture at a high rate.<wbr/></li>
+<li><code>LEVEL_<wbr/>3</code> devices additionally support YUV reprocessing and RAW image capture,<wbr/> along
+ with additional output stream configurations.<wbr/></li>
+</ul>
+<p>See the individual level enums for full descriptions of the supported capabilities.<wbr/> The
+<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> entry describes the device's capabilities at a
+finer-grain level,<wbr/> if needed.<wbr/> In addition,<wbr/> many controls have their available settings or
+ranges defined in individual <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> entries.<wbr/></p>
+<p>Some features are not part of any particular hardware level or capability and must be
+queried separately.<wbr/> These include:</p>
+<ul>
+<li>Calibrated timestamps (<a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME)</li>
+<li>Precision lens control (<a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> <code>==</code> CALIBRATED)</li>
+<li>Face detection (<a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a>)</li>
+<li>Optical or electrical image stabilization
+ (<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a>,<wbr/>
+ <a href="#static_android.control.availableVideoStabilizationModes">android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes</a>)</li>
+</ul>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The camera 3 HAL device can implement one of three possible operational modes; LIMITED,<wbr/>
+FULL,<wbr/> and LEVEL_<wbr/>3.<wbr/></p>
+<p>FULL support or better is expected from new higher-end devices.<wbr/> Limited
+mode has hardware requirements roughly in line with those for a camera HAL device v1
+implementation,<wbr/> and is expected from older or inexpensive devices.<wbr/> Each level is a strict
+superset of the previous level,<wbr/> and they share the same essential operational flow.<wbr/></p>
+<p>For full details refer to "S3.<wbr/> Operational Modes" in camera3.<wbr/>h</p>
+<p>Camera HAL3+ must not implement LEGACY mode.<wbr/> It is there for backwards compatibility in
+the <code>android.<wbr/>hardware.<wbr/>camera2</code> user-facing API only on HALv1 devices,<wbr/> and is implemented
+by the camera framework code.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_blackLevel" class="section">blackLevel</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.blackLevel.lock">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>black<wbr/>Level.<wbr/>lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether black-level compensation is locked
+to its current values,<wbr/> or is free to vary.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When set to <code>true</code> (ON),<wbr/> the values used for black-level
+compensation will not change until the lock is set to
+<code>false</code> (OFF).<wbr/></p>
+<p>Since changes to certain capture parameters (such as
+exposure time) may require resetting of black level
+compensation,<wbr/> the camera device must report whether setting
+the black level lock was successful in the output result
+metadata.<wbr/></p>
+<p>For example,<wbr/> if a sequence of requests is as follows:</p>
+<ul>
+<li>Request 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li>
+<li>Request 2: Exposure = 10ms,<wbr/> Black level lock = ON</li>
+<li>Request 3: Exposure = 10ms,<wbr/> Black level lock = ON</li>
+<li>Request 4: Exposure = 20ms,<wbr/> Black level lock = ON</li>
+<li>Request 5: Exposure = 20ms,<wbr/> Black level lock = ON</li>
+<li>Request 6: Exposure = 20ms,<wbr/> Black level lock = ON</li>
+</ul>
+<p>And the exposure change in Request 4 requires the camera
+device to reset the black level offsets,<wbr/> then the output
+result metadata is expected to be:</p>
+<ul>
+<li>Result 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li>
+<li>Result 2: Exposure = 10ms,<wbr/> Black level lock = ON</li>
+<li>Result 3: Exposure = 10ms,<wbr/> Black level lock = ON</li>
+<li>Result 4: Exposure = 20ms,<wbr/> Black level lock = OFF</li>
+<li>Result 5: Exposure = 20ms,<wbr/> Black level lock = ON</li>
+<li>Result 6: Exposure = 20ms,<wbr/> Black level lock = ON</li>
+</ul>
+<p>This indicates to the application that on frame 4,<wbr/> black
+levels were reset due to exposure value changes,<wbr/> and pixel
+values may not be consistent across captures.<wbr/></p>
+<p>The camera device will maintain the lock to the extent
+possible,<wbr/> only overriding the lock to OFF when changes to
+other request parameters require a black level recalculation
+or reset.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If for some reason black level locking is no longer possible
+(for example,<wbr/> the analog gain has changed,<wbr/> which forces
+black level offsets to be recalculated),<wbr/> then the HAL must
+override this request (and it must report 'OFF' when this
+does happen) until the next capture for which locking is
+possible again.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.blackLevel.lock">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>black<wbr/>Level.<wbr/>lock
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[full] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OFF</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ON</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Whether black-level compensation is locked
+to its current values,<wbr/> or is free to vary.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_HAL2">HAL2</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Whether the black level offset was locked for this frame.<wbr/> Should be
+ON if <a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a> was ON in the capture request,<wbr/> unless
+a change in other capture settings forced the camera device to
+perform a black level reset.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If for some reason black level locking is no longer possible
+(for example,<wbr/> the analog gain has changed,<wbr/> which forces
+black level offsets to be recalculated),<wbr/> then the HAL must
+override this request (and it must report 'OFF' when this
+does happen) until the next capture for which locking is
+possible again.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_sync" class="section">sync</td></tr>
+
+
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.sync.frameNumber">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sync.<wbr/>frame<wbr/>Number
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int64</span>
+
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">CONVERGING</span>
+ <span class="entry_type_enum_value">-1</span>
+ <span class="entry_type_enum_notes"><p>The current result is not yet fully synchronized to any request.<wbr/></p>
+<p>Synchronization is in progress,<wbr/> and reading metadata from this
+result may include a mix of data that have taken effect since the
+last synchronization time.<wbr/></p>
+<p>In some future result,<wbr/> within <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> frames,<wbr/>
+this value will update to the actual frame number frame number
+the result is guaranteed to be synchronized to (as long as the
+request settings remain constant).<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">UNKNOWN</span>
+ <span class="entry_type_enum_value">-2</span>
+ <span class="entry_type_enum_notes"><p>The current result's synchronization status is unknown.<wbr/></p>
+<p>The result may have already converged,<wbr/> or it may be in
+progress.<wbr/> Reading from this result may include some mix
+of settings from past requests.<wbr/></p>
+<p>After a settings change,<wbr/> the new settings will eventually all
+take effect for the output buffers and results.<wbr/> However,<wbr/> this
+value will not change when that happens.<wbr/> Altering settings
+rapidly may provide outcomes using mixes of settings from recent
+requests.<wbr/></p>
+<p>This value is intended primarily for backwards compatibility with
+the older camera implementations (for android.<wbr/>hardware.<wbr/>Camera).<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The frame number corresponding to the last request
+with which the output result (metadata + buffers) has been fully
+synchronized.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>Either a non-negative value corresponding to a
+<code>frame_<wbr/>number</code>,<wbr/> or one of the two enums (CONVERGING /<wbr/> UNKNOWN).<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>When a request is submitted to the camera device,<wbr/> there is usually a
+delay of several frames before the controls get applied.<wbr/> A camera
+device may either choose to account for this delay by implementing a
+pipeline and carefully submit well-timed atomic control updates,<wbr/> or
+it may start streaming control changes that span over several frame
+boundaries.<wbr/></p>
+<p>In the latter case,<wbr/> whenever a request's settings change relative to
+the previous submitted request,<wbr/> the full set of changes may take
+multiple frame durations to fully take effect.<wbr/> Some settings may
+take effect sooner (in less frame durations) than others.<wbr/></p>
+<p>While a set of control changes are being propagated,<wbr/> this value
+will be CONVERGING.<wbr/></p>
+<p>Once it is fully known that a set of control changes have been
+finished propagating,<wbr/> and the resulting updated control settings
+have been read back by the camera device,<wbr/> this value will be set
+to a non-negative frame number (corresponding to the request to
+which the results have synchronized to).<wbr/></p>
+<p>Older camera device implementations may not have a way to detect
+when all camera controls have been applied,<wbr/> and will always set this
+value to UNKNOWN.<wbr/></p>
+<p>FULL capability devices will always have this value set to the
+frame number of the request corresponding to this result.<wbr/></p>
+<p><em>Further details</em>:</p>
+<ul>
+<li>Whenever a request differs from the last request,<wbr/> any future
+results not yet returned may have this value set to CONVERGING (this
+could include any in-progress captures not yet returned by the camera
+device,<wbr/> for more details see pipeline considerations below).<wbr/></li>
+<li>Submitting a series of multiple requests that differ from the
+previous request (e.<wbr/>g.<wbr/> r1,<wbr/> r2,<wbr/> r3 s.<wbr/>t.<wbr/> r1 != r2 != r3)
+moves the new synchronization frame to the last non-repeating
+request (using the smallest frame number from the contiguous list of
+repeating requests).<wbr/></li>
+<li>Submitting the same request repeatedly will not change this value
+to CONVERGING,<wbr/> if it was already a non-negative value.<wbr/></li>
+<li>When this value changes to non-negative,<wbr/> that means that all of the
+metadata controls from the request have been applied,<wbr/> all of the
+metadata controls from the camera device have been read to the
+updated values (into the result),<wbr/> and all of the graphics buffers
+corresponding to this result are also synchronized to the request.<wbr/></li>
+</ul>
+<p><em>Pipeline considerations</em>:</p>
+<p>Submitting a request with updated controls relative to the previously
+submitted requests may also invalidate the synchronization state
+of all the results corresponding to currently in-flight requests.<wbr/></p>
+<p>In other words,<wbr/> results for this current request and up to
+<a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> prior requests may have their
+<a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> change to CONVERGING.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>Using UNKNOWN here is illegal unless <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a>
+is also UNKNOWN.<wbr/></p>
+<p>FULL capability devices should simply set this value to the
+<code>frame_<wbr/>number</code> of the request this result corresponds to.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.sync.maxLatency">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>sync.<wbr/>max<wbr/>Latency
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+
+ <span class="entry_type_visibility"> [public]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">PER_FRAME_CONTROL</span>
+ <span class="entry_type_enum_value">0</span>
+ <span class="entry_type_enum_notes"><p>Every frame has the requests immediately applied.<wbr/></p>
+<p>Changing controls over multiple requests one after another will
+produce results that have those controls applied atomically
+each frame.<wbr/></p>
+<p>All FULL capability devices will have this as their maxLatency.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">UNKNOWN</span>
+ <span class="entry_type_enum_value">-1</span>
+ <span class="entry_type_enum_notes"><p>Each new frame has some subset (potentially the entire set)
+of the past requests applied to the camera settings.<wbr/></p>
+<p>By submitting a series of identical requests,<wbr/> the camera device
+will eventually have the camera settings applied,<wbr/> but it is
+unknown when that exact point will be.<wbr/></p>
+<p>All LEGACY capability devices will have this as their maxLatency.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximum number of frames that can occur after a request
+(different than the previous) has been submitted,<wbr/> and before the
+result's state becomes synchronized.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Frame counts
+ </td>
+
+ <td class="entry_range">
+ <p>A positive value,<wbr/> PER_<wbr/>FRAME_<wbr/>CONTROL,<wbr/> or UNKNOWN.<wbr/></p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_V1">V1</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This defines the maximum distance (in number of metadata results),<wbr/>
+between the frame number of the request that has new controls to apply
+and the frame number of the result that has all the controls applied.<wbr/></p>
+<p>In other words this acts as an upper boundary for how many frames
+must occur before the camera device knows for a fact that the new
+submitted camera settings have been applied in outgoing frames.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>For example if maxLatency was 2,<wbr/></p>
+<pre><code>initial request = X (repeating)
+request1 = X
+request2 = Y
+request3 = Y
+request4 = Y
+
+where requestN has frameNumber N,<wbr/> and the first of the repeating
+initial request's has frameNumber F (and F < 1).<wbr/>
+
+initial result = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F }
+result1 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F }
+result2 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING }
+result3 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING }
+result4 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2 }
+
+where resultN has frameNumber N.<wbr/>
+</code></pre>
+<p>Since <code>result4</code> has a <code>frameNumber == 4</code> and
+<code><a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2</code>,<wbr/> the distance is clearly
+<code>4 - 2 = 2</code>.<wbr/></p>
+<p>Use <code>frame_<wbr/>count</code> from camera3_<wbr/>request_<wbr/>t instead of
+<a href="#controls_android.request.frameCount">android.<wbr/>request.<wbr/>frame<wbr/>Count</a> or
+<code><a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html#getFrameNumber">CaptureResult#getFrameNumber</a></code>.<wbr/></p>
+<p>LIMITED devices are strongly encouraged to use a non-negative
+value.<wbr/> If UNKNOWN is used here then app developers do not have a way
+to know when sensor settings have been applied.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_reprocess" class="section">reprocess</td></tr>
+
+
+ <tr><td colspan="6" class="kind">controls</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="controls_android.reprocess.effectiveExposureFactor">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of exposure time increase factor applied to the original output
+frame by the application processing before sending for reprocessing.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Relative exposure time increase factor.<wbr/>
+ </td>
+
+ <td class="entry_range">
+ <p>>= 1.<wbr/>0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING
+capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p>
+<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original
+output frames to effectively reduce the noise to the same level as a frame that was
+captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured
+images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in
+the camera device is that the amount of noise in the image would be approximately what
+would be expected if the original capture parameters had been a sensitivity of
+S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather
+than S and T respectively.<wbr/> If the captured images were processed by the application
+before being sent for reprocessing,<wbr/> then the application may have used image processing
+algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the
+application-processed images (input images).<wbr/> By using the effectiveExposureFactor
+control,<wbr/> the application can communicate to the camera device the actual noise level
+improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera
+device can select appropriate noise reduction and edge enhancement parameters to avoid
+excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge
+enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p>
+<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse
+multiple output frames together to a final frame for reprocessing.<wbr/> When N image are
+fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to
+square root of N (based on a simple photon shot noise model).<wbr/> The camera device will
+adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+produce the best quality images.<wbr/></p>
+<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input
+buffer in a way that affects its effective exposure time.<wbr/></p>
+<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise
+reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/>
+Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when
+<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">dynamic</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="dynamic_android.reprocess.effectiveExposureFactor">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">float</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The amount of exposure time increase factor applied to the original output
+frame by the application processing before sending for reprocessing.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Relative exposure time increase factor.<wbr/>
+ </td>
+
+ <td class="entry_range">
+ <p>>= 1.<wbr/>0</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING
+capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p>
+<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original
+output frames to effectively reduce the noise to the same level as a frame that was
+captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured
+images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in
+the camera device is that the amount of noise in the image would be approximately what
+would be expected if the original capture parameters had been a sensitivity of
+S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather
+than S and T respectively.<wbr/> If the captured images were processed by the application
+before being sent for reprocessing,<wbr/> then the application may have used image processing
+algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the
+application-processed images (input images).<wbr/> By using the effectiveExposureFactor
+control,<wbr/> the application can communicate to the camera device the actual noise level
+improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera
+device can select appropriate noise reduction and edge enhancement parameters to avoid
+excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge
+enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p>
+<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse
+multiple output frames together to a final frame for reprocessing.<wbr/> When N image are
+fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to
+square root of N (based on a simple photon shot noise model).<wbr/> The camera device will
+adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+produce the best quality images.<wbr/></p>
+<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input
+buffer in a way that affects its effective exposure time.<wbr/></p>
+<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise
+reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/>
+Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when
+<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.reprocess.maxCaptureStall">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [java_public]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The maximal camera capture pipeline stall (in unit of frame count) introduced by a
+reprocess capture request.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ Number of frames.<wbr/>
+ </td>
+
+ <td class="entry_range">
+ <p><= 4</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_REPROC">REPROC</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>The key describes the maximal interference that one reprocess (input) request
+can introduce to the camera simultaneous streaming of regular (output) capture
+requests,<wbr/> including repeating requests.<wbr/></p>
+<p>When a reprocessing capture request is submitted while a camera output repeating request
+(e.<wbr/>g.<wbr/> preview) is being served by the camera device,<wbr/> it may preempt the camera capture
+pipeline for at least one frame duration so that the camera device is unable to process
+the following capture request in time for the next sensor start of exposure boundary.<wbr/>
+When this happens,<wbr/> the application may observe a capture time gap (longer than one frame
+duration) between adjacent capture output frames,<wbr/> which usually exhibits as preview
+glitch if the repeating request output targets include a preview surface.<wbr/> This key gives
+the worst-case number of frame stall introduced by one reprocess request with any kind of
+formats/<wbr/>sizes combination.<wbr/></p>
+<p>If this key reports 0,<wbr/> it means a reprocess request doesn't introduce any glitch to the
+ongoing camera repeating request outputs,<wbr/> as if this reprocess request is never issued.<wbr/></p>
+<p>This key is supported if the camera device supports PRIVATE or YUV reprocessing (
+i.<wbr/>e.<wbr/> <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains PRIVATE_<wbr/>REPROCESSING or
+YUV_<wbr/>REPROCESSING).<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+ <tr><td colspan="6" id="section_depth" class="section">depth</td></tr>
+
+
+ <tr><td colspan="6" class="kind">static</td></tr>
+
+ <thead class="entries_header">
+ <tr>
+ <th class="th_name">Property Name</th>
+ <th class="th_type">Type</th>
+ <th class="th_description">Description</th>
+ <th class="th_units">Units</th>
+ <th class="th_range">Range</th>
+ <th class="th_tags">Tags</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+
+
+
+
+
+
+
+
+
+ <tr class="entry" id="static_android.depth.maxDepthSamples">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int32</span>
+
+ <span class="entry_type_visibility"> [system]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Maximum number of points that a depth point cloud may contain.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If a camera device supports outputting depth range data in the form of a depth point
+cloud (<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a>),<wbr/> this is the maximum
+number of points an output buffer may contain.<wbr/></p>
+<p>Any given buffer may contain between 0 and maxDepthSamples points,<wbr/> inclusive.<wbr/>
+If output in the depth point cloud format is not supported,<wbr/> this entry will
+not be defined.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.depth.availableDepthStreamConfigurations">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ n x 4
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">OUTPUT</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">INPUT</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The available depth dataspace stream
+configurations that this camera device supports
+(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>These are output stream configurations for use with
+dataSpace HAL_<wbr/>DATASPACE_<wbr/>DEPTH.<wbr/> The configurations are
+listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code> tuples.<wbr/></p>
+<p>Only devices that support depth output for at least
+the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16 dense depth map may include
+this entry.<wbr/></p>
+<p>A device that also supports the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB
+sparse depth point cloud must report a single entry for
+the format in this list as <code>(HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB,<wbr/>
+<a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a>,<wbr/> 1,<wbr/> OUTPUT)</code> in addition to
+the entries for HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.depth.availableDepthMinFrameDurations">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This lists the minimum frame duration for each
+format/<wbr/>size combination for depth output formats.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>This should correspond to the frame duration when only that
+stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
+set to either OFF or FAST.<wbr/></p>
+<p>When multiple streams are used in a request,<wbr/> the minimum frame
+duration will be max(individual stream min durations).<wbr/></p>
+<p>The minimum frame duration of a stream (of a particular format,<wbr/> size)
+is the same regardless of whether the stream is input or output.<wbr/></p>
+<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about
+calculating the max frame rate.<wbr/></p>
+<p>(Keep in sync with <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.depth.availableDepthStallDurations">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name">int64</span>
+ <span class="entry_type_container">x</span>
+
+ <span class="entry_type_array">
+ 4 x n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>This lists the maximum stall duration for each
+output format/<wbr/>size combination for depth streams.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_DEPTH">DEPTH</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>A stall duration is how much extra time would get added
+to the normal minimum frame duration for a repeating request
+that has streams with non-zero stall.<wbr/></p>
+<p>This functions similarly to
+<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for depth
+streams.<wbr/></p>
+<p>All depth output stream formats may have a nonzero stall
+duration.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.depth.depthIsExclusive">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+ <span class="entry_type_hwlevel">[limited] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Indicates whether a capture request may target both a
+DEPTH16 /<wbr/> DEPTH_<wbr/>POINT_<wbr/>CLOUD output,<wbr/> and normal color outputs (such as
+YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> or RAW) simultaneously.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If TRUE,<wbr/> including both depth and color outputs in a single
+capture request is not supported.<wbr/> An application must interleave color
+and depth requests.<wbr/> If FALSE,<wbr/> a single request can target both types
+of output.<wbr/></p>
+<p>Typically,<wbr/> this restriction exists on camera devices that
+need to emit a specific pattern or wavelength of light to
+measure depth values,<wbr/> which causes the color image to be
+corrupted during depth measurement.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
+
+
+ <!-- end of kind -->
+ </tbody>
+
+ <!-- end of section -->
+<!-- </namespace> -->
+ </table>
+
+ <div class="tags" id="tag_index">
+ <h2>Tags</h2>
+ <ul>
+ <li id="tag_BC">BC -
+ Needed for backwards compatibility with old Java API
+
+ <ul class="tags_entries">
+ <li><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a> (controls)</li>
+ <li><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a> (controls)</li>
+ <li><a href="#controls_android.control.aeLock">android.control.aeLock</a> (controls)</li>
+ <li><a href="#controls_android.control.aeMode">android.control.aeMode</a> (controls)</li>
+ <li><a href="#controls_android.control.aeRegions">android.control.aeRegions</a> (controls)</li>
+ <li><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a> (controls)</li>
+ <li><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a> (controls)</li>
+ <li><a href="#controls_android.control.afMode">android.control.afMode</a> (controls)</li>
+ <li><a href="#controls_android.control.afRegions">android.control.afRegions</a> (controls)</li>
+ <li><a href="#controls_android.control.afTrigger">android.control.afTrigger</a> (controls)</li>
+ <li><a href="#controls_android.control.awbLock">android.control.awbLock</a> (controls)</li>
+ <li><a href="#controls_android.control.awbMode">android.control.awbMode</a> (controls)</li>
+ <li><a href="#controls_android.control.awbRegions">android.control.awbRegions</a> (controls)</li>
+ <li><a href="#controls_android.control.captureIntent">android.control.captureIntent</a> (controls)</li>
+ <li><a href="#controls_android.control.effectMode">android.control.effectMode</a> (controls)</li>
+ <li><a href="#controls_android.control.mode">android.control.mode</a> (controls)</li>
+ <li><a href="#controls_android.control.sceneMode">android.control.sceneMode</a> (controls)</li>
+ <li><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a> (controls)</li>
+ <li><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a> (static)</li>
+ <li><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a> (static)</li>
+ <li><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a> (static)</li>
+ <li><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a> (static)</li>
+ <li><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a> (static)</li>
+ <li><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a> (static)</li>
+ <li><a href="#static_android.control.availableEffects">android.control.availableEffects</a> (static)</li>
+ <li><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a> (static)</li>
+ <li><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a> (static)</li>
+ <li><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a> (static)</li>
+ <li><a href="#static_android.control.maxRegions">android.control.maxRegions</a> (static)</li>
+ <li><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a> (static)</li>
+ <li><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a> (static)</li>
+ <li><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a> (static)</li>
+ <li><a href="#controls_android.flash.mode">android.flash.mode</a> (controls)</li>
+ <li><a href="#static_android.flash.info.available">android.flash.info.available</a> (static)</li>
+ <li><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.quality">android.jpeg.quality</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a> (controls)</li>
+ <li><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a> (controls)</li>
+ <li><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a> (static)</li>
+ <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li>
+ <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li>
+ <li><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a> (dynamic)</li>
+ <li><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a> (static)</li>
+ <li><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a> (controls)</li>
+ <li><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a> (static)</li>
+ <li><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a> (static)</li>
+ <li><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a> (static)</li>
+ <li><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a> (static)</li>
+ <li><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a> (static)</li>
+ <li><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a> (static)</li>
+ <li><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a> (static)</li>
+ <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li>
+ <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li>
+ <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li>
+ <li><a href="#static_android.sensor.orientation">android.sensor.orientation</a> (static)</li>
+ <li><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a> (dynamic)</li>
+ <li><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a> (controls)</li>
+ <li><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a> (static)</li>
+ <li><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a> (dynamic)</li>
+ <li><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a> (dynamic)</li>
+ <li><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a> (dynamic)</li>
+ <li><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a> (dynamic)</li>
+ <li><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a> (dynamic)</li>
+ <li><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a> (dynamic)</li>
+ </ul>
+ </li> <!-- tag_BC -->
+ <li id="tag_V1">V1 -
+ New features for first camera 2 release (API1)
+
+ <ul class="tags_entries">
+ <li><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a> (static)</li>
+ <li><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a> (static)</li>
+ <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li>
+ <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li>
+ <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li>
+ <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li>
+ <li><a href="#controls_android.lens.aperture">android.lens.aperture</a> (controls)</li>
+ <li><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a> (controls)</li>
+ <li><a href="#controls_android.lens.focalLength">android.lens.focalLength</a> (controls)</li>
+ <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li>
+ <li><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (controls)</li>
+ <li><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a> (static)</li>
+ <li><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a> (static)</li>
+ <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li>
+ <li><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a> (static)</li>
+ <li><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a> (static)</li>
+ <li><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a> (static)</li>
+ <li><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a> (static)</li>
+ <li><a href="#dynamic_android.lens.state">android.lens.state</a> (dynamic)</li>
+ <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li>
+ <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li>
+ <li><a href="#controls_android.request.id">android.request.id</a> (controls)</li>
+ <li><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a> (static)</li>
+ <li><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a> (static)</li>
+ <li><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a> (controls)</li>
+ <li><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a> (controls)</li>
+ <li><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a> (controls)</li>
+ <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li>
+ <li><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a> (static)</li>
+ <li><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a> (static)</li>
+ <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li>
+ <li><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a> (static)</li>
+ <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li>
+ <li><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a> (dynamic)</li>
+ <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li>
+ <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li>
+ <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a> (dynamic)</li>
+ <li><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a> (static)</li>
+ <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li>
+ <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li>
+ <li><a href="#dynamic_android.lens.aperture">android.lens.aperture</a> (dynamic)</li>
+ <li><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a> (dynamic)</li>
+ <li><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (dynamic)</li>
+ <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li>
+ </ul>
+ </li> <!-- tag_V1 -->
+ <li id="tag_RAW">RAW -
+ Needed for useful RAW image processing and DNG file support
+
+ <ul class="tags_entries">
+ <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li>
+ <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li>
+ <li><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a> (static)</li>
+ <li><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a> (static)</li>
+ <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li>
+ <li><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a> (static)</li>
+ <li><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a> (static)</li>
+ <li><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a> (static)</li>
+ <li><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a> (static)</li>
+ <li><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a> (static)</li>
+ <li><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a> (static)</li>
+ <li><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a> (static)</li>
+ <li><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a> (static)</li>
+ <li><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a> (static)</li>
+ <li><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a> (static)</li>
+ <li><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a> (static)</li>
+ <li><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a> (static)</li>
+ <li><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a> (dynamic)</li>
+ <li><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a> (dynamic)</li>
+ <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li>
+ <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li>
+ <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li>
+ <li><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a> (controls)</li>
+ <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li>
+ </ul>
+ </li> <!-- tag_RAW -->
+ <li id="tag_HAL2">HAL2 -
+ Entry is only used by camera device HAL 2.x
+
+ <ul class="tags_entries">
+ <li><a href="#controls_android.request.inputStreams">android.request.inputStreams</a> (controls)</li>
+ <li><a href="#controls_android.request.outputStreams">android.request.outputStreams</a> (controls)</li>
+ <li><a href="#controls_android.request.type">android.request.type</a> (controls)</li>
+ <li><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a> (static)</li>
+ <li><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a> (controls)</li>
+ </ul>
+ </li> <!-- tag_HAL2 -->
+ <li id="tag_FULL">FULL -
+ Entry is required for full hardware level devices, and optional for other hardware levels
+
+ <ul class="tags_entries">
+ <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li>
+ </ul>
+ </li> <!-- tag_FULL -->
+ <li id="tag_DEPTH">DEPTH -
+ Entry is required for the depth capability.
+
+ <ul class="tags_entries">
+ <li><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a> (static)</li>
+ <li><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a> (static)</li>
+ <li><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a> (static)</li>
+ <li><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a> (static)</li>
+ <li><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a> (static)</li>
+ <li><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a> (static)</li>
+ <li><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a> (static)</li>
+ <li><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a> (static)</li>
+ </ul>
+ </li> <!-- tag_DEPTH -->
+ <li id="tag_REPROC">REPROC -
+ Entry is required for the YUV or PRIVATE reprocessing capability.
+
+ <ul class="tags_entries">
+ <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li>
+ <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li>
+ <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li>
+ <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li>
+ <li><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a> (static)</li>
+ <li><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a> (static)</li>
+ <li><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a> (controls)</li>
+ <li><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a> (static)</li>
+ <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li>
+ <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li>
+ </ul>
+ </li> <!-- tag_REPROC -->
+ <li id="tag_FUTURE">FUTURE -
+ Entry is under-specified and is not required for now. This is for book-keeping purpose,
+ do not implement or use it, it may be revised for future.
+
+ <ul class="tags_entries">
+ <li><a href="#controls_android.demosaic.mode">android.demosaic.mode</a> (controls)</li>
+ <li><a href="#controls_android.edge.strength">android.edge.strength</a> (controls)</li>
+ <li><a href="#controls_android.flash.firingPower">android.flash.firingPower</a> (controls)</li>
+ <li><a href="#controls_android.flash.firingTime">android.flash.firingTime</a> (controls)</li>
+ <li><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a> (static)</li>
+ <li><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a> (static)</li>
+ <li><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a> (static)</li>
+ <li><a href="#dynamic_android.jpeg.size">android.jpeg.size</a> (dynamic)</li>
+ <li><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a> (controls)</li>
+ <li><a href="#controls_android.request.metadataMode">android.request.metadataMode</a> (controls)</li>
+ <li><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a> (static)</li>
+ <li><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a> (dynamic)</li>
+ <li><a href="#controls_android.shading.strength">android.shading.strength</a> (controls)</li>
+ <li><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a> (controls)</li>
+ <li><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a> (controls)</li>
+ <li><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a> (static)</li>
+ <li><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a> (static)</li>
+ <li><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a> (static)</li>
+ <li><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a> (static)</li>
+ <li><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a> (dynamic)</li>
+ <li><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a> (dynamic)</li>
+ </ul>
+ </li> <!-- tag_FUTURE -->
+ </ul>
+ </div>
+
+ [ <a href="#">top</a> ]
+
+</body>
+</html>
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
new file mode 100644
index 0000000..2b4b287
--- /dev/null
+++ b/camera/metadata/3.2/types.hal
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (C) 2016 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.camera.metadata@3.2;
+
+/** TODO(b/33012412):
+ * - The following information should be code-generated from:
+ * system/media/camera/docs/metadata_properties.xml
+ * - Some enum below should be signed:
+ * - metadata section/key should be unsigned
+ * - matadata value enum should be signed
+ */
+
+/**
+ * Top level hierarchy definitions for camera metadata. *_INFO sections are for
+ * the static metadata that can be retrived without opening the camera device.
+ * New sections must be added right before ANDROID_SECTION_COUNT to maintain
+ * existing enumerations.
+ */
+enum CameraMetadataSection : uint32_t {
+ ANDROID_COLOR_CORRECTION,
+
+ ANDROID_CONTROL,
+
+ ANDROID_DEMOSAIC,
+
+ ANDROID_EDGE,
+
+ ANDROID_FLASH,
+
+ ANDROID_FLASH_INFO,
+
+ ANDROID_HOT_PIXEL,
+
+ ANDROID_JPEG,
+
+ ANDROID_LENS,
+
+ ANDROID_LENS_INFO,
+
+ ANDROID_NOISE_REDUCTION,
+
+ ANDROID_QUIRKS,
+
+ ANDROID_REQUEST,
+
+ ANDROID_SCALER,
+
+ ANDROID_SENSOR,
+
+ ANDROID_SENSOR_INFO,
+
+ ANDROID_SHADING,
+
+ ANDROID_STATISTICS,
+
+ ANDROID_STATISTICS_INFO,
+
+ ANDROID_TONEMAP,
+
+ ANDROID_LED,
+
+ ANDROID_INFO,
+
+ ANDROID_BLACK_LEVEL,
+
+ ANDROID_SYNC,
+
+ ANDROID_REPROCESS,
+
+ ANDROID_DEPTH,
+
+ ANDROID_SECTION_COUNT,
+
+ VENDOR_SECTION = 0x8000,
+
+};
+
+/**
+ * Hierarchy positions in enum space. All vendor extension tags must be
+ * defined with tag >= VENDOR_SECTION_START
+ */
+enum CameraMetadataSectionStart : uint32_t {
+ ANDROID_COLOR_CORRECTION_START = CameraMetadataSection:ANDROID_COLOR_CORRECTION << 16,
+
+ ANDROID_CONTROL_START = CameraMetadataSection:ANDROID_CONTROL << 16,
+
+ ANDROID_DEMOSAIC_START = CameraMetadataSection:ANDROID_DEMOSAIC << 16,
+
+ ANDROID_EDGE_START = CameraMetadataSection:ANDROID_EDGE << 16,
+
+ ANDROID_FLASH_START = CameraMetadataSection:ANDROID_FLASH << 16,
+
+ ANDROID_FLASH_INFO_START = CameraMetadataSection:ANDROID_FLASH_INFO << 16,
+
+ ANDROID_HOT_PIXEL_START = CameraMetadataSection:ANDROID_HOT_PIXEL << 16,
+
+ ANDROID_JPEG_START = CameraMetadataSection:ANDROID_JPEG << 16,
+
+ ANDROID_LENS_START = CameraMetadataSection:ANDROID_LENS << 16,
+
+ ANDROID_LENS_INFO_START = CameraMetadataSection:ANDROID_LENS_INFO << 16,
+
+ ANDROID_NOISE_REDUCTION_START = CameraMetadataSection:ANDROID_NOISE_REDUCTION << 16,
+
+ ANDROID_QUIRKS_START = CameraMetadataSection:ANDROID_QUIRKS << 16,
+
+ ANDROID_REQUEST_START = CameraMetadataSection:ANDROID_REQUEST << 16,
+
+ ANDROID_SCALER_START = CameraMetadataSection:ANDROID_SCALER << 16,
+
+ ANDROID_SENSOR_START = CameraMetadataSection:ANDROID_SENSOR << 16,
+
+ ANDROID_SENSOR_INFO_START = CameraMetadataSection:ANDROID_SENSOR_INFO << 16,
+
+ ANDROID_SHADING_START = CameraMetadataSection:ANDROID_SHADING << 16,
+
+ ANDROID_STATISTICS_START = CameraMetadataSection:ANDROID_STATISTICS << 16,
+
+ ANDROID_STATISTICS_INFO_START = CameraMetadataSection:ANDROID_STATISTICS_INFO << 16,
+
+ ANDROID_TONEMAP_START = CameraMetadataSection:ANDROID_TONEMAP << 16,
+
+ ANDROID_LED_START = CameraMetadataSection:ANDROID_LED << 16,
+
+ ANDROID_INFO_START = CameraMetadataSection:ANDROID_INFO << 16,
+
+ ANDROID_BLACK_LEVEL_START = CameraMetadataSection:ANDROID_BLACK_LEVEL << 16,
+
+ ANDROID_SYNC_START = CameraMetadataSection:ANDROID_SYNC << 16,
+
+ ANDROID_REPROCESS_START = CameraMetadataSection:ANDROID_REPROCESS << 16,
+
+ ANDROID_DEPTH_START = CameraMetadataSection:ANDROID_DEPTH << 16,
+
+ VENDOR_SECTION_START = CameraMetadataSection:VENDOR_SECTION << 16,
+
+};
+
+/**
+ * Main enum for defining camera metadata tags. New entries must always go
+ * before the section _END tag to preserve existing enumeration values. In
+ * addition, the name and type of the tag needs to be added to
+ * system/media/camera/src/camera_metadata_tag_info.c
+ */
+enum CameraMetadataTag : uint32_t {
+ ANDROID_COLOR_CORRECTION_MODE = CameraMetadataSectionStart:ANDROID_COLOR_CORRECTION_START,
+
+ ANDROID_COLOR_CORRECTION_TRANSFORM,
+
+ ANDROID_COLOR_CORRECTION_GAINS,
+
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+
+ ANDROID_COLOR_CORRECTION_END,
+
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE = CameraMetadataSectionStart:ANDROID_CONTROL_START,
+
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+
+ ANDROID_CONTROL_AE_LOCK,
+
+ ANDROID_CONTROL_AE_MODE,
+
+ ANDROID_CONTROL_AE_REGIONS,
+
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+
+ ANDROID_CONTROL_AF_MODE,
+
+ ANDROID_CONTROL_AF_REGIONS,
+
+ ANDROID_CONTROL_AF_TRIGGER,
+
+ ANDROID_CONTROL_AWB_LOCK,
+
+ ANDROID_CONTROL_AWB_MODE,
+
+ ANDROID_CONTROL_AWB_REGIONS,
+
+ ANDROID_CONTROL_CAPTURE_INTENT,
+
+ ANDROID_CONTROL_EFFECT_MODE,
+
+ ANDROID_CONTROL_MODE,
+
+ ANDROID_CONTROL_SCENE_MODE,
+
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+
+ ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+
+ ANDROID_CONTROL_AE_AVAILABLE_MODES,
+
+ ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+
+ ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+
+ ANDROID_CONTROL_AE_COMPENSATION_STEP,
+
+ ANDROID_CONTROL_AF_AVAILABLE_MODES,
+
+ ANDROID_CONTROL_AVAILABLE_EFFECTS,
+
+ ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+
+ ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+
+ ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+
+ ANDROID_CONTROL_MAX_REGIONS,
+
+ ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
+
+ ANDROID_CONTROL_AE_PRECAPTURE_ID,
+
+ ANDROID_CONTROL_AE_STATE,
+
+ ANDROID_CONTROL_AF_STATE,
+
+ ANDROID_CONTROL_AF_TRIGGER_ID,
+
+ ANDROID_CONTROL_AWB_STATE,
+
+ ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
+
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+
+ ANDROID_CONTROL_AVAILABLE_MODES,
+
+ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+
+ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
+
+ ANDROID_CONTROL_ENABLE_ZSL,
+
+ ANDROID_CONTROL_END,
+
+ ANDROID_DEMOSAIC_MODE = CameraMetadataSectionStart:ANDROID_DEMOSAIC_START,
+
+ ANDROID_DEMOSAIC_END,
+
+ ANDROID_EDGE_MODE = CameraMetadataSectionStart:ANDROID_EDGE_START,
+
+ ANDROID_EDGE_STRENGTH,
+
+ ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+
+ ANDROID_EDGE_END,
+
+ ANDROID_FLASH_FIRING_POWER = CameraMetadataSectionStart:ANDROID_FLASH_START,
+
+ ANDROID_FLASH_FIRING_TIME,
+
+ ANDROID_FLASH_MODE,
+
+ ANDROID_FLASH_COLOR_TEMPERATURE,
+
+ ANDROID_FLASH_MAX_ENERGY,
+
+ ANDROID_FLASH_STATE,
+
+ ANDROID_FLASH_END,
+
+ ANDROID_FLASH_INFO_AVAILABLE = CameraMetadataSectionStart:ANDROID_FLASH_INFO_START,
+
+ ANDROID_FLASH_INFO_CHARGE_DURATION,
+
+ ANDROID_FLASH_INFO_END,
+
+ ANDROID_HOT_PIXEL_MODE = CameraMetadataSectionStart:ANDROID_HOT_PIXEL_START,
+
+ ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
+
+ ANDROID_HOT_PIXEL_END,
+
+ ANDROID_JPEG_GPS_COORDINATES = CameraMetadataSectionStart:ANDROID_JPEG_START,
+
+ ANDROID_JPEG_GPS_PROCESSING_METHOD,
+
+ ANDROID_JPEG_GPS_TIMESTAMP,
+
+ ANDROID_JPEG_ORIENTATION,
+
+ ANDROID_JPEG_QUALITY,
+
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+
+ ANDROID_JPEG_THUMBNAIL_SIZE,
+
+ ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+
+ ANDROID_JPEG_MAX_SIZE,
+
+ ANDROID_JPEG_SIZE,
+
+ ANDROID_JPEG_END,
+
+ ANDROID_LENS_APERTURE = CameraMetadataSectionStart:ANDROID_LENS_START,
+
+ ANDROID_LENS_FILTER_DENSITY,
+
+ ANDROID_LENS_FOCAL_LENGTH,
+
+ ANDROID_LENS_FOCUS_DISTANCE,
+
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+
+ ANDROID_LENS_FACING,
+
+ ANDROID_LENS_POSE_ROTATION,
+
+ ANDROID_LENS_POSE_TRANSLATION,
+
+ ANDROID_LENS_FOCUS_RANGE,
+
+ ANDROID_LENS_STATE,
+
+ ANDROID_LENS_INTRINSIC_CALIBRATION,
+
+ ANDROID_LENS_RADIAL_DISTORTION,
+
+ ANDROID_LENS_END,
+
+ ANDROID_LENS_INFO_AVAILABLE_APERTURES = CameraMetadataSectionStart:ANDROID_LENS_INFO_START,
+
+ ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
+
+ ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
+
+ ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+
+ ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
+
+ ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
+
+ ANDROID_LENS_INFO_SHADING_MAP_SIZE,
+
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+
+ ANDROID_LENS_INFO_END,
+
+ ANDROID_NOISE_REDUCTION_MODE = CameraMetadataSectionStart:ANDROID_NOISE_REDUCTION_START,
+
+ ANDROID_NOISE_REDUCTION_STRENGTH,
+
+ ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+
+ ANDROID_NOISE_REDUCTION_END,
+
+ ANDROID_QUIRKS_METERING_CROP_REGION = CameraMetadataSectionStart:ANDROID_QUIRKS_START,
+
+ ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO,
+
+ ANDROID_QUIRKS_USE_ZSL_FORMAT,
+
+ ANDROID_QUIRKS_USE_PARTIAL_RESULT,
+
+ ANDROID_QUIRKS_PARTIAL_RESULT,
+
+ ANDROID_QUIRKS_END,
+
+ ANDROID_REQUEST_FRAME_COUNT = CameraMetadataSectionStart:ANDROID_REQUEST_START,
+
+ ANDROID_REQUEST_ID,
+
+ ANDROID_REQUEST_INPUT_STREAMS,
+
+ ANDROID_REQUEST_METADATA_MODE,
+
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+
+ ANDROID_REQUEST_TYPE,
+
+ ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+
+ ANDROID_REQUEST_MAX_NUM_REPROCESS_STREAMS,
+
+ ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+
+ ANDROID_REQUEST_PIPELINE_DEPTH,
+
+ ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+
+ ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+
+ ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
+
+ ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
+
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+
+ ANDROID_REQUEST_END,
+
+ ANDROID_SCALER_CROP_REGION = CameraMetadataSectionStart:ANDROID_SCALER_START,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS,
+
+ ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
+
+ ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
+
+ ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+
+ ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
+
+ ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
+
+ ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
+
+ ANDROID_SCALER_AVAILABLE_RAW_SIZES,
+
+ ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP,
+
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+
+ ANDROID_SCALER_CROPPING_TYPE,
+
+ ANDROID_SCALER_END,
+
+ ANDROID_SENSOR_EXPOSURE_TIME = CameraMetadataSectionStart:ANDROID_SENSOR_START,
+
+ ANDROID_SENSOR_FRAME_DURATION,
+
+ ANDROID_SENSOR_SENSITIVITY,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
+
+ ANDROID_SENSOR_CALIBRATION_TRANSFORM1,
+
+ ANDROID_SENSOR_CALIBRATION_TRANSFORM2,
+
+ ANDROID_SENSOR_COLOR_TRANSFORM1,
+
+ ANDROID_SENSOR_COLOR_TRANSFORM2,
+
+ ANDROID_SENSOR_FORWARD_MATRIX1,
+
+ ANDROID_SENSOR_FORWARD_MATRIX2,
+
+ ANDROID_SENSOR_BASE_GAIN_FACTOR,
+
+ ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
+
+ ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY,
+
+ ANDROID_SENSOR_ORIENTATION,
+
+ ANDROID_SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS,
+
+ ANDROID_SENSOR_TIMESTAMP,
+
+ ANDROID_SENSOR_TEMPERATURE,
+
+ ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+
+ ANDROID_SENSOR_NOISE_PROFILE,
+
+ ANDROID_SENSOR_PROFILE_HUE_SAT_MAP,
+
+ ANDROID_SENSOR_PROFILE_TONE_CURVE,
+
+ ANDROID_SENSOR_GREEN_SPLIT,
+
+ ANDROID_SENSOR_TEST_PATTERN_DATA,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE,
+
+ ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
+
+ ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
+
+ ANDROID_SENSOR_OPTICAL_BLACK_REGIONS,
+
+ ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL,
+
+ ANDROID_SENSOR_DYNAMIC_WHITE_LEVEL,
+
+ ANDROID_SENSOR_OPAQUE_RAW_SIZE,
+
+ ANDROID_SENSOR_END,
+
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE = CameraMetadataSectionStart:ANDROID_SENSOR_INFO_START,
+
+ ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
+
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
+
+ ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
+
+ ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+
+ ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
+
+ ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+
+ ANDROID_SENSOR_INFO_WHITE_LEVEL,
+
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+
+ ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED,
+
+ ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+
+ ANDROID_SENSOR_INFO_END,
+
+ ANDROID_SHADING_MODE = CameraMetadataSectionStart:ANDROID_SHADING_START,
+
+ ANDROID_SHADING_STRENGTH,
+
+ ANDROID_SHADING_AVAILABLE_MODES,
+
+ ANDROID_SHADING_END,
+
+ ANDROID_STATISTICS_FACE_DETECT_MODE = CameraMetadataSectionStart:ANDROID_STATISTICS_START,
+
+ ANDROID_STATISTICS_HISTOGRAM_MODE,
+
+ ANDROID_STATISTICS_SHARPNESS_MAP_MODE,
+
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+
+ ANDROID_STATISTICS_FACE_IDS,
+
+ ANDROID_STATISTICS_FACE_LANDMARKS,
+
+ ANDROID_STATISTICS_FACE_RECTANGLES,
+
+ ANDROID_STATISTICS_FACE_SCORES,
+
+ ANDROID_STATISTICS_HISTOGRAM,
+
+ ANDROID_STATISTICS_SHARPNESS_MAP,
+
+ ANDROID_STATISTICS_LENS_SHADING_CORRECTION_MAP,
+
+ ANDROID_STATISTICS_LENS_SHADING_MAP,
+
+ ANDROID_STATISTICS_PREDICTED_COLOR_GAINS,
+
+ ANDROID_STATISTICS_PREDICTED_COLOR_TRANSFORM,
+
+ ANDROID_STATISTICS_SCENE_FLICKER,
+
+ ANDROID_STATISTICS_HOT_PIXEL_MAP,
+
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+
+ ANDROID_STATISTICS_END,
+
+ ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
+ CameraMetadataSectionStart:ANDROID_STATISTICS_INFO_START,
+
+ ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT,
+
+ ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+
+ ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
+
+ ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
+
+ ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+
+ ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+
+ ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+
+ ANDROID_STATISTICS_INFO_END,
+
+ ANDROID_TONEMAP_CURVE_BLUE = CameraMetadataSectionStart:ANDROID_TONEMAP_START,
+
+ ANDROID_TONEMAP_CURVE_GREEN,
+
+ ANDROID_TONEMAP_CURVE_RED,
+
+ ANDROID_TONEMAP_MODE,
+
+ ANDROID_TONEMAP_MAX_CURVE_POINTS,
+
+ ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES,
+
+ ANDROID_TONEMAP_GAMMA,
+
+ ANDROID_TONEMAP_PRESET_CURVE,
+
+ ANDROID_TONEMAP_END,
+
+ ANDROID_LED_TRANSMIT = CameraMetadataSectionStart:ANDROID_LED_START,
+
+ ANDROID_LED_AVAILABLE_LEDS,
+
+ ANDROID_LED_END,
+
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL = CameraMetadataSectionStart:ANDROID_INFO_START,
+
+ ANDROID_INFO_END,
+
+ ANDROID_BLACK_LEVEL_LOCK = CameraMetadataSectionStart:ANDROID_BLACK_LEVEL_START,
+
+ ANDROID_BLACK_LEVEL_END,
+
+ ANDROID_SYNC_FRAME_NUMBER = CameraMetadataSectionStart:ANDROID_SYNC_START,
+
+ ANDROID_SYNC_MAX_LATENCY,
+
+ ANDROID_SYNC_END,
+
+ ANDROID_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR = CameraMetadataSectionStart:ANDROID_REPROCESS_START,
+
+ ANDROID_REPROCESS_MAX_CAPTURE_STALL,
+
+ ANDROID_REPROCESS_END,
+
+ ANDROID_DEPTH_MAX_DEPTH_SAMPLES = CameraMetadataSectionStart:ANDROID_DEPTH_START,
+
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+
+ ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
+
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,
+
+ ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE,
+
+ ANDROID_DEPTH_END,
+
+};
+
+/**
+ * Enumeration definitions for the various entries that need them
+ */
+enum CameraMetadataEnumAndroidColorCorrectionMode : uint32_t {
+ ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
+
+ ANDROID_COLOR_CORRECTION_MODE_FAST,
+
+ ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY,
+
+};
+
+enum CameraMetadataEnumAndroidColorCorrectionAberrationMode : uint32_t {
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF,
+
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
+
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY,
+
+};
+
+enum CameraMetadataEnumAndroidControlAeAntibandingMode : uint32_t {
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
+
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,
+
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
+
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
+
+};
+
+enum CameraMetadataEnumAndroidControlAeLock : uint32_t {
+ ANDROID_CONTROL_AE_LOCK_OFF,
+
+ ANDROID_CONTROL_AE_LOCK_ON,
+
+};
+
+enum CameraMetadataEnumAndroidControlAeMode : uint32_t {
+ ANDROID_CONTROL_AE_MODE_OFF,
+
+ ANDROID_CONTROL_AE_MODE_ON,
+
+ ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH,
+
+ ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
+
+ ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
+
+};
+
+enum CameraMetadataEnumAndroidControlAePrecaptureTrigger : uint32_t {
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE,
+
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START,
+
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
+
+};
+
+enum CameraMetadataEnumAndroidControlAfMode : uint32_t {
+ ANDROID_CONTROL_AF_MODE_OFF,
+
+ ANDROID_CONTROL_AF_MODE_AUTO,
+
+ ANDROID_CONTROL_AF_MODE_MACRO,
+
+ ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+
+ ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+
+ ANDROID_CONTROL_AF_MODE_EDOF,
+
+};
+
+enum CameraMetadataEnumAndroidControlAfTrigger : uint32_t {
+ ANDROID_CONTROL_AF_TRIGGER_IDLE,
+
+ ANDROID_CONTROL_AF_TRIGGER_START,
+
+ ANDROID_CONTROL_AF_TRIGGER_CANCEL,
+
+};
+
+enum CameraMetadataEnumAndroidControlAwbLock : uint32_t {
+ ANDROID_CONTROL_AWB_LOCK_OFF,
+
+ ANDROID_CONTROL_AWB_LOCK_ON,
+
+};
+
+enum CameraMetadataEnumAndroidControlAwbMode : uint32_t {
+ ANDROID_CONTROL_AWB_MODE_OFF,
+
+ ANDROID_CONTROL_AWB_MODE_AUTO,
+
+ ANDROID_CONTROL_AWB_MODE_INCANDESCENT,
+
+ ANDROID_CONTROL_AWB_MODE_FLUORESCENT,
+
+ ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT,
+
+ ANDROID_CONTROL_AWB_MODE_DAYLIGHT,
+
+ ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT,
+
+ ANDROID_CONTROL_AWB_MODE_TWILIGHT,
+
+ ANDROID_CONTROL_AWB_MODE_SHADE,
+
+};
+
+enum CameraMetadataEnumAndroidControlCaptureIntent : uint32_t {
+ ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
+
+ ANDROID_CONTROL_CAPTURE_INTENT_MANUAL,
+
+};
+
+enum CameraMetadataEnumAndroidControlEffectMode : uint32_t {
+ ANDROID_CONTROL_EFFECT_MODE_OFF,
+
+ ANDROID_CONTROL_EFFECT_MODE_MONO,
+
+ ANDROID_CONTROL_EFFECT_MODE_NEGATIVE,
+
+ ANDROID_CONTROL_EFFECT_MODE_SOLARIZE,
+
+ ANDROID_CONTROL_EFFECT_MODE_SEPIA,
+
+ ANDROID_CONTROL_EFFECT_MODE_POSTERIZE,
+
+ ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD,
+
+ ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD,
+
+ ANDROID_CONTROL_EFFECT_MODE_AQUA,
+
+};
+
+enum CameraMetadataEnumAndroidControlMode : uint32_t {
+ ANDROID_CONTROL_MODE_OFF,
+
+ ANDROID_CONTROL_MODE_AUTO,
+
+ ANDROID_CONTROL_MODE_USE_SCENE_MODE,
+
+ ANDROID_CONTROL_MODE_OFF_KEEP_STATE,
+
+};
+
+enum CameraMetadataEnumAndroidControlSceneMode : uint32_t {
+ ANDROID_CONTROL_SCENE_MODE_DISABLED = 0,
+
+ ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY,
+
+ ANDROID_CONTROL_SCENE_MODE_ACTION,
+
+ ANDROID_CONTROL_SCENE_MODE_PORTRAIT,
+
+ ANDROID_CONTROL_SCENE_MODE_LANDSCAPE,
+
+ ANDROID_CONTROL_SCENE_MODE_NIGHT,
+
+ ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
+
+ ANDROID_CONTROL_SCENE_MODE_THEATRE,
+
+ ANDROID_CONTROL_SCENE_MODE_BEACH,
+
+ ANDROID_CONTROL_SCENE_MODE_SNOW,
+
+ ANDROID_CONTROL_SCENE_MODE_SUNSET,
+
+ ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO,
+
+ ANDROID_CONTROL_SCENE_MODE_FIREWORKS,
+
+ ANDROID_CONTROL_SCENE_MODE_SPORTS,
+
+ ANDROID_CONTROL_SCENE_MODE_PARTY,
+
+ ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT,
+
+ ANDROID_CONTROL_SCENE_MODE_BARCODE,
+
+ ANDROID_CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO,
+
+ ANDROID_CONTROL_SCENE_MODE_HDR,
+
+ ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT,
+
+ ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_START = 100,
+
+ ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_END = 127,
+
+};
+
+enum CameraMetadataEnumAndroidControlVideoStabilizationMode : uint32_t {
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidControlAeState : uint32_t {
+ ANDROID_CONTROL_AE_STATE_INACTIVE,
+
+ ANDROID_CONTROL_AE_STATE_SEARCHING,
+
+ ANDROID_CONTROL_AE_STATE_CONVERGED,
+
+ ANDROID_CONTROL_AE_STATE_LOCKED,
+
+ ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED,
+
+ ANDROID_CONTROL_AE_STATE_PRECAPTURE,
+
+};
+
+enum CameraMetadataEnumAndroidControlAfState : uint32_t {
+ ANDROID_CONTROL_AF_STATE_INACTIVE,
+
+ ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN,
+
+ ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED,
+
+ ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN,
+
+ ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED,
+
+ ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED,
+
+ ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED,
+
+};
+
+enum CameraMetadataEnumAndroidControlAwbState : uint32_t {
+ ANDROID_CONTROL_AWB_STATE_INACTIVE,
+
+ ANDROID_CONTROL_AWB_STATE_SEARCHING,
+
+ ANDROID_CONTROL_AWB_STATE_CONVERGED,
+
+ ANDROID_CONTROL_AWB_STATE_LOCKED,
+
+};
+
+enum CameraMetadataEnumAndroidControlAeLockAvailable : uint32_t {
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE,
+
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE,
+
+};
+
+enum CameraMetadataEnumAndroidControlAwbLockAvailable : uint32_t {
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE,
+
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE,
+
+};
+
+enum CameraMetadataEnumAndroidControlEnableZsl : uint32_t {
+ ANDROID_CONTROL_ENABLE_ZSL_FALSE,
+
+ ANDROID_CONTROL_ENABLE_ZSL_TRUE,
+
+};
+
+enum CameraMetadataEnumAndroidDemosaicMode : uint32_t {
+ ANDROID_DEMOSAIC_MODE_FAST,
+
+ ANDROID_DEMOSAIC_MODE_HIGH_QUALITY,
+
+};
+
+enum CameraMetadataEnumAndroidEdgeMode : uint32_t {
+ ANDROID_EDGE_MODE_OFF,
+
+ ANDROID_EDGE_MODE_FAST,
+
+ ANDROID_EDGE_MODE_HIGH_QUALITY,
+
+ ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG,
+
+};
+
+enum CameraMetadataEnumAndroidFlashMode : uint32_t {
+ ANDROID_FLASH_MODE_OFF,
+
+ ANDROID_FLASH_MODE_SINGLE,
+
+ ANDROID_FLASH_MODE_TORCH,
+
+};
+
+enum CameraMetadataEnumAndroidFlashState : uint32_t {
+ ANDROID_FLASH_STATE_UNAVAILABLE,
+
+ ANDROID_FLASH_STATE_CHARGING,
+
+ ANDROID_FLASH_STATE_READY,
+
+ ANDROID_FLASH_STATE_FIRED,
+
+ ANDROID_FLASH_STATE_PARTIAL,
+
+};
+
+enum CameraMetadataEnumAndroidFlashInfoAvailable : uint32_t {
+ ANDROID_FLASH_INFO_AVAILABLE_FALSE,
+
+ ANDROID_FLASH_INFO_AVAILABLE_TRUE,
+
+};
+
+enum CameraMetadataEnumAndroidHotPixelMode : uint32_t {
+ ANDROID_HOT_PIXEL_MODE_OFF,
+
+ ANDROID_HOT_PIXEL_MODE_FAST,
+
+ ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY,
+
+};
+
+enum CameraMetadataEnumAndroidLensOpticalStabilizationMode : uint32_t {
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,
+
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidLensFacing : uint32_t {
+ ANDROID_LENS_FACING_FRONT,
+
+ ANDROID_LENS_FACING_BACK,
+
+ ANDROID_LENS_FACING_EXTERNAL,
+
+};
+
+enum CameraMetadataEnumAndroidLensState : uint32_t {
+ ANDROID_LENS_STATE_STATIONARY,
+
+ ANDROID_LENS_STATE_MOVING,
+
+};
+
+enum CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration : uint32_t {
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED,
+
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE,
+
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED,
+
+};
+
+enum CameraMetadataEnumAndroidNoiseReductionMode : uint32_t {
+ ANDROID_NOISE_REDUCTION_MODE_OFF,
+
+ ANDROID_NOISE_REDUCTION_MODE_FAST,
+
+ ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY,
+
+ ANDROID_NOISE_REDUCTION_MODE_MINIMAL,
+
+ ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG,
+
+};
+
+enum CameraMetadataEnumAndroidQuirksPartialResult : uint32_t {
+ ANDROID_QUIRKS_PARTIAL_RESULT_FINAL,
+
+ ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL,
+
+};
+
+enum CameraMetadataEnumAndroidRequestMetadataMode : uint32_t {
+ ANDROID_REQUEST_METADATA_MODE_NONE,
+
+ ANDROID_REQUEST_METADATA_MODE_FULL,
+
+};
+
+enum CameraMetadataEnumAndroidRequestType : uint32_t {
+ ANDROID_REQUEST_TYPE_CAPTURE,
+
+ ANDROID_REQUEST_TYPE_REPROCESS,
+
+};
+
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities : uint32_t {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
+
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO,
+
+};
+
+enum CameraMetadataEnumAndroidScalerAvailableFormats : uint32_t {
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 = 0x20,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE = 0x24,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_YV12 = 0x32315659,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP = 0x11,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED = 0x22,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 = 0x23,
+
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB = 0x21,
+
+};
+
+enum CameraMetadataEnumAndroidScalerAvailableStreamConfigurations : uint32_t {
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+
+};
+
+enum CameraMetadataEnumAndroidScalerCroppingType : uint32_t {
+ ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY,
+
+ ANDROID_SCALER_CROPPING_TYPE_FREEFORM,
+
+};
+
+enum CameraMetadataEnumAndroidSensorReferenceIlluminant1 : uint32_t {
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT = 1,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT = 2,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN = 3,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLASH = 4,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER = 9,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_SHADE = 11,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT = 12,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT = 13,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT = 15,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A = 17,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B = 18,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C = 19,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D55 = 20,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D65 = 21,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D75 = 22,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D50 = 23,
+
+ ANDROID_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN = 24,
+
+};
+
+enum CameraMetadataEnumAndroidSensorTestPatternMode : uint32_t {
+ ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE_PN9,
+
+ ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
+
+};
+
+enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement : uint32_t {
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
+
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
+
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
+
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR,
+
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB,
+
+};
+
+enum CameraMetadataEnumAndroidSensorInfoTimestampSource : uint32_t {
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN,
+
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME,
+
+};
+
+enum CameraMetadataEnumAndroidSensorInfoLensShadingApplied : uint32_t {
+ ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_FALSE,
+
+ ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_TRUE,
+
+};
+
+enum CameraMetadataEnumAndroidShadingMode : uint32_t {
+ ANDROID_SHADING_MODE_OFF,
+
+ ANDROID_SHADING_MODE_FAST,
+
+ ANDROID_SHADING_MODE_HIGH_QUALITY,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsFaceDetectMode : uint32_t {
+ ANDROID_STATISTICS_FACE_DETECT_MODE_OFF,
+
+ ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE,
+
+ ANDROID_STATISTICS_FACE_DETECT_MODE_FULL,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsHistogramMode : uint32_t {
+ ANDROID_STATISTICS_HISTOGRAM_MODE_OFF,
+
+ ANDROID_STATISTICS_HISTOGRAM_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsSharpnessMapMode : uint32_t {
+ ANDROID_STATISTICS_SHARPNESS_MAP_MODE_OFF,
+
+ ANDROID_STATISTICS_SHARPNESS_MAP_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsHotPixelMapMode : uint32_t {
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF,
+
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsSceneFlicker : uint32_t {
+ ANDROID_STATISTICS_SCENE_FLICKER_NONE,
+
+ ANDROID_STATISTICS_SCENE_FLICKER_50HZ,
+
+ ANDROID_STATISTICS_SCENE_FLICKER_60HZ,
+
+};
+
+enum CameraMetadataEnumAndroidStatisticsLensShadingMapMode : uint32_t {
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF,
+
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON,
+
+};
+
+enum CameraMetadataEnumAndroidTonemapMode : uint32_t {
+ ANDROID_TONEMAP_MODE_CONTRAST_CURVE,
+
+ ANDROID_TONEMAP_MODE_FAST,
+
+ ANDROID_TONEMAP_MODE_HIGH_QUALITY,
+
+ ANDROID_TONEMAP_MODE_GAMMA_VALUE,
+
+ ANDROID_TONEMAP_MODE_PRESET_CURVE,
+
+};
+
+enum CameraMetadataEnumAndroidTonemapPresetCurve : uint32_t {
+ ANDROID_TONEMAP_PRESET_CURVE_SRGB,
+
+ ANDROID_TONEMAP_PRESET_CURVE_REC709,
+
+};
+
+enum CameraMetadataEnumAndroidLedTransmit : uint32_t {
+ ANDROID_LED_TRANSMIT_OFF,
+
+ ANDROID_LED_TRANSMIT_ON,
+
+};
+
+enum CameraMetadataEnumAndroidLedAvailableLeds : uint32_t {
+ ANDROID_LED_AVAILABLE_LEDS_TRANSMIT,
+
+};
+
+enum CameraMetadataEnumAndroidInfoSupportedHardwareLevel : uint32_t {
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3,
+
+};
+
+enum CameraMetadataEnumAndroidBlackLevelLock : uint32_t {
+ ANDROID_BLACK_LEVEL_LOCK_OFF,
+
+ ANDROID_BLACK_LEVEL_LOCK_ON,
+
+};
+
+enum CameraMetadataEnumAndroidSyncFrameNumber : uint32_t {
+ ANDROID_SYNC_FRAME_NUMBER_CONVERGING = -1,
+
+ ANDROID_SYNC_FRAME_NUMBER_UNKNOWN = -2,
+
+};
+
+enum CameraMetadataEnumAndroidSyncMaxLatency : uint32_t {
+ ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL = 0,
+
+ ANDROID_SYNC_MAX_LATENCY_UNKNOWN = -1,
+
+};
+
+enum CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations : uint32_t {
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_INPUT,
+
+};
+
+enum CameraMetadataEnumAndroidDepthDepthIsExclusive : uint32_t {
+ ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE,
+
+ ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE,
+
+};
diff --git a/camera/metadata/README.md b/camera/metadata/README.md
new file mode 100644
index 0000000..752973d
--- /dev/null
+++ b/camera/metadata/README.md
@@ -0,0 +1,19 @@
+## Camera Metadata Interface ##
+---
+
+## Overview: ##
+
+The camera.metadata interface is used by the Android camera service,
+camera provider and camera devices to retrieve static camera information and issue
+camera capture controls.
+
+See the docs.html for each version for the detailed description of each metadata
+specification.
+## Version history: ##
+
+### @3.2:
+
+HIDL version of the baseline camera metadata interface, required by
+camera.provider@2.4 and camera.device@3.2 onwards.
+
+
diff --git a/camera/provider/2.4/Android.bp b/camera/provider/2.4/Android.bp
new file mode 100644
index 0000000..1656325
--- /dev/null
+++ b/camera/provider/2.4/Android.bp
@@ -0,0 +1,76 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.camera.provider@2.4_hal",
+ srcs: [
+ "ICameraProvider.hal",
+ "ICameraProviderCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.provider@2.4_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.provider@2.4",
+ srcs: [
+ ":android.hardware.camera.provider@2.4_hal",
+ ],
+ out: [
+ "android/hardware/camera/provider/2.4/CameraProviderAll.cpp",
+ "android/hardware/camera/provider/2.4/CameraProviderCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.camera.provider@2.4_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.provider@2.4",
+ srcs: [
+ ":android.hardware.camera.provider@2.4_hal",
+ ],
+ out: [
+ "android/hardware/camera/provider/2.4/ICameraProvider.h",
+ "android/hardware/camera/provider/2.4/IHwCameraProvider.h",
+ "android/hardware/camera/provider/2.4/BnHwCameraProvider.h",
+ "android/hardware/camera/provider/2.4/BpHwCameraProvider.h",
+ "android/hardware/camera/provider/2.4/BsCameraProvider.h",
+ "android/hardware/camera/provider/2.4/ICameraProviderCallback.h",
+ "android/hardware/camera/provider/2.4/IHwCameraProviderCallback.h",
+ "android/hardware/camera/provider/2.4/BnHwCameraProviderCallback.h",
+ "android/hardware/camera/provider/2.4/BpHwCameraProviderCallback.h",
+ "android/hardware/camera/provider/2.4/BsCameraProviderCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.provider@2.4",
+ generated_sources: ["android.hardware.camera.provider@2.4_genc++"],
+ generated_headers: ["android.hardware.camera.provider@2.4_genc++_headers"],
+ export_generated_headers: ["android.hardware.camera.provider@2.4_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
new file mode 100644
index 0000000..3015b7d
--- /dev/null
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 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.camera.provider@2.4;
+
+import ICameraProviderCallback;
+import android.hardware.camera.common@1.0::types;
+import android.hardware.camera.device@1.0::ICameraDevice;
+import android.hardware.camera.device@3.2::ICameraDevice;
+
+/**
+ * Camera provider HAL, which enumerates the available individual camera devices
+ * known to the provider, and provides updates about changes to device status,
+ * such as connection, disconnection, or torch mode enable/disable.
+ *
+ * The provider is responsible for generating a list of camera device service
+ * names that can then be opened via the hardware service manager.
+ *
+ * Multiple camera provider HALs may be present in a single system.
+ * For discovery, the service names, and process names, must be of the form
+ * "android.hardware.camera.provider@<major>.<minor>/<type>/<instance>"
+ * where
+ * - <major>/<minor> is the provider HAL HIDL version,
+ * - <type> is the type of devices this provider knows about, such as
+ * "internal", "legacy", "usb", or "remote"
+ * - <instance> is a non-negative integer starting from 0 to disambiguate
+ * between multiple HALs of the same type.
+ *
+ * The "legacy" type is only used for passthrough legacy HAL mode, and must
+ * not be used by a standalone binderized HAL.
+ *
+ * The device instance names enumerated by the provider must be of the form
+ * "device@<major>.<minor>/<type>/<id>" where
+ * <major>/<minor> is the HIDL version of the interface. <id> is either a small
+ * incrementing integer for "internal" device types, with 0 being the main
+ * back-facing camera and 1 being the main front-facing camera, if they exist.
+ * Or, for external devices such as type "usb", a unique serial number that can
+ * be used to identify the device reliably when it is disconnected and
+ * reconnected. Multiple providers may not enumerate the same device ID.
+ *
+ */
+interface ICameraProvider {
+
+ /**
+ * setCallback:
+ *
+ * Provide a callback interface to the HAL provider to inform framework of
+ * asynchronous camera events. The framework must call this function once
+ * during camera service startup, before any other calls to the provider
+ * (note that in case the camera service restarts, this method must be
+ * invoked again during its startup).
+ *
+ * @param callback
+ * A non-null callback interface to invoke when camera events occur.
+ * @return status
+ * Status code for the operation, one of:
+ * OK:
+ * On success
+ * INTERNAL_ERROR:
+ * An unexpected internal error occurred while setting the callbacks
+ * ILLEGAL_ARGUMENT:
+ * The callback argument is invalid (for example, null).
+ *
+ */
+ setCallback(ICameraProviderCallback callback) generates (Status status);
+
+ /**
+ * getVendorTags:
+ *
+ * Retrieve all vendor tags supported by devices discoverable through this
+ * provider. The tags are grouped into sections.
+ *
+ * @return status
+ * Status code for the operation, one of:
+ * OK:
+ * On success
+ * INTERNAL_ERROR:
+ * An unexpected internal error occurred while setting the callbacks
+ * @return sections
+ * The supported vendor tag sections; empty if there are no supported
+ * vendor tags, or status is not OK.
+ *
+ */
+ getVendorTags() generates (Status status, vec<VendorTagSection> sections);
+
+ /**
+ * getCameraDeviceList:
+ *
+ * Returns the list of internal camera device interfaces known to this
+ * camera provider. These devices can then be accessed via the hardware
+ * service manager.
+ *
+ * External camera devices (camera facing EXTERNAL) must be reported through
+ * the device status change callback, not in this list. Only devices with
+ * facing BACK or FRONT must be listed here.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a succesful generation of camera ID list
+ * INTERNAL_ERROR:
+ * A camera ID list cannot be created. This may be due to
+ * a failure to initialize the camera subsystem, for example.
+ * @return cameraDeviceServiceNames The vector of internal camera device
+ * names known to this provider.
+ */
+ getCameraIdList()
+ generates (Status status, vec<string> cameraDeviceNames);
+
+ /**
+ * isSetTorchModeSupported:
+ *
+ * Returns if the camera devices known to this camera provider support
+ * setTorchMode API or not. If the provider does not support setTorchMode
+ * API, calling to setTorchMode will return METHOD_NOT_SUPPORTED.
+ *
+ * Note that not every camera device has a flash unit, so even this API
+ * returns true, setTorchMode call might still fail due to the camera device
+ * does not have a flash unit. In such case, the returned status will be
+ * OPERATION_NOT_SUPPORTED.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a succesful call
+ * INTERNAL_ERROR:
+ * Torch API support cannot be queried. This may be due to
+ * a failure to initialize the camera subsystem, for example.
+ * @return support Whether the camera devices known to this provider
+ * supports setTorchMode API or not.
+ *
+ */
+ isSetTorchModeSupported() generates (Status status, bool support);
+
+ /**
+ * getCameraDeviceInterface_VN_x:
+ *
+ * Return a android.hardware.camera.device@N.x/ICameraDevice interface for
+ * the requested device name. This does not power on the camera device, but
+ * simply acquires the interface for querying the device static information,
+ * or to additionally open the device for active use.
+ *
+ * A separate method is required for each major revision of the camera device
+ * HAL interface, since they are not compatible with each other.
+ *
+ * Valid device names for this provider can be obtained via either
+ * getCameraIdList(), or via availability callbacks from
+ * ICameraProviderCallback::cameraDeviceStatusChange().
+ *
+ * The returned interface must be of the highest defined minor version for
+ * the major version; it's the responsibility of the HAL client to ensure
+ * they do not use methods/etc that are not valid for the actual minor
+ * version of the device.
+ *
+ * @param cameraDeviceName the name of the device to get an interface to.
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a succesful generation of camera ID list
+ * ILLEGAL_ARGUMENT:
+ * This device name is unknown, or has been disconnected
+ * OPERATION_NOT_SUPPORTED:
+ * The specified device does not support this major version of the
+ * HAL interface.
+ * INTERNAL_ERROR:
+ * A camera interface cannot be returned due to an unexpected
+ * internal error.
+ * @return device The inteface to this camera device, or null in case of
+ * error.
+ */
+ getCameraDeviceInterface_V1_x(string cameraDeviceName) generates
+ (Status status,
+ android.hardware.camera.device@1.0::ICameraDevice device);
+ getCameraDeviceInterface_V3_x(string cameraDeviceName) generates
+ (Status status,
+ android.hardware.camera.device@3.2::ICameraDevice device);
+
+};
diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal
new file mode 100644
index 0000000..63dd3c5
--- /dev/null
+++ b/camera/provider/2.4/ICameraProviderCallback.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.camera.provider@2.4;
+
+import android.hardware.camera.common@1.0::types;
+
+/**
+ * Callback functions for a camera provider HAL to use to inform the camera
+ * service of changes to the camera subsystem.
+ */
+interface ICameraProviderCallback {
+
+ /**
+ * cameraDeviceStatusChange:
+ *
+ * Callback to the camera service to indicate that the state of a specific
+ * camera device has changed.
+ *
+ * On camera service startup, when ICameraProvider::setCallback is invoked,
+ * the camera service must assume that all internal camera devices are in
+ * the CAMERA_DEVICE_STATUS_PRESENT state.
+ *
+ * The provider must call this method to inform the camera service of any
+ * initially NOT_PRESENT devices, and of any external camera devices that
+ * are already present, as soon as the callbacks are available through
+ * setCallback.
+ *
+ * @param cameraDeviceServiceName The name of the camera device that has a
+ * new status.
+ * @param newStatus The new status that device is in.
+ *
+ */
+ cameraDeviceStatusChange(string cameraDeviceName,
+ CameraDeviceStatus newStatus);
+
+ /**
+ * torchModeStatusChange:
+ *
+ * Callback to the camera service to indicate that the state of the torch
+ * mode of the flash unit associated with a specific camera device has
+ * changed. At provider registration time, the camera service must assume
+ * the torch modes are in the TORCH_MODE_STATUS_AVAILABLE_OFF state if
+ * android.flash.info.available is reported as true via the
+ * ICameraDevice::getCameraCharacteristics call.
+ *
+ * @param cameraDeviceServiceName The name of the camera device that has a
+ * new status.
+ * @param newStatus The new status that device is in.
+ *
+ */
+ torchModeStatusChange(string cameraDeviceName,
+ TorchModeStatus newStatus);
+
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
new file mode 100644
index 0000000..42dec4d
--- /dev/null
+++ b/camera/provider/2.4/default/Android.bp
@@ -0,0 +1,45 @@
+cc_library_shared {
+ name: "android.hardware.camera.provider@2.4-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["CameraProvider.cpp"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "camera.device@1.0-impl",
+ "camera.device@3.2-impl",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.common@1.0",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper"
+ ]
+}
+
+cc_binary {
+ name: "android.hardware.camera.provider@2.4-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ compile_multilib: "32",
+ init_rc: ["android.hardware.camera.provider@2.4-service.rc"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.common@1.0",
+ ],
+}
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
new file mode 100644
index 0000000..8701ec1
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "CamProvider@2.4-impl"
+#include <android/log.h>
+
+#include "CameraProvider.h"
+#include "CameraDevice_1_0.h"
+#include "CameraDevice_3_2.h"
+#include <string.h>
+#include <utils/Trace.h>
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+namespace {
+const char *kLegacyProviderName = "legacy/0";
+// "device@<version>/legacy/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
+const char *kHAL3_2 = "3.2";
+const char *kHAL1_0 = "1.0";
+const int kMaxCameraDeviceNameLen = 128;
+const int kMaxCameraIdLen = 16;
+
+} // anonymous namespace
+
+using ::android::hardware::camera::common::V1_0::CameraMetadataType;
+using ::android::hardware::camera::common::V1_0::Status;
+
+/**
+ * static callback forwarding methods from HAL to instance
+ */
+void CameraProvider::sCameraDeviceStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ int camera_id,
+ int new_status) {
+ CameraProvider* cp = const_cast<CameraProvider*>(
+ static_cast<const CameraProvider*>(callbacks));
+
+ if (cp == nullptr) {
+ ALOGE("%s: callback ops is null", __FUNCTION__);
+ return;
+ }
+
+ Mutex::Autolock _l(cp->mCbLock);
+ char cameraId[kMaxCameraIdLen];
+ snprintf(cameraId, sizeof(cameraId), "%d", camera_id);
+ std::string cameraIdStr(cameraId);
+ cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status;
+ if (cp->mCallbacks != nullptr) {
+ CameraDeviceStatus status = (CameraDeviceStatus) new_status;
+ for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+ if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+ cp->mCallbacks->cameraDeviceStatusChange(
+ deviceNamePair.second, status);
+ }
+ }
+ }
+}
+
+void CameraProvider::sTorchModeStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status) {
+ CameraProvider* cp = const_cast<CameraProvider*>(
+ static_cast<const CameraProvider*>(callbacks));
+
+ if (cp == nullptr) {
+ ALOGE("%s: callback ops is null", __FUNCTION__);
+ return;
+ }
+
+ Mutex::Autolock _l(cp->mCbLock);
+ if (cp->mCallbacks != nullptr) {
+ std::string cameraIdStr(camera_id);
+ TorchModeStatus status = (TorchModeStatus) new_status;
+ for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+ if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+ cp->mCallbacks->torchModeStatusChange(
+ deviceNamePair.second, status);
+ }
+ }
+ }
+}
+
+Status CameraProvider::getHidlStatus(int status) {
+ switch (status) {
+ case 0: return Status::OK;
+ case -ENODEV: return Status::INTERNAL_ERROR;
+ case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+ default:
+ ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+ return Status::INTERNAL_ERROR;
+ }
+}
+
+bool CameraProvider::matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+ std::string deviceNameStd(deviceName.c_str());
+ return std::regex_match(deviceNameStd, sm, kDeviceNameRE);
+}
+
+std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return std::string("");
+ }
+ return sm[2];
+}
+
+int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return -1;
+ }
+ if (sm[1].compare(kHAL3_2) == 0) {
+ // maybe switched to 3.4 or define the hidl version enum later
+ return CAMERA_DEVICE_API_VERSION_3_2;
+ } else if (sm[1].compare(kHAL1_0) == 0) {
+ return CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ return 0;
+}
+
+std::string CameraProvider::getHidlDeviceName(
+ std::string cameraId, int deviceVersion) {
+ // Maybe consider create a version check method and SortedVec to speed up?
+ if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) {
+ return hidl_string("");
+ }
+ const char* versionStr = (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) ? kHAL1_0 : kHAL3_2;
+ char deviceName[kMaxCameraDeviceNameLen];
+ snprintf(deviceName, sizeof(deviceName), "device@%s/legacy/%s",
+ versionStr, cameraId.c_str());
+ return deviceName;
+}
+
+CameraProvider::CameraProvider() :
+ camera_module_callbacks_t({sCameraDeviceStatusChange,
+ sTorchModeStatusChange}) {
+ mInitFailed = initialize();
+}
+
+CameraProvider::~CameraProvider() {}
+
+bool CameraProvider::initialize() {
+ camera_module_t *rawModule;
+ int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&rawModule);
+ if (err < 0) {
+ ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
+ return true;
+ }
+
+ mModule = new CameraModule(rawModule);
+ err = mModule->init();
+ if (err != OK) {
+ ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err));
+ mModule.clear();
+ return true;
+ }
+ ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
+
+ // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ if (!setUpVendorTags()) {
+ ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);
+ }
+
+ // Setup callback now because we are going to try openLegacy next
+ err = mModule->setCallbacks(this);
+ if (err != OK) {
+ ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err));
+ mModule.clear();
+ return true;
+ }
+
+ mNumberOfLegacyCameras = mModule->getNumberOfCameras();
+ for (int i = 0; i < mNumberOfLegacyCameras; i++) {
+ char cameraId[kMaxCameraIdLen];
+ snprintf(cameraId, sizeof(cameraId), "%d", i);
+ std::string cameraIdStr(cameraId);
+ mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
+ mCameraIds.add(cameraIdStr);
+
+ // initialize mCameraDeviceNames and mOpenLegacySupported
+ mOpenLegacySupported[cameraIdStr] = false;
+ int deviceVersion = mModule->getDeviceVersion(i);
+ mCameraDeviceNames.add(
+ std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, deviceVersion)));
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+ mModule->isOpenLegacyDefined()) {
+ // try open_legacy to see if it actually works
+ struct hw_device_t* halDev = nullptr;
+ int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
+ if (ret == 0) {
+ mOpenLegacySupported[cameraIdStr] = true;
+ halDev->close(halDev);
+ mCameraDeviceNames.add(
+ std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
+ } else if (ret == -EBUSY || ret == -EUSERS) {
+ // Looks like this provider instance is not initialized during
+ // system startup and there are other camera users already.
+ // Not a good sign but not fatal.
+ ALOGW("%s: open_legacy try failed!", __FUNCTION__);
+ }
+ }
+ }
+
+ return false; // mInitFailed
+}
+
+bool CameraProvider::setUpVendorTags() {
+ ATRACE_CALL();
+ vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+ // Check if vendor operations have been implemented
+ if (!mModule->isVendorTagDefined()) {
+ ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
+ return true;
+ }
+
+ mModule->getVendorTagOps(&vOps);
+
+ // Ensure all vendor operations are present
+ if (vOps.get_tag_count == nullptr || vOps.get_all_tags == nullptr ||
+ vOps.get_section_name == nullptr || vOps.get_tag_name == nullptr ||
+ vOps.get_tag_type == nullptr) {
+ ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+ , __FUNCTION__);
+ return false;
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ sp<VendorTagDescriptor> desc;
+ status_t res;
+ if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return false;
+ }
+
+ // Set the global descriptor to use with camera metadata
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ const SortedVector<String8>* sectionNames = desc->getAllSectionNames();
+ size_t numSections = sectionNames->size();
+ std::vector<std::vector<VendorTag>> tagsBySection(numSections);
+ int tagCount = desc->getTagCount();
+ std::vector<uint32_t> tags(tagCount);
+ desc->getTagArray(tags.data());
+ for (int i = 0; i < tagCount; i++) {
+ VendorTag vt;
+ vt.tagId = tags[i];
+ vt.tagName = desc->getTagName(tags[i]);
+ vt.tagType = (CameraMetadataType) desc->getTagType(tags[i]);
+ ssize_t sectionIdx = desc->getSectionIndex(tags[i]);
+ tagsBySection[sectionIdx].push_back(vt);
+ }
+ mVendorTagSections.resize(numSections);
+ for (size_t s = 0; s < numSections; s++) {
+ mVendorTagSections[s].sectionName = (*sectionNames)[s].string();
+ mVendorTagSections[s].tags = tagsBySection[s];
+ }
+ return true;
+}
+
+// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback) {
+ Mutex::Autolock _l(mCbLock);
+ mCallbacks = callback;
+ return Status::OK;
+}
+
+Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
+ _hidl_cb(Status::OK, mVendorTagSections);
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
+ std::vector<hidl_string> deviceNameList;
+ for (auto const& deviceNamePair : mCameraDeviceNames) {
+ if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) {
+ deviceNameList.push_back(deviceNamePair.second);
+ }
+ }
+ hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
+ _hidl_cb(Status::OK, hidlDeviceNameList);
+ return Void();
+}
+
+Return<void> CameraProvider::isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) {
+ bool support = mModule->isSetTorchModeSupported();
+ _hidl_cb (Status::OK, support);
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V1_x(
+ const hidl_string& cameraDeviceName, getCameraDeviceInterface_V1_x_cb _hidl_cb) {
+ std::smatch sm;
+ bool match = matchDeviceName(cameraDeviceName, sm);
+ if (!match) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ std::string cameraId = sm[2];
+ std::string deviceVersion = sm[1];
+ std::string deviceName(cameraDeviceName.c_str());
+ ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
+ if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
+ Status status = Status::OK;
+ ssize_t idx = mCameraIds.indexOf(cameraId);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str());
+ status = Status::ILLEGAL_ARGUMENT;
+ } else { // invalid version
+ ALOGE("%s: camera device %s does not support version %s!",
+ __FUNCTION__, cameraId.c_str(), deviceVersion.c_str());
+ status = Status::OPERATION_NOT_SUPPORTED;
+ }
+ _hidl_cb(status, nullptr);
+ return Void();
+ }
+
+ if (mCameraStatusMap.count(cameraId) == 0 ||
+ mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ sp<android::hardware::camera::device::V1_0::implementation::CameraDevice> device =
+ new android::hardware::camera::device::V1_0::implementation::CameraDevice(
+ mModule, cameraId, mCameraDeviceNames);
+
+ if (device == nullptr) {
+ ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str());
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ if (device->isInitFailed()) {
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+ device = nullptr;
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ _hidl_cb (Status::OK, device);
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
+ const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) {
+ std::smatch sm;
+ bool match = matchDeviceName(cameraDeviceName, sm);
+ if (!match) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ std::string cameraId = sm[2];
+ std::string deviceVersion = sm[1];
+ std::string deviceName(cameraDeviceName.c_str());
+ ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
+ if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
+ Status status = Status::OK;
+ ssize_t idx = mCameraIds.indexOf(cameraId);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str());
+ status = Status::ILLEGAL_ARGUMENT;
+ } else { // invalid version
+ ALOGE("%s: camera device %s does not support version %s!",
+ __FUNCTION__, cameraId.c_str(), deviceVersion.c_str());
+ status = Status::OPERATION_NOT_SUPPORTED;
+ }
+ _hidl_cb(status, nullptr);
+ return Void();
+ }
+
+ if (mCameraStatusMap.count(cameraId) == 0 ||
+ mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ // TODO: we also need to keep a wp list of all generated devices to notify
+ // devices of device present status change, but then each device might
+ // need a sp<provider> to keep provider alive until all device closed?
+ // Problem: do we have external camera products to test this?
+ sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device =
+ new android::hardware::camera::device::V3_2::implementation::CameraDevice(
+ mModule, cameraId, mCameraDeviceNames);
+
+ if (device == nullptr) {
+ ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str());
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ if (device->isInitFailed()) {
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+ device = nullptr;
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ _hidl_cb (Status::OK, device);
+ return Void();
+}
+
+ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
+ if (strcmp(name, kLegacyProviderName) != 0) {
+ return nullptr;
+ }
+ CameraProvider* provider = new CameraProvider();
+ if (provider == nullptr) {
+ ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
+ return nullptr;
+ }
+ if (provider->isInitFailed()) {
+ ALOGE("%s: camera provider init failed!", __FUNCTION__);
+ delete provider;
+ return nullptr;
+ }
+ return provider;
+}
+
+} // namespace implementation
+} // namespace V2_4
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
new file mode 100644
index 0000000..2a43e2f
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+
+#include <regex>
+#include "hardware/camera_common.h"
+#include "utils/Mutex.h"
+#include "utils/SortedVector.h"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include "CameraModule.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::common::V1_0::VendorTag;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t {
+ CameraProvider();
+ ~CameraProvider();
+
+ // Caller must use this method to check if CameraProvider ctor failed
+ bool isInitFailed() { return mInitFailed; }
+
+ // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+ Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override;
+ Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override;
+ Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override;
+ Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override;
+ Return<void> getCameraDeviceInterface_V1_x(
+ const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V1_x_cb _hidl_cb) override;
+ Return<void> getCameraDeviceInterface_V3_x(
+ const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V3_x_cb _hidl_cb) override;
+
+private:
+ Mutex mCbLock;
+ sp<ICameraProviderCallback> mCallbacks = nullptr;
+
+ sp<CameraModule> mModule;
+
+ int mNumberOfLegacyCameras;
+ std::map<std::string, camera_device_status_t> mCameraStatusMap; // camera id -> status
+ std::map<std::string, bool> mOpenLegacySupported; // camera id -> open_legacy HAL1.0 supported
+ SortedVector<std::string> mCameraIds; // the "0"/"1" legacy camera Ids
+ // (cameraId string, hidl device name) pairs
+ SortedVector<std::pair<std::string, std::string>> mCameraDeviceNames;
+
+ // Must be queried before using any APIs.
+ // APIs will only work when this returns true
+ bool mInitFailed;
+ bool initialize();
+
+ hidl_vec<VendorTagSection> mVendorTagSections;
+ bool setUpVendorTags();
+
+ // extract legacy camera ID/device version from a HIDL device name
+ static bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm);
+ static std::string getLegacyCameraId(const hidl_string& deviceName);
+ static int getCameraDeviceVersion(const hidl_string& deviceName);
+
+ // create HIDL device name from camera ID and device version
+ static std::string getHidlDeviceName(std::string cameraId, int deviceVersion);
+
+ // convert conventional HAL status to HIDL Status
+ static Status getHidlStatus(int);
+
+ // static callback forwarding methods
+ static void sCameraDeviceStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ int camera_id,
+ int new_status);
+ static void sTorchModeStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status);
+};
+
+extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name);
+
+} // namespace implementation
+} // namespace V2_4
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
new file mode 100644
index 0000000..192870b
--- /dev/null
+++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
@@ -0,0 +1,6 @@
+service camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service
+ class hal
+ user cameraserver
+ group audio camera input drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
\ No newline at end of file
diff --git a/camera/provider/2.4/default/service.cpp b/camera/provider/2.4/default/service.cpp
new file mode 100644
index 0000000..df2602e
--- /dev/null
+++ b/camera/provider/2.4/default/service.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#define LOG_TAG "android.hardware.camera.provider@2.4-service"
+
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::camera::provider::V2_4::ICameraProvider;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main()
+{
+ ALOGI("Camera provider Service is starting.");
+ return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", /*maxThreads*/ 6);
+}
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..a0be5cb
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalCameraProviderV2_4TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp",
+ "CameraParameters.cpp" ],
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libcutils",
+ "libutils",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@1.0",
+ "libcamera_metadata",
+ "libbinder",
+ "libgui",
+ "libui"
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.cpp b/camera/provider/2.4/vts/functional/CameraParameters.cpp
new file mode 100644
index 0000000..0285154
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/CameraParameters.cpp
@@ -0,0 +1,537 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#define LOG_TAG "CameraParams"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "CameraParameters.h"
+#include <system/graphics.h>
+
+namespace android {
+// Parameter keys to communicate between camera application and driver.
+const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
+const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
+const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
+const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
+const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
+const char CameraParameters::KEY_ROTATION[] = "rotation";
+const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
+const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
+const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
+const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
+const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
+const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
+const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
+const char CameraParameters::KEY_EFFECT[] = "effect";
+const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
+const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
+const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
+const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
+const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
+const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
+const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
+const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
+const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
+const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
+const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
+const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
+const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
+const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
+const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
+const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
+const char CameraParameters::KEY_ZOOM[] = "zoom";
+const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
+const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
+const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
+const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
+const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
+const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
+const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
+const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
+const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
+const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
+const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
+const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
+
+const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
+const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
+
+// Values for white balance settings.
+const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
+const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
+const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
+const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
+const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
+const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
+const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
+const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
+
+// Values for effect settings.
+const char CameraParameters::EFFECT_NONE[] = "none";
+const char CameraParameters::EFFECT_MONO[] = "mono";
+const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
+const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
+const char CameraParameters::EFFECT_SEPIA[] = "sepia";
+const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
+const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
+const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
+const char CameraParameters::EFFECT_AQUA[] = "aqua";
+
+// Values for antibanding settings.
+const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
+const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
+const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
+const char CameraParameters::ANTIBANDING_OFF[] = "off";
+
+// Values for flash mode settings.
+const char CameraParameters::FLASH_MODE_OFF[] = "off";
+const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
+const char CameraParameters::FLASH_MODE_ON[] = "on";
+const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
+const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
+
+// Values for scene mode settings.
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_ACTION[] = "action";
+const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
+const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
+const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
+const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
+const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
+const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
+const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
+const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
+const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
+const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
+const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
+const char CameraParameters::SCENE_MODE_PARTY[] = "party";
+const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode";
+const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
+
+const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
+const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
+const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
+const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
+const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
+const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
+
+// Values for focus mode settings.
+const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
+const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
+const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
+const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
+const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture";
+
+// Values for light fx settings
+const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
+const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range";
+
+CameraParameters::CameraParameters()
+ : mMap()
+{
+}
+
+CameraParameters::~CameraParameters()
+{
+}
+
+String8 CameraParameters::flatten() const
+{
+ String8 flattened("");
+ size_t size = mMap.size();
+
+ for (size_t i = 0; i < size; i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+
+ flattened += k;
+ flattened += "=";
+ flattened += v;
+ if (i != size-1)
+ flattened += ";";
+ }
+
+ return flattened;
+}
+
+void CameraParameters::unflatten(const String8 ¶ms)
+{
+ const char *a = params.string();
+ const char *b;
+
+ mMap.clear();
+
+ for (;;) {
+ // Find the bounds of the key name.
+ b = strchr(a, '=');
+ if (b == 0)
+ break;
+
+ // Create the key string.
+ String8 k(a, (size_t)(b-a));
+
+ // Find the value.
+ a = b+1;
+ b = strchr(a, ';');
+ if (b == 0) {
+ // If there's no semicolon, this is the last item.
+ String8 v(a);
+ mMap.add(k, v);
+ break;
+ }
+
+ String8 v(a, (size_t)(b-a));
+ mMap.add(k, v);
+ a = b+1;
+ }
+}
+
+
+void CameraParameters::set(const char *key, const char *value)
+{
+ // i think i can do this with strspn()
+ if (strchr(key, '=') || strchr(key, ';')) {
+ // ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+ return;
+ }
+
+ if (strchr(value, '=') || strchr(value, ';')) {
+ // ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+ return;
+ }
+
+ mMap.replaceValueFor(String8(key), String8(value));
+}
+
+void CameraParameters::set(const char *key, int value)
+{
+ char str[16];
+ sprintf(str, "%d", value);
+ set(key, str);
+}
+
+void CameraParameters::setFloat(const char *key, float value)
+{
+ char str[16]; // 14 should be enough. We overestimate to be safe.
+ snprintf(str, sizeof(str), "%g", value);
+ set(key, str);
+}
+
+const char *CameraParameters::get(const char *key) const
+{
+ String8 v = mMap.valueFor(String8(key));
+ if (v.length() == 0)
+ return 0;
+ return v.string();
+}
+
+int CameraParameters::getInt(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0)
+ return -1;
+ return strtol(v, 0, 0);
+}
+
+float CameraParameters::getFloat(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0) return -1;
+ return strtof(v, 0);
+}
+
+void CameraParameters::remove(const char *key)
+{
+ mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+ char **endptr = NULL)
+{
+ // Find the first integer.
+ char *end;
+ int w = (int)strtol(str, &end, 10);
+ // If a delimeter does not immediately follow, give up.
+ if (*end != delim) {
+ ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+ return -1;
+ }
+
+ // Find the second integer, immediately after the delimeter.
+ int h = (int)strtol(end+1, &end, 10);
+
+ *first = w;
+ *second = h;
+
+ if (endptr) {
+ *endptr = end;
+ }
+
+ return 0;
+}
+
+static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
+{
+ if (sizesStr == 0) {
+ return;
+ }
+
+ char *sizeStartPtr = (char *)sizesStr;
+
+ while (true) {
+ int width, height;
+ int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+ &sizeStartPtr);
+ if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+ ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+ return;
+ }
+ sizes.push(Size(width, height));
+
+ if (*sizeStartPtr == '\0') {
+ return;
+ }
+ sizeStartPtr++;
+ }
+}
+
+void CameraParameters::setPreviewSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters::getPreviewSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_PREVIEW_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
+{
+ const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
+ parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters::setVideoSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters::getVideoSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_VIDEO_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const
+{
+ const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
+ parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters::setPreviewFrameRate(int fps)
+{
+ set(KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters::getPreviewFrameRate() const
+{
+ return getInt(KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+ *min_fps = *max_fps = -1;
+ const char *p = get(KEY_PREVIEW_FPS_RANGE);
+ if (p == 0) return;
+ parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters::setPreviewFormat(const char *format)
+{
+ set(KEY_PREVIEW_FORMAT, format);
+}
+
+const char *CameraParameters::getPreviewFormat() const
+{
+ return get(KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters::setPictureSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters::getPictureSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_PICTURE_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const
+{
+ const char *pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
+ parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters::setPictureFormat(const char *format)
+{
+ set(KEY_PICTURE_FORMAT, format);
+}
+
+const char *CameraParameters::getPictureFormat() const
+{
+ return get(KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters::dump() const
+{
+ ALOGD("dump: mMap.size = %zu", mMap.size());
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ ALOGD("%s: %s\n", k.string(), v.string());
+ }
+}
+
+status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size());
+ result.append(buffer);
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
+ const char* supportedPreviewFormats =
+ get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+
+ if (supportedPreviewFormats == NULL) {
+ ALOGW("%s: No supported preview formats.", __FUNCTION__);
+ return;
+ }
+
+ String8 fmtStr(supportedPreviewFormats);
+ char* prevFmts = fmtStr.lockBuffer(fmtStr.size());
+
+ char* savePtr;
+ char* fmt = strtok_r(prevFmts, ",", &savePtr);
+ while (fmt) {
+ int actual = previewFormatToEnum(fmt);
+ if (actual != -1) {
+ formats.add(actual);
+ }
+ fmt = strtok_r(NULL, ",", &savePtr);
+ }
+ fmtStr.unlockBuffer(fmtStr.size());
+}
+
+
+int CameraParameters::previewFormatToEnum(const char* format) {
+ return
+ !format ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP :
+ !strcmp(format, PIXEL_FORMAT_YUV422SP) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+ !strcmp(format, PIXEL_FORMAT_YUV420SP) ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+ !strcmp(format, PIXEL_FORMAT_YUV422I) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
+ !strcmp(format, PIXEL_FORMAT_YUV420P) ?
+ HAL_PIXEL_FORMAT_YV12 : // YV12
+ !strcmp(format, PIXEL_FORMAT_RGB565) ?
+ HAL_PIXEL_FORMAT_RGB_565 : // RGB565
+ !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
+ HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
+ !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
+ HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data
+ -1;
+}
+
+bool CameraParameters::isEmpty() const {
+ return mMap.isEmpty();
+}
+
+}; // namespace android
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.h b/camera/provider/2.4/vts/functional/CameraParameters.h
new file mode 100644
index 0000000..ba33ffe
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/CameraParameters.h
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct Size {
+ int width;
+ int height;
+
+ Size() {
+ width = 0;
+ height = 0;
+ }
+
+ Size(int w, int h) {
+ width = w;
+ height = h;
+ }
+};
+
+class CameraParameters
+{
+public:
+ CameraParameters();
+ CameraParameters(const String8 ¶ms) { unflatten(params); }
+ ~CameraParameters();
+
+ String8 flatten() const;
+ void unflatten(const String8 ¶ms);
+
+ void set(const char *key, const char *value);
+ void set(const char *key, int value);
+ void setFloat(const char *key, float value);
+ const char *get(const char *key) const;
+ int getInt(const char *key) const;
+ float getFloat(const char *key) const;
+
+ void remove(const char *key);
+
+ void setPreviewSize(int width, int height);
+ void getPreviewSize(int *width, int *height) const;
+ void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+
+ // Set the dimensions in pixels to the given width and height
+ // for video frames. The given width and height must be one
+ // of the supported dimensions returned from
+ // getSupportedVideoSizes(). Must not be called if
+ // getSupportedVideoSizes() returns an empty Vector of Size.
+ void setVideoSize(int width, int height);
+ // Retrieve the current dimensions (width and height)
+ // in pixels for video frames, which must be one of the
+ // supported dimensions returned from getSupportedVideoSizes().
+ // Must not be called if getSupportedVideoSizes() returns an
+ // empty Vector of Size.
+ void getVideoSize(int *width, int *height) const;
+ // Retrieve a Vector of supported dimensions (width and height)
+ // in pixels for video frames. If sizes returned from the method
+ // is empty, the camera does not support calls to setVideoSize()
+ // or getVideoSize(). In adddition, it also indicates that
+ // the camera only has a single output, and does not have
+ // separate output for video frames and preview frame.
+ void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+
+ void setPreviewFrameRate(int fps);
+ int getPreviewFrameRate() const;
+ void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+ void setPreviewFormat(const char *format);
+ const char *getPreviewFormat() const;
+ void setPictureSize(int width, int height);
+ void getPictureSize(int *width, int *height) const;
+ void getSupportedPictureSizes(Vector<Size> &sizes) const;
+ void setPictureFormat(const char *format);
+ const char *getPictureFormat() const;
+
+ void dump() const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+ /**
+ * Returns a Vector containing the supported preview formats
+ * as enums given in graphics.h.
+ */
+ void getSupportedPreviewFormats(Vector<int>& formats) const;
+
+ // Returns true if no keys are present
+ bool isEmpty() const;
+
+ // Parameter keys to communicate between camera application and driver.
+ // The access (read/write, read only, or write only) is viewed from the
+ // perspective of applications, not driver.
+
+ // Preview frame size in pixels (width x height).
+ // Example value: "480x320". Read/Write.
+ static const char KEY_PREVIEW_SIZE[];
+ // Supported preview frame sizes in pixels.
+ // Example value: "800x600,480x320". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+ // The current minimum and maximum preview fps. This controls the rate of
+ // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
+ // maximum fps must be one of the elements from
+ // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
+ // Example value: "10500,26623"
+ static const char KEY_PREVIEW_FPS_RANGE[];
+ // The supported preview fps (frame-per-second) ranges. Each range contains
+ // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
+ // camera outputs frames in fixed frame rate. If not, the camera outputs
+ // frames in auto frame rate. The actual frame rate fluctuates between the
+ // minimum and the maximum. The list has at least one element. The list is
+ // sorted from small to large (first by maximum fps and then minimum fps).
+ // Example value: "(10500,26623),(15000,26623),(30000,30000)"
+ static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
+ // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
+ // frameworks/av/include/camera/Camera.h. The default is
+ // PIXEL_FORMAT_YUV420SP. Example value: "yuv420sp" or PIXEL_FORMAT_XXX
+ // constants. Read/write.
+ static const char KEY_PREVIEW_FORMAT[];
+ // Supported image formats for preview frames.
+ // Example value: "yuv420sp,yuv422i-yuyv". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
+ // Number of preview frames per second. This is the target frame rate. The
+ // actual frame rate depends on the driver.
+ // Example value: "15". Read/write.
+ static const char KEY_PREVIEW_FRAME_RATE[];
+ // Supported number of preview frames per second.
+ // Example value: "24,15,10". Read.
+ static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
+ // The dimensions for captured pictures in pixels (width x height).
+ // Example value: "1024x768". Read/write.
+ static const char KEY_PICTURE_SIZE[];
+ // Supported dimensions for captured pictures in pixels.
+ // Example value: "2048x1536,1024x768". Read only.
+ static const char KEY_SUPPORTED_PICTURE_SIZES[];
+ // The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
+ // in frameworks/base/include/camera/Camera.h.
+ // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
+ static const char KEY_PICTURE_FORMAT[];
+ // Supported image formats for captured pictures.
+ // Example value: "jpeg,rgb565". Read only.
+ static const char KEY_SUPPORTED_PICTURE_FORMATS[];
+ // The width (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "512". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_WIDTH[];
+ // The height (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "384". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
+ // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
+ // in EXIF.
+ // Example value: "512x384,320x240,0x0". Read only.
+ static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
+ // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
+ // with 100 being the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_QUALITY[];
+ // Jpeg quality of captured picture. The range is 1 to 100, with 100 being
+ // the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_QUALITY[];
+ // The rotation angle in degrees relative to the orientation of the camera.
+ // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
+ // camera driver may set orientation in the EXIF header without rotating the
+ // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
+ // the Jpeg picture is rotated, the orientation in the EXIF header will be
+ // missing or 1 (row #0 is top and column #0 is left side).
+ //
+ // Note that the JPEG pictures of front-facing cameras are not mirrored
+ // as in preview display.
+ //
+ // For example, suppose the natural orientation of the device is portrait.
+ // The device is rotated 270 degrees clockwise, so the device orientation is
+ // 270. Suppose a back-facing camera sensor is mounted in landscape and the
+ // top side of the camera sensor is aligned with the right edge of the
+ // display in natural orientation. So the camera orientation is 90. The
+ // rotation should be set to 0 (270 + 90).
+ //
+ // Example value: "0" or "90" or "180" or "270". Write only.
+ static const char KEY_ROTATION[];
+ // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
+ // JPEG EXIF header.
+ // Example value: "25.032146" or "-33.462809". Write only.
+ static const char KEY_GPS_LATITUDE[];
+ // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
+ // in JPEG EXIF header.
+ // Example value: "121.564448" or "-70.660286". Write only.
+ static const char KEY_GPS_LONGITUDE[];
+ // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
+ // header.
+ // Example value: "21.0" or "-5". Write only.
+ static const char KEY_GPS_ALTITUDE[];
+ // GPS timestamp (UTC in seconds since January 1, 1970). This should be
+ // stored in JPEG EXIF header.
+ // Example value: "1251192757". Write only.
+ static const char KEY_GPS_TIMESTAMP[];
+ // GPS Processing Method
+ // Example value: "GPS" or "NETWORK". Write only.
+ static const char KEY_GPS_PROCESSING_METHOD[];
+ // Current white balance setting.
+ // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
+ static const char KEY_WHITE_BALANCE[];
+ // Supported white balance settings.
+ // Example value: "auto,incandescent,daylight". Read only.
+ static const char KEY_SUPPORTED_WHITE_BALANCE[];
+ // Current color effect setting.
+ // Example value: "none" or EFFECT_XXX constants. Read/write.
+ static const char KEY_EFFECT[];
+ // Supported color effect settings.
+ // Example value: "none,mono,sepia". Read only.
+ static const char KEY_SUPPORTED_EFFECTS[];
+ // Current antibanding setting.
+ // Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
+ static const char KEY_ANTIBANDING[];
+ // Supported antibanding settings.
+ // Example value: "auto,50hz,60hz,off". Read only.
+ static const char KEY_SUPPORTED_ANTIBANDING[];
+ // Current scene mode.
+ // Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
+ static const char KEY_SCENE_MODE[];
+ // Supported scene mode settings.
+ // Example value: "auto,night,fireworks". Read only.
+ static const char KEY_SUPPORTED_SCENE_MODES[];
+ // Current flash mode.
+ // Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
+ static const char KEY_FLASH_MODE[];
+ // Supported flash modes.
+ // Example value: "auto,on,off". Read only.
+ static const char KEY_SUPPORTED_FLASH_MODES[];
+ // Current focus mode. This will not be empty. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus if focus mode is
+ // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
+ // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
+ static const char KEY_FOCUS_MODE[];
+ // Supported focus modes.
+ // Example value: "auto,macro,fixed". Read only.
+ static const char KEY_SUPPORTED_FOCUS_MODES[];
+ // The maximum number of focus areas supported. This is the maximum length
+ // of KEY_FOCUS_AREAS.
+ // Example value: "0" or "2". Read only.
+ static const char KEY_MAX_NUM_FOCUS_AREAS[];
+ // Current focus areas.
+ //
+ // Before accessing this parameter, apps should check
+ // KEY_MAX_NUM_FOCUS_AREAS first to know the maximum number of focus areas
+ // first. If the value is 0, focus area is not supported.
+ //
+ // Each focus area is a five-element int array. The first four elements are
+ // the rectangle of the area (left, top, right, bottom). The direction is
+ // relative to the sensor orientation, that is, what the sensor sees. The
+ // direction is not affected by the rotation or mirroring of
+ // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates range from -1000 to 1000.
+ // (-1000,-1000) is the upper left point. (1000, 1000) is the lower right
+ // point. The width and height of focus areas cannot be 0 or negative.
+ //
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // focusing than the larger area. Focus areas can partially overlap and the
+ // driver will add the weights in the overlap region.
+ //
+ // A special case of single focus area (0,0,0,0,0) means driver to decide
+ // the focus area. For example, the driver may use more signals to decide
+ // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they
+ // want the driver to decide focus areas.
+ //
+ // Focus areas are relative to the current field of view (KEY_ZOOM). No
+ // matter what the zoom level is, (-1000,-1000) represents the top of the
+ // currently visible camera frame. The focus area cannot be set to be
+ // outside the current field of view, even when using zoom.
+ //
+ // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO,
+ // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or
+ // FOCUS_MODE_CONTINUOUS_PICTURE.
+ // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+ static const char KEY_FOCUS_AREAS[];
+ // Focal length in millimeter.
+ // Example value: "4.31". Read only.
+ static const char KEY_FOCAL_LENGTH[];
+ // Horizontal angle of view in degrees.
+ // Example value: "54.8". Read only.
+ static const char KEY_HORIZONTAL_VIEW_ANGLE[];
+ // Vertical angle of view in degrees.
+ // Example value: "42.5". Read only.
+ static const char KEY_VERTICAL_VIEW_ANGLE[];
+ // Exposure compensation index. 0 means exposure is not adjusted.
+ // Example value: "-5" or "5". Read/write.
+ static const char KEY_EXPOSURE_COMPENSATION[];
+ // The maximum exposure compensation index (>=0).
+ // Example value: "6". Read only.
+ static const char KEY_MAX_EXPOSURE_COMPENSATION[];
+ // The minimum exposure compensation index (<=0).
+ // Example value: "-6". Read only.
+ static const char KEY_MIN_EXPOSURE_COMPENSATION[];
+ // The exposure compensation step. Exposure compensation index multiply by
+ // step eqals to EV. Ex: if exposure compensation index is -6 and step is
+ // 0.3333, EV is -2.
+ // Example value: "0.333333333" or "0.5". Read only.
+ static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+ // The state of the auto-exposure lock. "true" means that
+ // auto-exposure is locked to its current value and will not
+ // change. "false" means the auto-exposure routine is free to
+ // change exposure values. If auto-exposure is already locked,
+ // setting this to true again has no effect (the driver will not
+ // recalculate exposure values). Changing exposure compensation
+ // settings will still affect the exposure settings while
+ // auto-exposure is locked. Stopping preview or taking a still
+ // image will not change the lock. In conjunction with
+ // exposure compensation, this allows for capturing multi-exposure
+ // brackets with known relative exposure values. Locking
+ // auto-exposure after open but before the first call to
+ // startPreview may result in severely over- or under-exposed
+ // images. The driver will not change the AE lock after
+ // auto-focus completes.
+ static const char KEY_AUTO_EXPOSURE_LOCK[];
+ // Whether locking the auto-exposure is supported. "true" means it is, and
+ // "false" or this key not existing means it is not supported.
+ static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
+ // The state of the auto-white balance lock. "true" means that
+ // auto-white balance is locked to its current value and will not
+ // change. "false" means the auto-white balance routine is free to
+ // change white balance values. If auto-white balance is already
+ // locked, setting this to true again has no effect (the driver
+ // will not recalculate white balance values). Stopping preview or
+ // taking a still image will not change the lock. In conjunction
+ // with exposure compensation, this allows for capturing
+ // multi-exposure brackets with fixed white balance. Locking
+ // auto-white balance after open but before the first call to
+ // startPreview may result in severely incorrect color. The
+ // driver will not change the AWB lock after auto-focus
+ // completes.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK[];
+ // Whether locking the auto-white balance is supported. "true"
+ // means it is, and "false" or this key not existing means it is
+ // not supported.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
+
+ // The maximum number of metering areas supported. This is the maximum
+ // length of KEY_METERING_AREAS.
+ // Example value: "0" or "2". Read only.
+ static const char KEY_MAX_NUM_METERING_AREAS[];
+ // Current metering areas. Camera driver uses these areas to decide
+ // exposure.
+ //
+ // Before accessing this parameter, apps should check
+ // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
+ // areas first. If the value is 0, metering area is not supported.
+ //
+ // Each metering area is a rectangle with specified weight. The direction is
+ // relative to the sensor orientation, that is, what the sensor sees. The
+ // direction is not affected by the rotation or mirroring of
+ // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
+ // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
+ // is the lower right point. The width and height of metering areas cannot
+ // be 0 or negative.
+ //
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // metering than the larger area. Metering areas can partially overlap and
+ // the driver will add the weights in the overlap region.
+ //
+ // A special case of all-zero single metering area means driver to decide
+ // the metering area. For example, the driver may use more signals to decide
+ // metering areas and change them dynamically. Apps can set all-zero if they
+ // want the driver to decide metering areas.
+ //
+ // Metering areas are relative to the current field of view (KEY_ZOOM).
+ // No matter what the zoom level is, (-1000,-1000) represents the top of the
+ // currently visible camera frame. The metering area cannot be set to be
+ // outside the current field of view, even when using zoom.
+ //
+ // No matter what metering areas are, the final exposure are compensated
+ // by KEY_EXPOSURE_COMPENSATION.
+ // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+ static const char KEY_METERING_AREAS[];
+ // Current zoom value.
+ // Example value: "0" or "6". Read/write.
+ static const char KEY_ZOOM[];
+ // Maximum zoom value.
+ // Example value: "6". Read only.
+ static const char KEY_MAX_ZOOM[];
+ // The zoom ratios of all zoom values. The zoom ratio is in 1/100
+ // increments. Ex: a zoom of 3.2x is returned as 320. The number of list
+ // elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last
+ // element is the zoom ratio of zoom value KEY_MAX_ZOOM.
+ // Example value: "100,150,200,250,300,350,400". Read only.
+ static const char KEY_ZOOM_RATIOS[];
+ // Whether zoom is supported. Zoom is supported if the value is "true". Zoom
+ // is not supported if the value is not "true" or the key does not exist.
+ // Example value: "true". Read only.
+ static const char KEY_ZOOM_SUPPORTED[];
+ // Whether if smooth zoom is supported. Smooth zoom is supported if the
+ // value is "true". It is not supported if the value is not "true" or the
+ // key does not exist.
+ // See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and
+ // CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h.
+ // Example value: "true". Read only.
+ static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
+
+ // The distances (in meters) from the camera to where an object appears to
+ // be in focus. The object is sharpest at the optimal focus distance. The
+ // depth of field is the far focus distance minus near focus distance.
+ //
+ // Focus distances may change after starting auto focus, canceling auto
+ // focus, or starting the preview. Applications can read this anytime to get
+ // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
+ // focus distances may change from time to time.
+ //
+ // This is intended to estimate the distance between the camera and the
+ // subject. After autofocus, the subject distance may be within near and far
+ // focus distance. However, the precision depends on the camera hardware,
+ // autofocus algorithm, the focus area, and the scene. The error can be
+ // large and it should be only used as a reference.
+ //
+ // Far focus distance > optimal focus distance > near focus distance. If
+ // the far focus distance is infinity, the value should be "Infinity" (case
+ // sensitive). The format is three float values separated by commas. The
+ // first is near focus distance. The second is optimal focus distance. The
+ // third is far focus distance.
+ // Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only.
+ static const char KEY_FOCUS_DISTANCES[];
+
+ // The current dimensions in pixels (width x height) for video frames.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_VIDEO_SIZES.
+ // Example value: "1280x720". Read/write.
+ static const char KEY_VIDEO_SIZE[];
+ // A list of the supported dimensions in pixels (width x height)
+ // for video frames. See CAMERA_MSG_VIDEO_FRAME for details in
+ // frameworks/base/include/camera/Camera.h.
+ // Example: "176x144,1280x720". Read only.
+ static const char KEY_SUPPORTED_VIDEO_SIZES[];
+
+ // The maximum number of detected faces supported by hardware face
+ // detection. If the value is 0, hardware face detection is not supported.
+ // Example: "5". Read only
+ static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
+
+ // The maximum number of detected faces supported by software face
+ // detection. If the value is 0, software face detection is not supported.
+ // Example: "5". Read only
+ static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
+
+ // Preferred preview frame size in pixels for video recording.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+ // getSupportedVideoSizes() does not return an empty Vector of Size.
+ // Camcorder applications are recommended to set the preview size
+ // to a value that is not larger than the preferred preview size.
+ // In other words, the product of the width and height of the
+ // preview size should not be larger than that of the preferred
+ // preview size. In addition, we recommend to choos a preview size
+ // that has the same aspect ratio as the resolution of video to be
+ // recorded.
+ // Example value: "800x600". Read only.
+ static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
+
+ // The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
+ // frameworks/base/include/camera/Camera.h.
+ // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
+ static const char KEY_VIDEO_FRAME_FORMAT[];
+
+ // Sets the hint of the recording mode. If this is true, MediaRecorder.start
+ // may be faster or has less glitches. This should be called before starting
+ // the preview for the best result. But it is allowed to change the hint
+ // while the preview is active. The default value is false.
+ //
+ // The apps can still call Camera.takePicture when the hint is true. The
+ // apps can call MediaRecorder.start when the hint is false. But the
+ // performance may be worse.
+ // Example value: "true" or "false". Read/write.
+ static const char KEY_RECORDING_HINT[];
+
+ // Returns true if video snapshot is supported. That is, applications
+ // can call Camera.takePicture during recording. Applications do not need to
+ // call Camera.startPreview after taking a picture. The preview will be
+ // still active. Other than that, taking a picture during recording is
+ // identical to taking a picture normally. All settings and methods related
+ // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
+ // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
+ // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
+ // also still work, but the video will record the flash.
+ //
+ // Applications can set shutter callback as null to avoid the shutter
+ // sound. It is also recommended to set raw picture and post view callbacks
+ // to null to avoid the interrupt of preview display.
+ //
+ // Field-of-view of the recorded video may be different from that of the
+ // captured pictures.
+ // Example value: "true" or "false". Read only.
+ static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+
+ // The state of the video stabilization. If set to true, both the
+ // preview stream and the recorded video stream are stabilized by
+ // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is
+ // set to true.
+ //
+ // The value of this key can be changed any time the camera is
+ // open. If preview or recording is active, it is acceptable for
+ // there to be a slight video glitch when video stabilization is
+ // toggled on and off.
+ //
+ // This only stabilizes video streams (between-frames stabilization), and
+ // has no effect on still image capture.
+ static const char KEY_VIDEO_STABILIZATION[];
+
+ // Returns true if video stabilization is supported. That is, applications
+ // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
+ // stream and record stabilized videos.
+ static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
+
+ // Supported modes for special effects with light.
+ // Example values: "lowlight,hdr".
+ static const char KEY_LIGHTFX[];
+
+ // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
+ static const char TRUE[];
+ static const char FALSE[];
+
+ // Value for KEY_FOCUS_DISTANCES.
+ static const char FOCUS_DISTANCE_INFINITY[];
+
+ // Values for white balance settings.
+ static const char WHITE_BALANCE_AUTO[];
+ static const char WHITE_BALANCE_INCANDESCENT[];
+ static const char WHITE_BALANCE_FLUORESCENT[];
+ static const char WHITE_BALANCE_WARM_FLUORESCENT[];
+ static const char WHITE_BALANCE_DAYLIGHT[];
+ static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
+ static const char WHITE_BALANCE_TWILIGHT[];
+ static const char WHITE_BALANCE_SHADE[];
+
+ // Values for effect settings.
+ static const char EFFECT_NONE[];
+ static const char EFFECT_MONO[];
+ static const char EFFECT_NEGATIVE[];
+ static const char EFFECT_SOLARIZE[];
+ static const char EFFECT_SEPIA[];
+ static const char EFFECT_POSTERIZE[];
+ static const char EFFECT_WHITEBOARD[];
+ static const char EFFECT_BLACKBOARD[];
+ static const char EFFECT_AQUA[];
+
+ // Values for antibanding settings.
+ static const char ANTIBANDING_AUTO[];
+ static const char ANTIBANDING_50HZ[];
+ static const char ANTIBANDING_60HZ[];
+ static const char ANTIBANDING_OFF[];
+
+ // Values for flash mode settings.
+ // Flash will not be fired.
+ static const char FLASH_MODE_OFF[];
+ // Flash will be fired automatically when required. The flash may be fired
+ // during preview, auto-focus, or snapshot depending on the driver.
+ static const char FLASH_MODE_AUTO[];
+ // Flash will always be fired during snapshot. The flash may also be
+ // fired during preview or auto-focus depending on the driver.
+ static const char FLASH_MODE_ON[];
+ // Flash will be fired in red-eye reduction mode.
+ static const char FLASH_MODE_RED_EYE[];
+ // Constant emission of light during preview, auto-focus and snapshot.
+ // This can also be used for video recording.
+ static const char FLASH_MODE_TORCH[];
+
+ // Values for scene mode settings.
+ static const char SCENE_MODE_AUTO[];
+ static const char SCENE_MODE_ACTION[];
+ static const char SCENE_MODE_PORTRAIT[];
+ static const char SCENE_MODE_LANDSCAPE[];
+ static const char SCENE_MODE_NIGHT[];
+ static const char SCENE_MODE_NIGHT_PORTRAIT[];
+ static const char SCENE_MODE_THEATRE[];
+ static const char SCENE_MODE_BEACH[];
+ static const char SCENE_MODE_SNOW[];
+ static const char SCENE_MODE_SUNSET[];
+ static const char SCENE_MODE_STEADYPHOTO[];
+ static const char SCENE_MODE_FIREWORKS[];
+ static const char SCENE_MODE_SPORTS[];
+ static const char SCENE_MODE_PARTY[];
+ static const char SCENE_MODE_CANDLELIGHT[];
+ // Applications are looking for a barcode. Camera driver will be optimized
+ // for barcode reading.
+ static const char SCENE_MODE_BARCODE[];
+ // A high-dynamic range mode. In this mode, the HAL module will use a
+ // capture strategy that extends the dynamic range of the captured
+ // image in some fashion. Only the final image is returned.
+ static const char SCENE_MODE_HDR[];
+
+ // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
+ // and KEY_VIDEO_FRAME_FORMAT
+ static const char PIXEL_FORMAT_YUV422SP[];
+ static const char PIXEL_FORMAT_YUV420SP[]; // NV21
+ static const char PIXEL_FORMAT_YUV422I[]; // YUY2
+ static const char PIXEL_FORMAT_YUV420P[]; // YV12
+ static const char PIXEL_FORMAT_RGB565[];
+ static const char PIXEL_FORMAT_RGBA8888[];
+ static const char PIXEL_FORMAT_JPEG[];
+ // Raw bayer format used for images, which is 10 bit precision samples
+ // stored in 16 bit words. The filter pattern is RGGB.
+ static const char PIXEL_FORMAT_BAYER_RGGB[];
+ // Pixel format is not known to the framework
+ static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
+
+ // Values for focus mode settings.
+ // Auto-focus mode. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus in this mode.
+ static const char FOCUS_MODE_AUTO[];
+ // Focus is set at infinity. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_INFINITY[];
+ // Macro (close-up) focus mode. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus in this mode.
+ static const char FOCUS_MODE_MACRO[];
+ // Focus is fixed. The camera is always in this mode if the focus is not
+ // adjustable. If the camera has auto-focus, this mode can fix the
+ // focus, which is usually at hyperfocal distance. Applications should
+ // not call CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_FIXED[];
+ // Extended depth of field (EDOF). Focusing is done digitally and
+ // continuously. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_EDOF[];
+ // Continuous auto focus mode intended for video recording. The camera
+ // continuously tries to focus. This is the best choice for video
+ // recording because the focus changes smoothly . Applications still can
+ // call CameraHardwareInterface.takePicture in this mode but the subject may
+ // not be in focus. Auto focus starts when the parameter is set.
+ //
+ // Applications can call CameraHardwareInterface.autoFocus in this mode. The
+ // focus callback will immediately return with a boolean that indicates
+ // whether the focus is sharp or not. The focus position is locked after
+ // autoFocus call. If applications want to resume the continuous focus,
+ // cancelAutoFocus must be called. Restarting the preview will not resume
+ // the continuous autofocus. To stop continuous focus, applications should
+ // change the focus mode to other modes.
+ static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
+ // Continuous auto focus mode intended for taking pictures. The camera
+ // continuously tries to focus. The speed of focus change is more aggressive
+ // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is
+ // set.
+ //
+ // Applications can call CameraHardwareInterface.autoFocus in this mode. If
+ // the autofocus is in the middle of scanning, the focus callback will
+ // return when it completes. If the autofocus is not scanning, focus
+ // callback will immediately return with a boolean that indicates whether
+ // the focus is sharp or not. The apps can then decide if they want to take
+ // a picture immediately or to change the focus mode to auto, and run a full
+ // autofocus cycle. The focus position is locked after autoFocus call. If
+ // applications want to resume the continuous focus, cancelAutoFocus must be
+ // called. Restarting the preview will not resume the continuous autofocus.
+ // To stop continuous focus, applications should change the focus mode to
+ // other modes.
+ static const char FOCUS_MODE_CONTINUOUS_PICTURE[];
+
+ // Values for light special effects
+ // Low-light enhancement mode
+ static const char LIGHTFX_LOWLIGHT[];
+ // High-dynamic range mode
+ static const char LIGHTFX_HDR[];
+
+ /**
+ * Returns the the supported preview formats as an enum given in graphics.h
+ * corrsponding to the format given in the input string or -1 if no such
+ * conversion exists.
+ */
+ static int previewFormatToEnum(const char* format);
+
+private:
+ DefaultKeyedVector<String8,String8> mMap;
+};
+
+}; // namespace android
+
+#endif
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
new file mode 100644
index 0000000..a79c9fa
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -0,0 +1,3231 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "camera_hidl_hal_test"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/1.0/ICameraDevice.h>
+#include "CameraParameters.h"
+#include <system/camera.h>
+#include <android/log.h>
+#include <ui/GraphicBuffer.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <gui/BufferQueue.h>
+#include <gui/Surface.h>
+#include <gui/BufferItemConsumer.h>
+#include <binder/MemoryHeapBase.h>
+#include <regex>
+#include "system/camera_metadata.h"
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <unordered_map>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <inttypes.h>
+#include <utils/Errors.h>
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::android::wp;
+using ::android::GraphicBuffer;
+using ::android::IGraphicBufferProducer;
+using ::android::IGraphicBufferConsumer;
+using ::android::BufferQueue;
+using ::android::BufferItemConsumer;
+using ::android::Surface;
+using ::android::CameraParameters;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::StreamBuffer;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::ErrorMsg;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V1_0::CameraFacing;
+using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg;
+using ::android::hardware::camera::device::V1_0::CommandType;
+using ::android::hardware::camera::device::V1_0::DataCallbackMsg;
+using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
+using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
+using ::android::hardware::camera::device::V1_0::FrameCallbackFlag;
+
+const char kCameraPassthroughServiceName[] = "legacy/0";
+const uint32_t kMaxPreviewWidth = 1920;
+const uint32_t kMaxPreviewHeight = 1080;
+const uint32_t kMaxVideoWidth = 4096;
+const uint32_t kMaxVideoHeight = 2160;
+const int64_t kStreamBufferTimeoutSec = 3;
+const int64_t kAutoFocusTimeoutSec = 5;
+const int64_t kTorchTimeoutSec = 1;
+const int64_t kEmptyFlushTimeoutMSec = 200;
+const char kDumpOutput[] = "/dev/null";
+
+struct AvailableStream {
+ int32_t width;
+ int32_t height;
+ int32_t format;
+};
+
+struct AvailableZSLInputOutput {
+ int32_t inputFormat;
+ int32_t outputFormat;
+};
+
+namespace {
+ // "device@<version>/legacy/<id>"
+ const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)";
+ const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
+ const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+ const char *kHAL3_2 = "3.2";
+ const char *kHAL1_0 = "1.0";
+
+ bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+ std::regex e(kDeviceNameRE);
+ std::string deviceNameStd(deviceName.c_str());
+ return std::regex_match(deviceNameStd, sm, e);
+ }
+
+ int getCameraDeviceVersion(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return -1;
+ }
+ std::string version = sm[1].str();
+ if (version.compare(kHAL3_2) == 0) {
+ // maybe switched to 3.4 or define the hidl version enumlater
+ return CAMERA_DEVICE_API_VERSION_3_2;
+ } else if (version.compare(kHAL1_0) == 0) {
+ return CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ return 0;
+ }
+
+ Status mapToStatus(::android::status_t s) {
+ switch(s) {
+ case ::android::OK:
+ return Status::OK ;
+ case ::android::BAD_VALUE:
+ return Status::ILLEGAL_ARGUMENT ;
+ case -EBUSY:
+ return Status::CAMERA_IN_USE;
+ case -EUSERS:
+ return Status::MAX_CAMERAS_IN_USE;
+ case ::android::UNKNOWN_TRANSACTION:
+ return Status::METHOD_NOT_SUPPORTED;
+ case ::android::INVALID_OPERATION:
+ return Status::OPERATION_NOT_SUPPORTED;
+ case ::android::DEAD_OBJECT:
+ return Status::CAMERA_DISCONNECTED;
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
+}
+
+// Test environment for camera
+class CameraHidlEnvironment : public ::testing::Environment {
+public:
+ // get the test environment singleton
+ static CameraHidlEnvironment* Instance() {
+ static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
+ return instance;
+ }
+
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ sp<ICameraProvider> mProvider;
+
+private:
+ CameraHidlEnvironment() {}
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
+};
+
+void CameraHidlEnvironment::SetUp() {
+ // TODO: test the binderized mode
+ mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraPassthroughServiceName);
+ // TODO: handle the device doesn't have any camera case
+ ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
+ ASSERT_NE(mProvider, nullptr);
+}
+
+void CameraHidlEnvironment::TearDown() {
+ ALOGI("TearDown CameraHidlEnvironment");
+}
+
+struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
+ BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}
+
+ void onFrameAvailable(const android::BufferItem&) override {
+ sp<BufferItemConsumer> consumer = mConsumer.promote();
+ ASSERT_NE(nullptr, consumer.get());
+
+ android::BufferItem buffer;
+ ASSERT_EQ(android::OK, consumer->acquireBuffer(&buffer, 0));
+ ASSERT_EQ(android::OK, consumer->releaseBuffer(buffer));
+ }
+
+ private:
+ wp<BufferItemConsumer> mConsumer;
+};
+
+struct PreviewWindowCb : public ICameraDevicePreviewCallback {
+ PreviewWindowCb(sp<ANativeWindow> anw) : mPreviewWidth(0),
+ mPreviewHeight(0), mFormat(0), mPreviewUsage(0),
+ mPreviewSwapInterval(-1), mCrop{-1, -1, -1, -1}, mAnw(anw) {}
+
+ using dequeueBuffer_cb =
+ std::function<void(Status status, uint64_t bufferId,
+ const hidl_handle& buffer, uint32_t stride)>;
+ Return<void> dequeueBuffer(dequeueBuffer_cb _hidl_cb) override;
+
+ Return<Status> enqueueBuffer(uint64_t bufferId) override;
+
+ Return<Status> cancelBuffer(uint64_t bufferId) override;
+
+ Return<Status> setBufferCount(uint32_t count) override;
+
+ Return<Status> setBuffersGeometry(uint32_t w,
+ uint32_t h, PixelFormat format) override;
+
+ Return<Status> setCrop(int32_t left, int32_t top,
+ int32_t right, int32_t bottom) override;
+
+ Return<Status> setUsage(ProducerUsage usage) override;
+
+ Return<Status> setSwapInterval(int32_t interval) override;
+
+ using getMinUndequeuedBufferCount_cb =
+ std::function<void(Status status, uint32_t count)>;
+ Return<void> getMinUndequeuedBufferCount(
+ getMinUndequeuedBufferCount_cb _hidl_cb) override;
+
+ Return<Status> setTimestamp(int64_t timestamp) override;
+
+ private:
+ struct BufferHasher {
+ size_t operator()(const buffer_handle_t& buf) const {
+ if (buf == nullptr)
+ return 0;
+
+ size_t result = 1;
+ result = 31 * result + buf->numFds;
+ result = 31 * result + buf->numInts;
+ int length = buf->numFds + buf->numInts;
+ for (int i = 0; i < length; i++) {
+ result = 31 * result + buf->data[i];
+ }
+ return result;
+ }
+ };
+
+ struct BufferComparator {
+ bool operator()(const buffer_handle_t& buf1,
+ const buffer_handle_t& buf2) const {
+ if ((buf1->numFds == buf2->numFds) &&
+ (buf1->numInts == buf2->numInts)) {
+ int length = buf1->numFds + buf1->numInts;
+ for (int i = 0; i < length; i++) {
+ if (buf1->data[i] != buf2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb);
+ void cleanupCirculatingBuffers();
+
+ std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId
+ typedef std::unordered_map<const buffer_handle_t, uint64_t,
+ BufferHasher, BufferComparator> BufferIdMap;
+
+ BufferIdMap mBufferIdMap; // stream ID -> per stream buffer ID map
+ std::unordered_map<uint64_t, ANativeWindowBuffer*> mReversedBufMap;
+ uint64_t mNextBufferId = 1;
+
+ uint32_t mPreviewWidth, mPreviewHeight;
+ int mFormat, mPreviewUsage;
+ int32_t mPreviewSwapInterval;
+ android_native_rect_t mCrop;
+ sp<ANativeWindow> mAnw; //Native window reference
+};
+
+std::pair<bool, uint64_t> PreviewWindowCb::getBufferId(
+ ANativeWindowBuffer* anb) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ buffer_handle_t& buf = anb->handle;
+ auto it = mBufferIdMap.find(buf);
+ if (it == mBufferIdMap.end()) {
+ uint64_t bufId = mNextBufferId++;
+ mBufferIdMap[buf] = bufId;
+ mReversedBufMap[bufId] = anb;
+ return std::make_pair(true, bufId);
+ } else {
+ return std::make_pair(false, it->second);
+ }
+}
+
+void PreviewWindowCb::cleanupCirculatingBuffers() {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ mBufferIdMap.clear();
+ mReversedBufMap.clear();
+}
+
+Return<void> PreviewWindowCb::dequeueBuffer(dequeueBuffer_cb _hidl_cb) {
+ ANativeWindowBuffer* anb;
+ auto rc = native_window_dequeue_buffer_and_wait(mAnw.get(), &anb);
+ uint64_t bufferId = 0;
+ uint32_t stride = 0;
+ hidl_handle buf = nullptr;
+ if (rc == ::android::OK) {
+ auto pair = getBufferId(anb);
+ buf = (pair.first) ? anb->handle : nullptr;
+ bufferId = pair.second;
+ stride = anb->stride;
+ }
+
+ _hidl_cb(mapToStatus(rc), bufferId, buf, stride);
+ return Void();
+}
+
+Return<Status> PreviewWindowCb::enqueueBuffer(uint64_t bufferId) {
+ if (mReversedBufMap.count(bufferId) == 0) {
+ ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ return mapToStatus(mAnw->queueBuffer(mAnw.get(),
+ mReversedBufMap.at(bufferId), -1));
+}
+
+Return<Status> PreviewWindowCb::cancelBuffer(uint64_t bufferId) {
+ if (mReversedBufMap.count(bufferId) == 0) {
+ ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ return mapToStatus(mAnw->cancelBuffer(mAnw.get(),
+ mReversedBufMap.at(bufferId), -1));
+}
+
+Return<Status> PreviewWindowCb::setBufferCount(uint32_t count) {
+ if (mAnw.get() != nullptr) {
+ // WAR for b/27039775
+ native_window_api_disconnect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
+ native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
+ if (mPreviewWidth != 0) {
+ native_window_set_buffers_dimensions(mAnw.get(),
+ mPreviewWidth, mPreviewHeight);
+ native_window_set_buffers_format(mAnw.get(), mFormat);
+ }
+ if (mPreviewUsage != 0) {
+ native_window_set_usage(mAnw.get(), mPreviewUsage);
+ }
+ if (mPreviewSwapInterval >= 0) {
+ mAnw->setSwapInterval(mAnw.get(), mPreviewSwapInterval);
+ }
+ if (mCrop.left >= 0) {
+ native_window_set_crop(mAnw.get(), &(mCrop));
+ }
+ }
+
+ auto rc = native_window_set_buffer_count(mAnw.get(), count);
+ if (rc == ::android::OK) {
+ cleanupCirculatingBuffers();
+ }
+
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setBuffersGeometry(uint32_t w, uint32_t h,
+ PixelFormat format) {
+ auto rc = native_window_set_buffers_dimensions(mAnw.get(), w, h);
+ if (rc == ::android::OK) {
+ mPreviewWidth = w;
+ mPreviewHeight = h;
+ rc = native_window_set_buffers_format(mAnw.get(),
+ static_cast<int>(format));
+ if (rc == ::android::OK) {
+ mFormat = static_cast<int>(format);
+ }
+ }
+
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setCrop(int32_t left, int32_t top,
+ int32_t right, int32_t bottom) {
+ android_native_rect_t crop = { left, top, right, bottom };
+ auto rc = native_window_set_crop(mAnw.get(), &crop);
+ if (rc == ::android::OK) {
+ mCrop = crop;
+ }
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setUsage(ProducerUsage usage) {
+ auto rc = native_window_set_usage(mAnw.get(), static_cast<int>(usage));
+ if (rc == ::android::OK) {
+ mPreviewUsage = static_cast<int>(usage);
+ }
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setSwapInterval(int32_t interval) {
+ auto rc = mAnw->setSwapInterval(mAnw.get(), interval);
+ if (rc == ::android::OK) {
+ mPreviewSwapInterval = interval;
+ }
+ return mapToStatus(rc);
+}
+
+Return<void> PreviewWindowCb::getMinUndequeuedBufferCount(
+ getMinUndequeuedBufferCount_cb _hidl_cb) {
+ int count = 0;
+ auto rc = mAnw->query(mAnw.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count);
+ _hidl_cb(mapToStatus(rc), count);
+ return Void();
+}
+
+Return<Status> PreviewWindowCb::setTimestamp(int64_t timestamp) {
+ return mapToStatus(native_window_set_buffers_timestamp(mAnw.get(),
+ timestamp));
+}
+
+// The main test class for camera HIDL HAL.
+class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+ virtual void SetUp() override {}
+ virtual void TearDown() override {}
+
+ hidl_vec<hidl_string> getCameraDeviceNames();
+
+ struct EmptyDeviceCb : public ICameraDeviceCallback {
+ virtual Return<void> processCaptureResult(const hidl_vec<CaptureResult>& /*results*/) override {
+ ALOGI("processCaptureResult callback");
+ ADD_FAILURE(); // Empty callback should not reach here
+ return Void();
+ }
+
+ virtual Return<void> notify(const hidl_vec<NotifyMsg>& /*msgs*/) override {
+ ALOGI("notify callback");
+ ADD_FAILURE(); // Empty callback should not reach here
+ return Void();
+ }
+ };
+
+ struct DeviceCb : public ICameraDeviceCallback {
+ DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+ Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
+ Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
+
+ private:
+ CameraHidlTest *mParent; // Parent object
+ };
+
+ struct TorchProviderCb : public ICameraProviderCallback {
+ TorchProviderCb(CameraHidlTest *parent) : mParent(parent) {}
+ virtual Return<void> cameraDeviceStatusChange(
+ const hidl_string&, CameraDeviceStatus) override {
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(
+ const hidl_string&, TorchModeStatus newStatus) override {
+ std::lock_guard<std::mutex> l(mParent->mTorchLock);
+ mParent->mTorchStatus = newStatus;
+ mParent->mTorchCond.notify_one();
+ return Void();
+ }
+
+ private:
+ CameraHidlTest *mParent; // Parent object
+ };
+
+ struct Camera1DeviceCb :
+ public ::android::hardware::camera::device::V1_0::ICameraDeviceCallback {
+ Camera1DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+
+ Return<void> notifyCallback(NotifyCallbackMsg msgType,
+ int32_t ext1, int32_t ext2) override;
+
+ Return<uint32_t> registerMemory(const hidl_handle& descriptor,
+ uint32_t bufferSize, uint32_t bufferCount) override;
+
+ Return<void> unregisterMemory(uint32_t memId) override;
+
+ Return<void> dataCallback(DataCallbackMsg msgType,
+ uint32_t data, uint32_t bufferIndex,
+ const CameraFrameMetadata& metadata) override;
+
+ Return<void> dataCallbackTimestamp(DataCallbackMsg msgType,
+ uint32_t data, uint32_t bufferIndex,
+ int64_t timestamp) override;
+
+ Return<void> handleCallbackTimestamp(DataCallbackMsg msgType,
+ const hidl_handle& frameData,uint32_t data,
+ uint32_t bufferIndex, int64_t timestamp) override;
+
+ private:
+ CameraHidlTest *mParent; // Parent object
+ };
+
+ void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env,
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/);
+ void setupPreviewWindow(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
+ sp<BufferItemHander> *bufferHandler /*out*/);
+ void stopPreviewAndClose(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void startPreview(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void enableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void disableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void getParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ CameraParameters *cameraParams /*out*/);
+ void setParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ const CameraParameters &cameraParams);
+ void waitForFrameLocked(DataCallbackMsg msgFrame,
+ std::unique_lock<std::mutex> &l);
+ void openEmptyDeviceSession(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<ICameraDeviceSession> *session /*out*/,
+ camera_metadata_t **staticMeta /*out*/);
+ void configurePreviewStream(const std::string &name,
+ const CameraHidlEnvironment* env,
+ const AvailableStream *previewThreshold,
+ sp<ICameraDeviceSession> *session /*out*/,
+ Stream *previewStream /*out*/,
+ HalStreamConfiguration *halStreamConfig /*out*/);
+ static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
+ std::vector<AvailableStream> &outputStreams,
+ const AvailableStream *threshold = nullptr);
+ static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
+ static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
+ AvailableStream &hfrStream);
+ static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
+ static Status getZSLInputOutputMap(camera_metadata_t *staticMeta,
+ std::vector<AvailableZSLInputOutput> &inputOutputMap);
+ static Status findLargestSize(
+ const std::vector<AvailableStream> &streamSizes,
+ int32_t format, AvailableStream &result);
+ static Status isAutoFocusModeAvailable(
+ ::android::CameraParameters &cameraParams, const char *mode) ;
+
+protected:
+ std::mutex mLock; // Synchronize access to member variables
+ std::condition_variable mResultCondition; // Condition variable for incoming results
+ uint32_t mResultFrameNumber; // Expected result frame number
+ std::vector<StreamBuffer> mResultBuffers; // Holds stream buffers from capture result
+ std::vector<ErrorMsg> mErrors; // Holds incoming error notifications
+ DataCallbackMsg mDataMessageTypeReceived; // Most recent message type received through data callbacks
+ uint32_t mVideoBufferIndex; // Buffer index of the most recent video buffer
+ uint32_t mVideoData; // Buffer data of the most recent video buffer
+ hidl_handle mVideoNativeHandle; // Most recent video buffer native handle
+ NotifyCallbackMsg mNotifyMessage; // Current notification message
+
+ std::mutex mTorchLock; // Synchronize access to torch status
+ std::condition_variable mTorchCond; // Condition variable for torch status
+ TorchModeStatus mTorchStatus; // Current torch status
+
+ // Holds camera registered buffers
+ std::unordered_map<uint32_t, sp<::android::MemoryHeapBase> > mMemoryPool;
+};
+
+Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback(
+ NotifyCallbackMsg msgType, int32_t ext1 __unused,
+ int32_t ext2 __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mNotifyMessage = msgType;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<uint32_t> CameraHidlTest::Camera1DeviceCb::registerMemory(
+ const hidl_handle& descriptor, uint32_t bufferSize,
+ uint32_t bufferCount) {
+ if (descriptor->numFds != 1) {
+ ADD_FAILURE() << "camera memory descriptor has"
+ " numFds " << descriptor->numFds << " (expect 1)" ;
+ return 0;
+ }
+ if (descriptor->data[0] < 0) {
+ ADD_FAILURE() << "camera memory descriptor has"
+ " FD " << descriptor->data[0] << " (expect >= 0)";
+ return 0;
+ }
+
+ sp<::android::MemoryHeapBase> pool = new ::android::MemoryHeapBase(
+ descriptor->data[0], bufferSize*bufferCount, 0, 0);
+ mParent->mMemoryPool.emplace(pool->getHeapID(), pool);
+
+ return pool->getHeapID();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::unregisterMemory(uint32_t memId) {
+ if (mParent->mMemoryPool.count(memId) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+ ADD_FAILURE();
+ return Void();
+ }
+
+ mParent->mMemoryPool.erase(memId);
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::dataCallback(
+ DataCallbackMsg msgType __unused, uint32_t data __unused,
+ uint32_t bufferIndex __unused,
+ const CameraFrameMetadata& metadata __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::dataCallbackTimestamp(
+ DataCallbackMsg msgType, uint32_t data,
+ uint32_t bufferIndex, int64_t timestamp __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mVideoBufferIndex = bufferIndex;
+ if (mParent->mMemoryPool.count(data) == 0) {
+ ADD_FAILURE() << "memory pool ID " << data << "not found";
+ }
+ mParent->mVideoData = data;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::handleCallbackTimestamp(
+ DataCallbackMsg msgType, const hidl_handle& frameData,
+ uint32_t data __unused, uint32_t bufferIndex,
+ int64_t timestamp __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mVideoBufferIndex = bufferIndex;
+ if (mParent->mMemoryPool.count(data) == 0) {
+ ADD_FAILURE() << "memory pool ID " << data << " not found";
+ }
+ mParent->mVideoData = data;
+ mParent->mVideoNativeHandle = frameData;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
+ const hidl_vec<CaptureResult>& results) {
+ if (nullptr == mParent) {
+ return Void();
+ }
+
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ const CaptureResult& result = results[0];
+
+ if(mParent->mResultFrameNumber != result.frameNumber) {
+ ALOGE("%s: Unexpected frame number! Expected: %u received: %u",
+ __func__, mParent->mResultFrameNumber, result.frameNumber);
+ ADD_FAILURE();
+ }
+
+ size_t resultLength = result.outputBuffers.size();
+ for (size_t i = 0; i < resultLength; i++) {
+ mParent->mResultBuffers.push_back(result.outputBuffers[i]);
+ }
+
+ // TODO(epeev): Handle partial results in case client supports them and
+ // verify the result against request settings.
+
+ l.unlock();
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::DeviceCb::notify(
+ const hidl_vec<NotifyMsg>& messages) {
+ const NotifyMsg& message = messages[0];
+
+ if (MsgType::ERROR == message.type) {
+ {
+ std::lock_guard<std::mutex> l(mParent->mLock);
+ mParent->mErrors.push_back(message.msg.error);
+ }
+
+ if ((ErrorCode::ERROR_REQUEST == message.msg.error.errorCode)
+ || (ErrorCode::ERROR_BUFFER == message.msg.error.errorCode)) {
+ mParent->mResultCondition.notify_one();
+ }
+ }
+
+ return Void();
+}
+
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames;
+ Return<void> ret;
+ ret = env->mProvider->getCameraIdList(
+ [&](auto status, const auto& idList) {
+ ALOGI("getCameraIdList returns status:%d", (int)status);
+ for (size_t i = 0; i < idList.size(); i++) {
+ ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+ }
+ ASSERT_EQ(Status::OK, status);
+ cameraDeviceNames = idList;
+ });
+ if (!ret.isOk()) {
+ ADD_FAILURE();
+ }
+ return cameraDeviceNames;
+}
+
+// Test if ICameraProvider::isTorchModeSupported returns Status::OK
+TEST_F(CameraHidlTest, isTorchModeSupported) {
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ [&](auto status, bool support) {
+ ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+ (int)status, support);
+ ASSERT_EQ(Status::OK, status);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
+TEST_F(CameraHidlTest, getCameraIdList) {
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
+ [&](auto status, const auto& idList) {
+ ALOGI("getCameraIdList returns status:%d", (int)status);
+ for (size_t i = 0; i < idList.size(); i++) {
+ ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+ }
+ ASSERT_EQ(Status::OK, status);
+ // This is true for internal camera provider.
+ // Not necessary hold for external cameras providers
+ ASSERT_GT(idList.size(), 0u);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Test if ICameraProvider::getVendorTags returns Status::OK
+TEST_F(CameraHidlTest, getVendorTags) {
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
+ [&](auto status, const auto& vendorTagSecs) {
+ ALOGI("getVendorTags returns status:%d numSections %zu",
+ (int)status, vendorTagSecs.size());
+ for (size_t i = 0; i < vendorTagSecs.size(); i++) {
+ ALOGI("Vendor tag section %zu name %s",
+ i, vendorTagSecs[i].sectionName.c_str());
+ for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
+ const auto& tag = vendorTagSecs[i].tags[j];
+ ALOGI("Vendor tag id %u name %s type %d",
+ tag.tagId,
+ tag.tagName.c_str(),
+ (int) tag.tagType);
+ }
+ }
+ ASSERT_EQ(Status::OK, status);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Test if ICameraProvider::setCallback returns Status::OK
+TEST_F(CameraHidlTest, setCallback) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ struct ProviderCb : public ICameraProviderCallback {
+ virtual Return<void> cameraDeviceStatusChange(
+ const hidl_string& cameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("camera device status callback name %s, status %d",
+ cameraDeviceName.c_str(), (int) newStatus);
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(
+ const hidl_string& cameraDeviceName,
+ TorchModeStatus newStatus) override {
+ ALOGI("Torch mode status callback name %s, status %d",
+ cameraDeviceName.c_str(), (int) newStatus);
+ return Void();
+ }
+ };
+ sp<ProviderCb> cb = new ProviderCb;
+ auto status = env->mProvider->setCallback(cb);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(Status::OK, status);
+}
+
+// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
+TEST_F(CameraHidlTest, getCameraDeviceInterface) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device3_2) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device3_2, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device1) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device1, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that the device resource cost can be retrieved and the values are
+// sane.
+TEST_F(CameraHidlTest, getResourceCost) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device3_2->getResourceCost(
+ [&](auto status, const auto& resourceCost) {
+ ALOGI("getResourceCost returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ALOGI(" Resource cost is %d", resourceCost.resourceCost);
+ ASSERT_LE(resourceCost.resourceCost, 100u);
+ for (const auto& name : resourceCost.conflictingDevices) {
+ ALOGI(" Conflicting device: %s", name.c_str());
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ } else {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device1->getResourceCost(
+ [&](auto status, const auto& resourceCost) {
+ ALOGI("getResourceCost returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ALOGI(" Resource cost is %d", resourceCost.resourceCost);
+ ASSERT_LE(resourceCost.resourceCost, 100u);
+ for (const auto& name : resourceCost.conflictingDevices) {
+ ALOGI(" Conflicting device: %s", name.c_str());
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that the static camera info can be retrieved
+// successfully.
+TEST_F(CameraHidlTest, getCameraInfo) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device1->getCameraInfo(
+ [&](auto status, const auto& info) {
+ ALOGI("getCameraInfo returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ switch(info.orientation) {
+ case 0:
+ case 90:
+ case 180:
+ case 270:
+ //Expected cases
+ ALOGI("camera orientation: %d", info.orientation);
+ break;
+ default:
+ FAIL() << "Unexpected camera orientation:" << info.orientation;
+ }
+ switch(info.facing) {
+ case CameraFacing::BACK:
+ case CameraFacing::FRONT:
+ case CameraFacing::EXTERNAL:
+ //Expected cases
+ ALOGI("camera facing: %d", info.facing);
+ break;
+ default:
+ FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (info.facing);
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check whether preview window can be configured
+TEST_F(CameraHidlTest, setPreviewWindow) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1,
+ &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+
+ Return<void> ret;
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that setting preview window fails in case device is not open
+TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus);
+ }
+ }
+}
+
+// Start and stop preview checking whether it gets enabled in between.
+TEST_F(CameraHidlTest, startStopPreview) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1,
+ &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+
+ startPreview(device1);
+
+ Return<bool> returnBoolStatus = device1->previewEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Start preview without active preview window. Preview should start as soon
+// as a valid active window gets configured.
+TEST_F(CameraHidlTest, startStopPreviewDelayed) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ startPreview(device1);
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ //Preview should get enabled now
+ Return<bool> returnBoolStatus = device1->previewEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Verify that image capture behaves as expected along with preview callbacks.
+TEST_F(CameraHidlTest, takePicture) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+ startPreview(device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
+ device1);
+ enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+ device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l);
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+ device1);
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Image capture should fail in case preview didn't get enabled first.
+TEST_F(CameraHidlTest, takePictureFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that image capture can be cancelled.
+TEST_F(CameraHidlTest, cancelPicture) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->cancelPicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Image capture cancel should fail when image capture is not running.
+TEST_F(CameraHidlTest, cancelPictureFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ Return<Status> returnStatus = device1->cancelPicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Test basic video recording.
+TEST_F(CameraHidlTest, startStopRecording) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+ startPreview(device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ mVideoBufferIndex = UINT32_MAX;
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+
+ bool videoMetaEnabled = false;
+ Return<Status> returnStatus = device1->storeMetaDataInBuffers(true);
+ ASSERT_TRUE(returnStatus.isOk());
+ // It is allowed for devices to not support this feature
+ ASSERT_TRUE((Status::OK == returnStatus) ||
+ (Status::OPERATION_NOT_SUPPORTED == returnStatus));
+ if (Status::OK == returnStatus) {
+ videoMetaEnabled = true;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1);
+ Return<bool> returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+
+ returnStatus = device1->startRecording();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l);
+ ASSERT_NE(UINT32_MAX, mVideoBufferIndex);
+ disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
+ device1);
+ }
+
+ returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ Return<void> ret;
+ if (videoMetaEnabled) {
+ ret = device1->releaseRecordingFrameHandle(mVideoData,
+ mVideoBufferIndex, mVideoNativeHandle);
+ ASSERT_TRUE(ret.isOk());
+ } else {
+ ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex);
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ ret = device1->stopRecording();
+ ASSERT_TRUE(ret.isOk());
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// It shouldn't be possible to start recording without enabling preview first.
+TEST_F(CameraHidlTest, startRecordingFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<bool> returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+
+ Return<Status> returnStatus = device1->startRecording();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check autofocus support if available.
+TEST_F(CameraHidlTest, autoFocus) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
+ CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
+ CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ CameraParameters::FOCUS_MODE_AUTO)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+ enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
+
+ for (auto &iter : focusModes) {
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ iter)) {
+ continue;
+ }
+
+ cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter);
+ setParameters(device1, cameraParams);
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mNotifyMessage = NotifyCallbackMsg::ERROR;
+ }
+
+ Return<Status> returnStatus = device1->autoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (NotifyCallbackMsg::FOCUS != mNotifyMessage) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kAutoFocusTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+ }
+ }
+
+ disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// In case autofocus is supported verify that it can be cancelled.
+TEST_F(CameraHidlTest, cancelAutoFocus) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ CameraParameters::FOCUS_MODE_AUTO)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ // It should be fine to call before preview starts.
+ ASSERT_EQ(Status::OK, device1->cancelAutoFocus());
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ // It should be fine to call after preview starts too.
+ Return<Status> returnStatus = device1->cancelAutoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->autoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->cancelAutoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Check whether face detection is available and try to enable&disable.
+TEST_F(CameraHidlTest, sendCommandFaceDetection) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ int32_t hwFaces = cameraParams.getInt(
+ CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW);
+ int32_t swFaces = cameraParams.getInt(
+ CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW);
+ if ((0 >= hwFaces) && (0 >= swFaces)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ if (0 < hwFaces) {
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_HW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(
+ CommandType::STOP_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_HW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ }
+
+ if (0 < swFaces) {
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_SW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(
+ CommandType::STOP_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_SW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ }
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Check whether smooth zoom is available and try to enable&disable.
+TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ const char *smoothZoomStr = cameraParams.get(
+ CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED);
+ bool smoothZoomSupported = ((nullptr != smoothZoomStr) &&
+ (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ?
+ true : false;
+ if (!smoothZoomSupported) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ int32_t maxZoom = cameraParams.getInt(
+ CameraParameters::KEY_MAX_ZOOM);
+ ASSERT_TRUE(0 < maxZoom);
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+ setParameters(device1, cameraParams);
+
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_SMOOTH_ZOOM, maxZoom, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM,
+ 0, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Basic sanity tests related to camera parameters.
+TEST_F(CameraHidlTest, getSetParameters) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ int32_t width, height;
+ cameraParams.getPictureSize(&width, &height);
+ ASSERT_TRUE((0 < width) && (0 < height));
+ cameraParams.getPreviewSize(&width, &height);
+ ASSERT_TRUE((0 < width) && (0 < height));
+ int32_t minFps, maxFps;
+ cameraParams.getPreviewFpsRange(&minFps, &maxFps);
+ ASSERT_TRUE((0 < minFps) && (0 < maxFps));
+ ASSERT_NE(nullptr, cameraParams.getPreviewFormat());
+ ASSERT_NE(nullptr, cameraParams.getPictureFormat());
+ ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG,
+ cameraParams.getPictureFormat()) == 0);
+
+ const char *flashMode = cameraParams.get(
+ CameraParameters::KEY_FLASH_MODE);
+ ASSERT_TRUE((nullptr == flashMode) || (strcmp(
+ CameraParameters::FLASH_MODE_OFF, flashMode) == 0));
+
+ const char *wbMode = cameraParams.get(
+ CameraParameters::KEY_WHITE_BALANCE);
+ ASSERT_TRUE((nullptr == wbMode) || (strcmp(
+ CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0));
+
+ const char *effect = cameraParams.get(CameraParameters::KEY_EFFECT);
+ ASSERT_TRUE((nullptr == effect) || (strcmp(
+ CameraParameters::EFFECT_NONE, effect) == 0));
+
+ ::android::Vector<::android::Size> previewSizes;
+ cameraParams.getSupportedPreviewSizes(previewSizes);
+ ASSERT_FALSE(previewSizes.empty());
+ ::android::Vector<::android::Size> pictureSizes;
+ cameraParams.getSupportedPictureSizes(pictureSizes);
+ ASSERT_FALSE(pictureSizes.empty());
+ const char *previewFormats = cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+ ASSERT_NE(nullptr, previewFormats);
+ ::android::String8 previewFormatsString(previewFormats);
+ ASSERT_TRUE(previewFormatsString.contains(
+ CameraParameters::PIXEL_FORMAT_YUV420SP));
+ ASSERT_NE(nullptr, cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS));
+ ASSERT_NE(nullptr, cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES));
+ const char *focusModes = cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
+ ASSERT_NE(nullptr, focusModes);
+ ::android::String8 focusModesString(focusModes);
+ const char *focusMode = cameraParams.get(
+ CameraParameters::KEY_FOCUS_MODE);
+ ASSERT_NE(nullptr, focusMode);
+ // Auto focus mode should be default
+ if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) {
+ ASSERT_TRUE(strcmp(
+ CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0);
+ }
+ ASSERT_TRUE(0 < cameraParams.getInt(
+ CameraParameters::KEY_FOCAL_LENGTH));
+ int32_t horizontalViewAngle = cameraParams.getInt(
+ CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE);
+ ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle));
+ int32_t verticalViewAngle = cameraParams.getInt(
+ CameraParameters::KEY_VERTICAL_VIEW_ANGLE);
+ ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle));
+ int32_t jpegQuality = cameraParams.getInt(
+ CameraParameters::KEY_JPEG_QUALITY);
+ ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality));
+ int32_t jpegThumbQuality = cameraParams.getInt(
+ CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+ ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality));
+
+ cameraParams.setPictureSize(pictureSizes[0].width,
+ pictureSizes[0].height);
+ cameraParams.setPreviewSize(previewSizes[0].width,
+ previewSizes[0].height);
+
+ setParameters(device1, cameraParams);
+ getParameters(device1, &cameraParams /*out*/);
+
+ cameraParams.getPictureSize(&width, &height);
+ ASSERT_TRUE((pictureSizes[0].width == width) &&
+ (pictureSizes[0].height == height));
+ cameraParams.getPreviewSize(&width, &height);
+ ASSERT_TRUE((previewSizes[0].width == width) &&
+ (previewSizes[0].height == height));
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that the static camera characteristics can be retrieved
+// successfully.
+TEST_F(CameraHidlTest, getCameraCharacteristics) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device3_2->getCameraCharacteristics(
+ [&](auto status, const auto& chars) {
+ ALOGI("getCameraCharacteristics returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ const camera_metadata_t* metadata = (camera_metadata_t*) chars.data();
+ size_t expectedSize = chars.size();
+ ASSERT_EQ(0, validate_camera_metadata_structure(metadata, &expectedSize));
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // characteristics keys we've defined.
+ ASSERT_GT(entryCount, 0u);
+ ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+//In case it is supported verify that torch can be enabled.
+//Check for corresponding toch callbacks as well.
+TEST_F(CameraHidlTest, setTorchMode) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ bool torchControlSupported = false;
+ Return<void> ret;
+
+ ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ [&](auto status, bool support) {
+ ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+ (int)status, support);
+ ASSERT_EQ(Status::OK, status);
+ torchControlSupported = support;
+ });
+
+
+ sp<TorchProviderCb> cb = new TorchProviderCb(this);
+ Return<Status> returnStatus = env->mProvider->setCallback(cb);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("setTorchMode: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ returnStatus = device3_2->setTorchMode(TorchMode::ON);
+ ASSERT_TRUE(returnStatus.isOk());
+ if (!torchControlSupported) {
+ ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+ } else {
+ ASSERT_TRUE(returnStatus == Status::OK ||
+ returnStatus == Status::OPERATION_NOT_SUPPORTED);
+ if (returnStatus == Status::OK) {
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ }
+
+ returnStatus = device3_2->setTorchMode(TorchMode::OFF);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+ }
+ }
+ }
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ returnStatus = device1->setTorchMode(TorchMode::ON);
+ ASSERT_TRUE(returnStatus.isOk());
+ if (!torchControlSupported) {
+ ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+ } else {
+ ASSERT_TRUE(returnStatus == Status::OK ||
+ returnStatus == Status::OPERATION_NOT_SUPPORTED);
+ if (returnStatus == Status::OK) {
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ }
+
+ returnStatus = device1->setTorchMode(TorchMode::OFF);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+ }
+ }
+ }
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+
+ returnStatus = env->mProvider->setCallback(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+// Check dump functionality.
+TEST_F(CameraHidlTest, dumpState) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ Return<void> ret;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ ret= device3_2->dumpState(handle);
+ ASSERT_TRUE(ret.isOk());
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ Return<Status> returnStatus = device1->dumpState(handle);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+ }
+ }
+}
+
+// Open, dumpStates, then close
+TEST_F(CameraHidlTest, openClose) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ Return<void> ret;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("openClose: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+ sp<ICameraDeviceSession> session;
+ ret = device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ ret = device3_2->dumpState(handle);
+ ASSERT_TRUE(ret.isOk());
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ // TODO: test all session API calls return INTERNAL_ERROR after close
+ // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ Return<Status> returnStatus = device1->dumpState(handle);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check whether all common default request settings can be sucessfully
+// constructed.
+TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ Return<void> ret;
+ ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+ sp<ICameraDeviceSession> session;
+ ret = device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
+ t <= (uint32_t) RequestTemplate::MANUAL; t++) {
+ RequestTemplate reqTemplate = (RequestTemplate) t;
+ ret = session->constructDefaultRequestSettings(
+ reqTemplate,
+ [&](auto status, const auto& req) {
+ ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
+ if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
+ reqTemplate == RequestTemplate::MANUAL) {
+ // optional templates
+ ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT);
+ } else {
+ ASSERT_EQ(Status::OK, status);
+ }
+
+ if (status == Status::OK) {
+ const camera_metadata_t* metadata =
+ (camera_metadata_t*) req.data();
+ size_t expectedSize = req.size();
+ ASSERT_EQ(0, validate_camera_metadata_structure(
+ metadata, &expectedSize));
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // request keys we've defined for each template
+ ASSERT_GT(entryCount, 0u);
+ ALOGI("template %u metadata entry count is %zu", t, entryCount);
+ } else {
+ ASSERT_EQ(0u, req.size());
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that all supported stream formats and sizes can be configured
+// successfully.
+TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputStreams;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ outputStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputStreams));
+ ASSERT_NE(0u, outputStreams.size());
+
+ int32_t streamId = 0;
+ for (auto &it : outputStreams) {
+ Stream stream = {streamId, StreamType::OUTPUT,
+ static_cast<uint32_t> (it.width),
+ static_cast<uint32_t> (it.height),
+ static_cast<PixelFormat> (it.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {stream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(1u, halConfig.streams.size());
+ ASSERT_EQ(halConfig.streams[0].id, streamId);
+ });
+ ASSERT_TRUE(ret.isOk());
+ streamId++;
+ }
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check for correct handling of invalid/incorrect configuration parameters.
+TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputStreams;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ outputStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputStreams));
+ ASSERT_NE(0u, outputStreams.size());
+
+ int32_t streamId = 0;
+ Stream stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (0),
+ static_cast<uint32_t> (0),
+ static_cast<PixelFormat> (outputStreams[0].format),
+ 0, 0, StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {stream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+ (Status::INTERNAL_ERROR == s));
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (UINT32_MAX),
+ static_cast<uint32_t> (UINT32_MAX),
+ static_cast<PixelFormat> (outputStreams[0].format),
+ 0, 0, StreamRotation::ROTATION_0};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ for (auto &it : outputStreams) {
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (it.width),
+ static_cast<uint32_t> (it.height),
+ static_cast<PixelFormat> (UINT32_MAX),
+ 0, 0, StreamRotation::ROTATION_0};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (it.width),
+ static_cast<uint32_t> (it.height),
+ static_cast<PixelFormat> (it.format),
+ 0, 0, static_cast<StreamRotation> (UINT32_MAX)};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check whether all supported ZSL output stream combinations can be
+// configured successfully.
+TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> inputStreams;
+ std::vector<AvailableZSLInputOutput> inputOutputMap;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ Status rc = isZSLModeAvailable(staticMeta);
+ if (Status::METHOD_NOT_SUPPORTED == rc) {
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+ ASSERT_EQ(Status::OK, rc);
+
+ inputStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ inputStreams));
+ ASSERT_NE(0u, inputStreams.size());
+
+ inputOutputMap.clear();
+ ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta,
+ inputOutputMap));
+ ASSERT_NE(0u, inputOutputMap.size());
+
+ int32_t streamId = 0;
+ for (auto &inputIter : inputOutputMap) {
+ AvailableStream input;
+ ASSERT_EQ(Status::OK,
+ findLargestSize(inputStreams, inputIter.inputFormat, input));
+ ASSERT_NE(0u, inputStreams.size());
+
+ AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
+ inputIter.outputFormat};
+ std::vector<AvailableStream> outputStreams;
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputStreams, &outputThreshold));
+ for (auto &outputIter : outputStreams) {
+ Stream zslStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (input.width),
+ static_cast<uint32_t> (input.height),
+ static_cast<PixelFormat> (input.format),
+ GRALLOC_USAGE_HW_CAMERA_ZSL, 0,
+ StreamRotation::ROTATION_0};
+ Stream inputStream = {streamId++, StreamType::INPUT,
+ static_cast<uint32_t> (input.width),
+ static_cast<uint32_t> (input.height),
+ static_cast<PixelFormat> (input.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ Stream outputStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (outputIter.width),
+ static_cast<uint32_t> (outputIter.height),
+ static_cast<PixelFormat> (outputIter.format), 0, 0,
+ StreamRotation::ROTATION_0};
+
+ ::android::hardware::hidl_vec<Stream> streams = {
+ inputStream, zslStream, outputStream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(3u, halConfig.streams.size());
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that all supported preview + still capture stream combinations
+// can be configured successfully.
+TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputBlobStreams;
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
+ static_cast<int32_t>(PixelFormat::BLOB)};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ outputBlobStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputBlobStreams, &blobThreshold));
+ ASSERT_NE(0u, outputBlobStreams.size());
+
+ outputPreviewStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputPreviewStreams, &previewThreshold));
+ ASSERT_NE(0u, outputPreviewStreams.size());
+
+ int32_t streamId = 0;
+ for (auto &blobIter : outputBlobStreams) {
+ for (auto &previewIter : outputPreviewStreams) {
+ Stream previewStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (previewIter.width),
+ static_cast<uint32_t> (previewIter.height),
+ static_cast<PixelFormat> (previewIter.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ Stream blobStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (blobIter.width),
+ static_cast<uint32_t> (blobIter.height),
+ static_cast<PixelFormat> (blobIter.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {
+ previewStream, blobStream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(2u, halConfig.streams.size());
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// In case constrained mode is supported, test whether it can be
+// configured. Additionally check for common invalid inputs when
+// using this mode.
+TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ Status rc = isConstrainedModeAvailable(staticMeta);
+ if (Status::METHOD_NOT_SUPPORTED == rc) {
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+ ASSERT_EQ(Status::OK, rc);
+
+ AvailableStream hfrStream;
+ rc = pickConstrainedModeSize(staticMeta, hfrStream);
+ ASSERT_EQ(Status::OK, rc);
+
+ int32_t streamId = 0;
+ Stream stream = {streamId, StreamType::OUTPUT,
+ static_cast<uint32_t> (hfrStream.width),
+ static_cast<uint32_t> (hfrStream.height),
+ static_cast<PixelFormat> (hfrStream.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {stream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(1u, halConfig.streams.size());
+ ASSERT_EQ(halConfig.streams[0].id, streamId);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (0),
+ static_cast<uint32_t> (0),
+ static_cast<PixelFormat> (hfrStream.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+ (Status::INTERNAL_ERROR == s));
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (UINT32_MAX),
+ static_cast<uint32_t> (UINT32_MAX),
+ static_cast<PixelFormat> (hfrStream.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ stream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (hfrStream.width),
+ static_cast<uint32_t> (hfrStream.height),
+ static_cast<PixelFormat> (UINT32_MAX), 0, 0,
+ StreamRotation::ROTATION_0};
+ streams[0] = stream;
+ config = {streams,
+ StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration) {
+ ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that all supported video + snapshot stream combinations can
+// be configured successfully.
+TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputBlobStreams;
+ std::vector<AvailableStream> outputVideoStreams;
+ AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+ static_cast<int32_t>(PixelFormat::BLOB)};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_t *staticMeta;
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ outputBlobStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputBlobStreams, &blobThreshold));
+ ASSERT_NE(0u, outputBlobStreams.size());
+
+ outputVideoStreams.clear();
+ ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+ outputVideoStreams, &videoThreshold));
+ ASSERT_NE(0u, outputVideoStreams.size());
+
+ int32_t streamId = 0;
+ for (auto &blobIter : outputBlobStreams) {
+ for (auto &videoIter : outputVideoStreams) {
+ Stream videoStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (videoIter.width),
+ static_cast<uint32_t> (videoIter.height),
+ static_cast<PixelFormat> (videoIter.format), 0, 0,
+ StreamRotation::ROTATION_0};
+ Stream blobStream = {streamId++, StreamType::OUTPUT,
+ static_cast<uint32_t> (blobIter.width),
+ static_cast<uint32_t> (blobIter.height),
+ static_cast<PixelFormat> (blobIter.format),
+ GRALLOC_USAGE_HW_VIDEO_ENCODER, 0,
+ StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {
+ videoStream, blobStream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = session->configureStreams(config, [streamId] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(2u, halConfig.streams.size());
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Generate and verify a camera capture request
+TEST_F(CameraHidlTest, processCaptureRequestPreview) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
+ previewStream.height,
+ static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat),
+ 1, halStreamConfig.streams[0].producerUsage,
+ halStreamConfig.streams[0].consumerUsage);
+ ASSERT_NE(nullptr, gb.get());
+ StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+ bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+ BufferStatus::OK, nullptr, nullptr};
+ ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+ outputBuffer};
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
+ CaptureRequest request = {frameNumber, settings,
+ emptyInputBuffer, outputBuffers};
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mResultFrameNumber = frameNumber;
+ }
+
+ Status status = Status::INTERNAL_ERROR;
+ uint32_t numRequestProcessed = 0;
+ Return<void> returnStatus = session->processCaptureRequest(
+ {request},
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_EQ(numRequestProcessed, 1u);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (0 == mResultBuffers.size()) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+
+ request.frameNumber++;
+ //Empty settings should be supported after the first call
+ //for repeating requests.
+ request.settings.setToExternal(nullptr, 0, true);
+ mResultBuffers.clear();
+ mResultFrameNumber++;
+ }
+
+ returnStatus = session->processCaptureRequest(
+ {request},
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_EQ(numRequestProcessed, 1u);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (0 == mResultBuffers.size()) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+ }
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Test whether an incorrect capture request with missing settings will
+// be reported correctly.
+TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
+ previewStream.height,
+ static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat),
+ 1, halStreamConfig.streams[0].producerUsage,
+ halStreamConfig.streams[0].consumerUsage);
+
+ StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+ bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+ BufferStatus::OK, nullptr, nullptr};
+ ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+ outputBuffer};
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
+ CaptureRequest request = {frameNumber, settings,
+ emptyInputBuffer, outputBuffers};
+
+ //Settings were not correctly initialized, we should fail here
+ Status status = Status::OK;
+ uint32_t numRequestProcessed = 0;
+ Return<void> ret = session->processCaptureRequest(
+ {request},
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Status::INTERNAL_ERROR, status);
+ ASSERT_EQ(numRequestProcessed, 0u);
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check whether an invalid capture request with missing output buffers
+// will be reported correctly.
+TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputBlobStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
+ CaptureRequest request = {frameNumber, settings,
+ emptyInputBuffer, emptyOutputBuffers};
+
+ //Output buffers are missing, we should fail here
+ Status status = Status::OK;
+ uint32_t numRequestProcessed = 0;
+ ret = session->processCaptureRequest(
+ {request},
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Status::INTERNAL_ERROR, status);
+ ASSERT_EQ(numRequestProcessed, 0u);
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Generate, trigger and flush a preview request
+TEST_F(CameraHidlTest, flushPreviewRequest) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
+ previewStream.height,
+ static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat),
+ 1, halStreamConfig.streams[0].producerUsage,
+ halStreamConfig.streams[0].consumerUsage);
+ ASSERT_NE(nullptr, gb.get());
+ StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+ bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+ BufferStatus::OK, nullptr, nullptr};
+ ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+ outputBuffer};
+ const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
+ CaptureRequest request = {frameNumber, settings,
+ emptyInputBuffer, outputBuffers};
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mErrors.clear();
+ mResultFrameNumber = frameNumber;
+ }
+
+ Status status = Status::INTERNAL_ERROR;
+ uint32_t numRequestProcessed = 0;
+ ret = session->processCaptureRequest(
+ {request},
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_EQ(numRequestProcessed, 1u);
+ //Flush before waiting for request to complete.
+ Return<Status> returnStatus = session->flush();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while ((0 == mResultBuffers.size()) && (0 == mErrors.size())) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+
+ if (mErrors.empty()) {
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+ } else {
+ for (auto &error : mErrors) {
+ switch (error.errorCode) {
+ case ErrorCode::ERROR_REQUEST:
+ case ErrorCode::ERROR_RESULT:
+ //Expected
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ //Expected as well
+ ASSERT_EQ(frameNumber, error.frameNumber);
+ ASSERT_EQ(previewStream.id, error.errorStreamId);
+ break;
+ case ErrorCode::ERROR_DEVICE:
+ default:
+ FAIL() <<"Unexpected error:" << static_cast<uint32_t> (error.errorCode);
+ }
+ }
+ }
+ }
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that camera flushes correctly without any pending requests.
+TEST_F(CameraHidlTest, flushEmpty) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mErrors.clear();
+ mResultFrameNumber = 0;
+ }
+
+ Return<Status> returnStatus = session->flush();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+ ASSERT_EQ(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ ASSERT_TRUE(mErrors.empty());
+ ASSERT_TRUE(mResultBuffers.empty());
+ }
+
+ Return<void> ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Retrieve all valid output stream resolutions from the camera
+// static characteristics.
+Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
+ std::vector<AvailableStream> &outputStreams,
+ const AvailableStream *threshold) {
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+ if ((0 != rc) || (0 != (entry.count % 4))) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ for (size_t i = 0; i < entry.count; i+=4) {
+ if (ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT ==
+ entry.data.i32[i + 3]) {
+ if(nullptr == threshold) {
+ AvailableStream s = {entry.data.i32[i+1],
+ entry.data.i32[i+2], entry.data.i32[i]};
+ outputStreams.push_back(s);
+ } else {
+ if ((threshold->format == entry.data.i32[i]) &&
+ (threshold->width >= entry.data.i32[i+1]) &&
+ (threshold->height >= entry.data.i32[i+2])) {
+ AvailableStream s = {entry.data.i32[i+1],
+ entry.data.i32[i+2], threshold->format};
+ outputStreams.push_back(s);
+ }
+ }
+ }
+
+ }
+
+ return Status::OK;
+}
+
+// Check if constrained mode is supported by using the static
+// camera characteristics.
+Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {
+ Status ret = Status::METHOD_NOT_SUPPORTED;
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if (0 != rc) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ for (size_t i = 0; i < entry.count; i++) {
+ if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO ==
+ entry.data.u8[i]) {
+ ret = Status::OK;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+// Pick the largest supported HFR mode from the static camera
+// characteristics.
+Status CameraHidlTest::pickConstrainedModeSize(camera_metadata_t *staticMeta,
+ AvailableStream &hfrStream) {
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &entry);
+ if (0 != rc) {
+ return Status::METHOD_NOT_SUPPORTED;
+ } else if (0 != (entry.count % 5)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ hfrStream = {0, 0,
+ static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ for (size_t i = 0; i < entry.count; i+=5) {
+ int32_t w = entry.data.i32[i];
+ int32_t h = entry.data.i32[i+1];
+ if ((hfrStream.width * hfrStream.height) < (w *h)) {
+ hfrStream.width = w;
+ hfrStream.height = h;
+ }
+ }
+
+ return Status::OK;
+}
+
+// Check whether ZSL is available using the static camera
+// characteristics.
+Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) {
+ Status ret = Status::METHOD_NOT_SUPPORTED;
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if (0 != rc) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ for (size_t i = 0; i < entry.count; i++) {
+ if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
+ entry.data.u8[i]) ||
+ (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING ==
+ entry.data.u8[i]) ){
+ ret = Status::OK;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+// Retrieve the reprocess input-output format map from the static
+// camera characteristics.
+Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,
+ std::vector<AvailableZSLInputOutput> &inputOutputMap) {
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, &entry);
+ if ((0 != rc) || (0 >= entry.count)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ const int32_t* contents = &entry.data.i32[0];
+ for (size_t i = 0; i < entry.count; ) {
+ int32_t inputFormat = contents[i++];
+ int32_t length = contents[i++];
+ for (int32_t j = 0; j < length; j++) {
+ int32_t outputFormat = contents[i+j];
+ AvailableZSLInputOutput zslEntry = {inputFormat, outputFormat};
+ inputOutputMap.push_back(zslEntry);
+ }
+ i += length;
+ }
+
+ return Status::OK;
+}
+
+// Search for the largest stream size for a given format.
+Status CameraHidlTest::findLargestSize(
+ const std::vector<AvailableStream> &streamSizes, int32_t format,
+ AvailableStream &result) {
+ result = {0, 0, 0};
+ for (auto &iter : streamSizes) {
+ if (format == iter.format) {
+ if ((result.width * result.height) < (iter.width * iter.height)) {
+ result = iter;
+ }
+ }
+ }
+
+ return (result.format == format) ? Status::OK : Status::ILLEGAL_ARGUMENT;
+}
+
+// Check whether the camera device supports specific focus mode.
+Status CameraHidlTest::isAutoFocusModeAvailable(
+ ::android::CameraParameters &cameraParams,
+ const char *mode) {
+ ::android::String8 focusModes(cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_FOCUS_MODES));
+ if (focusModes.contains(mode)) {
+ return Status::OK;
+ }
+
+ return Status::METHOD_NOT_SUPPORTED;
+}
+
+// Open a device session and configure a preview stream.
+void CameraHidlTest::configurePreviewStream(const std::string &name,
+ const CameraHidlEnvironment* env,
+ const AvailableStream *previewThreshold,
+ sp<ICameraDeviceSession> *session /*out*/,
+ Stream *previewStream /*out*/,
+ HalStreamConfiguration *halStreamConfig /*out*/) {
+ ASSERT_NE(nullptr, env);
+ ASSERT_NE(nullptr, session);
+ ASSERT_NE(nullptr, previewStream);
+ ASSERT_NE(nullptr, halStreamConfig);
+
+ std::vector<AvailableStream> outputPreviewStreams;
+ ::android::sp<ICameraDevice> device3_2;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<DeviceCb> cb = new DeviceCb(this);
+ ret = device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ *session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_t *staticMeta;
+ ret = device3_2->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ outputPreviewStreams.clear();
+ auto rc = getAvailableOutputStreams(staticMeta,
+ outputPreviewStreams, previewThreshold);
+ free_camera_metadata(staticMeta);
+ ASSERT_EQ(Status::OK, rc);
+ ASSERT_FALSE(outputPreviewStreams.empty());
+
+ *previewStream = {0, StreamType::OUTPUT,
+ static_cast<uint32_t> (outputPreviewStreams[0].width),
+ static_cast<uint32_t> (outputPreviewStreams[0].height),
+ static_cast<PixelFormat> (outputPreviewStreams[0].format),
+ 0, 0, StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {*previewStream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = (*session)->configureStreams(config, [&] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(1u, halConfig.streams.size());
+ *halStreamConfig = halConfig;
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Open a device session with empty callbacks and return static metadata.
+void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<ICameraDeviceSession> *session /*out*/,
+ camera_metadata_t **staticMeta /*out*/) {
+ ASSERT_NE(nullptr, env);
+ ASSERT_NE(nullptr, session);
+ ASSERT_NE(nullptr, staticMeta);
+
+ ::android::sp<ICameraDevice> device3_2;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb();
+ ret = device3_2->open(cb, [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ *session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device3_2->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ *staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, *staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Open a particular camera device.
+void CameraHidlTest::openCameraDevice(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) {
+ ASSERT_TRUE(nullptr != env);
+ ASSERT_TRUE(nullptr != device1);
+
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ *device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
+ Return<Status> returnStatus = (*device1)->open(deviceCb);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+// Initialize and configure a preview window.
+void CameraHidlTest::setupPreviewWindow(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
+ sp<BufferItemHander> *bufferHandler /*out*/) {
+ ASSERT_NE(nullptr, device.get());
+ ASSERT_NE(nullptr, bufferItemConsumer);
+ ASSERT_NE(nullptr, bufferHandler);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ *bufferItemConsumer = new BufferItemConsumer(consumer,
+ GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
+ ASSERT_NE(nullptr, (*bufferItemConsumer).get());
+ *bufferHandler = new BufferItemHander(*bufferItemConsumer);
+ ASSERT_NE(nullptr, (*bufferHandler).get());
+ (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
+ sp<Surface> surface = new Surface(producer);
+ sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);
+
+ auto rc = device->setPreviewWindow(previewCb);
+ ASSERT_TRUE(rc.isOk());
+ ASSERT_EQ(Status::OK, rc);
+}
+
+// Stop camera preview and close camera.
+void CameraHidlTest::stopPreviewAndClose(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->stopPreview();
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device->close();
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Enable a specific camera message type.
+void CameraHidlTest::enableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->enableMsgType(msgType);
+ ASSERT_TRUE(ret.isOk());
+
+ Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+}
+
+// Disable a specific camera message type.
+void CameraHidlTest::disableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->disableMsgType(msgType);
+ ASSERT_TRUE(ret.isOk());
+
+ Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+}
+
+// Wait until a specific frame notification arrives.
+void CameraHidlTest::waitForFrameLocked(DataCallbackMsg msgFrame,
+ std::unique_lock<std::mutex> &l) {
+ while (msgFrame != mDataMessageTypeReceived) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+}
+
+// Start preview on a particular camera device
+void CameraHidlTest::startPreview(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<Status> returnStatus = device->startPreview();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+// Retrieve camera parameters.
+void CameraHidlTest::getParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ CameraParameters *cameraParams /*out*/) {
+ ASSERT_NE(nullptr, cameraParams);
+
+ Return<void> ret;
+ ret = device->getParameters([&] (const ::android::hardware::hidl_string& params) {
+ ASSERT_FALSE(params.empty());
+ ::android::String8 paramString(params.c_str());
+ (*cameraParams).unflatten(paramString);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Set camera parameters.
+void CameraHidlTest::setParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ const CameraParameters &cameraParams) {
+ Return<Status> returnStatus = device->setParameters(
+ cameraParams.flatten().string());
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/camera/provider/README.md b/camera/provider/README.md
new file mode 100644
index 0000000..0718fb1
--- /dev/null
+++ b/camera/provider/README.md
@@ -0,0 +1,37 @@
+## Camera Provider HAL ##
+---
+
+## Overview: ##
+
+The camera.provider HAL is used by the Android camera service to discover,
+query, and open individual camera devices.
+
+It also allows for direct control of the flash unit of camera devices that have
+one, for turning on/off torch mode.
+
+More complete information about the Android camera HAL and subsystem can be found at
+[source.android.com](http://source.android.com/devices/camera/index.html).
+
+## Version history: ##
+
+## types.hal: ##
+
+### @0.0:
+
+Common enum and struct definitions for all camera HAL interfaces. Does not
+define any interfaces of its own.
+
+## ICameraProvider.hal: ##
+
+### @2.4:
+
+First HIDL version of the camera provider HAL, closely matching the feature set
+and operation of the pre-HIDL camera HAL module v2.4.
+
+## ICameraProviderCallback.hal: ##
+
+### @2.4:
+
+First HIDL version of the camara provider HAL callback interface, closely
+matching the feature set and operation of the pre-HIDL camera HAL module
+callbacks v2.4.
diff --git a/configstore/1.0/ISurfaceFlingerConfigs.hal b/configstore/1.0/ISurfaceFlingerConfigs.hal
index 4403a90..3b5c1b0 100644
--- a/configstore/1.0/ISurfaceFlingerConfigs.hal
+++ b/configstore/1.0/ISurfaceFlingerConfigs.hal
@@ -16,6 +16,96 @@
package android.hardware.configstore@1.0;
interface ISurfaceFlingerConfigs {
+ /*
+ * The following two methods define (respectively):
+ *
+ * - The phase offset between hardware vsync and when apps are woken up by the
+ * Choreographer callback
+ * - The phase offset between hardware vsync and when SurfaceFlinger wakes up
+ * to consume input
+ *
+ * Their values may be tuned to trade off between display pipeline latency (both
+ * overall latency and the lengths of the app --> SF and SF --> display phases)
+ * and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
+ * while interacting with the device). The default values must produce a
+ * relatively low amount of jitter at the expense of roughly two frames of
+ * app --> display latency, and unless significant testing is performed to avoid
+ * increased display jitter (both manual investigation using systrace [1] and
+ * automated testing using dumpsys gfxinfo [2] are recommended), they should not
+ * be modified.
+ *
+ * [1] https://developer.android.com/studio/profile/systrace.html
+ * [2] https://developer.android.com/training/testing/performance.html
+ */
vsyncEventPhaseOffsetNs() generates (OptionalInt64 value);
- useTripleFramebuffer() generates (OptionalBool value);
+ vsyncSfEventPhaseOffsetNs() generates (OptionalInt64 value);
+
+ /*
+ * Instruct the Render Engine to use EGL_IMG_context_priority hint if
+ * availabe.
+ */
+ useContextPriority() generates(OptionalBool value);
+
+ /*
+ * hasWideColorDisplay indicates that the device has
+ * or can support a wide-color display, e.g. color space
+ * greater than sRGB. Typical display may have same
+ * color primaries as DCI-P3.
+ * Indicate support for this feature by setting
+ * TARGET_HAS_WIDE_COLOR_DISPLAY to true in BoardConfig.mk
+ * This also means that the device is color managed.
+ * A color managed device will use the appropriate
+ * display mode depending on the content on the screen.
+ * Default is sRGB.
+ */
+ hasWideColorDisplay() generates (OptionalBool value);
+
+ /*
+ * hwHdrDisplay indicates that the device has
+ * or can support an HDR (High Dynamic Range) display.
+ * Typically an HDR display is also wide-color.
+ * Indicate support for this feature by setting
+ * TARGET_HAS_HDR_DISPLAY to true in BoardConfig.mk
+ */
+ hasHDRDisplay() generates (OptionalBool value);
+
+ /*
+ * Specify the offset in nanoseconds to add to vsync time when timestamping
+ * present fences.
+ */
+ presentTimeOffsetFromVSyncNs() generates(OptionalInt64 value);
+
+ /*
+ * Some hardware can do RGB->YUV conversion more efficiently in hardware
+ * controlled by HWC than in hardware controlled by the video encoder.
+ * This instruct VirtualDisplaySurface to use HWC for such conversion on
+ * GL composition.
+ */
+ useHwcForRGBtoYUV() generates(OptionalBool value);
+
+ /*
+ * Maximum dimension supported by HWC for virtual display.
+ * Must be equals to min(max_width, max_height).
+ */
+ maxVirtualDisplaySize() generates (OptionalUInt64 value);
+
+ /*
+ * Indicates if Sync framework is available. Sync framework provides fence
+ * mechanism which significantly reduces buffer processing latency.
+ */
+ hasSyncFramework() generates(OptionalBool value);
+
+ /*
+ * Return true if surface flinger should use vr flinger for compatible vr
+ * apps, false otherwise. Devices that will never be running vr apps should
+ * return false to avoid extra resource usage. Daydream ready devices must
+ * return true for full vr support.
+ */
+ useVrFlinger() generates (OptionalBool value);
+
+ /*
+ * Controls the number of buffers SurfaceFlinger will allocate for use in
+ * FramebufferSurface.
+ */
+ maxFrameBufferAcquiredBuffers() generates(OptionalInt64 value);
};
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
index 5d62b15..9469ab4 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
@@ -19,20 +19,108 @@
return Void();
}
-Return<void> SurfaceFlingerConfigs::useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) {
- bool value = false;
-#ifdef USE_TRIPLE_FRAMEBUFFER
- value = true;
+Return<void> SurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) {
+#ifdef SF_VSYNC_EVENT_PHASE_OFFSET_NS
+ _hidl_cb({true, SF_VSYNC_EVENT_PHASE_OFFSET_NS});
+ LOG(INFO) << "sfvsync event phase offset ns = " << SF_VSYNC_EVENT_PHASE_OFFSET_NS;
+#else
+ _hidl_cb({false, 0});
#endif
- _hidl_cb({true, value});
- LOG(INFO) << "SurfaceFlinger FrameBuffer: " << (value ? "triple" : "double");
return Void();
}
-// Methods from ::android::hidl::base::V1_0::IBase follow.
+Return<void> SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hidl_cb) {
+#ifdef USE_CONTEXT_PRIORITY
+ _hidl_cb({true, USE_CONTEXT_PRIORITY});
+ LOG(INFO) << "SurfaceFlinger useContextPriority=" << USE_CONTEXT_PRIORITY;
+#else
+ _hidl_cb({false, false});
+#endif
+ return Void();
+}
-ISurfaceFlingerConfigs* HIDL_FETCH_ISurfaceFlingerConfigs(const char* /* name */) {
- return new SurfaceFlingerConfigs();
+Return<void> SurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) {
+#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
+ _hidl_cb({true, NUM_FRAMEBUFFER_SURFACE_BUFFERS});
+ LOG(INFO) << "SurfaceFlinger FrameBuffer max acquired buffers : " << NUM_FRAMEBUFFER_SURFACE_BUFFERS;
+#else
+ _hidl_cb({false, 0});
+#endif
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) {
+ bool value = false;
+#ifdef HAS_WIDE_COLOR_DISPLAY
+ value = true;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger Display: " << (value ? "Wide Color" : "Standard Color");
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::hasSyncFramework(hasSyncFramework_cb _hidl_cb) {
+ bool value = true;
+#ifdef RUNNING_WITHOUT_SYNC_FRAMEWORK
+ value = false;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger hasSyncFramework: " << value;
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) {
+ bool value = false;
+#ifdef HAS_HDR_DISPLAY
+ value = true;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger Display: " << (value ? "HDR" : "SDR");
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) {
+#ifdef PRESENT_TIME_OFFSET_FROM_VSYNC_NS
+ _hidl_cb({true, PRESENT_TIME_OFFSET_FROM_VSYNC_NS});
+ LOG(INFO) << "SurfaceFlinger presentTimeStampOffsetNs = " << PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
+#else
+ _hidl_cb({false, 0});
+#endif
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::useHwcForRGBtoYUV(useHwcForRGBtoYUV_cb _hidl_cb) {
+ bool value = false;
+#ifdef FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS
+ value = true;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger forceHwcForRGBtoYUV: " << value;
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::maxVirtualDisplaySize(maxVirtualDisplaySize_cb _hidl_cb) {
+ uint64_t maxSize = 0;
+#ifdef MAX_VIRTUAL_DISPLAY_DIMENSION
+ maxSize = MAX_VIRTUAL_DISPLAY_DIMENSION;
+ _hidl_cb({true, maxSize});
+ LOG(INFO) << "SurfaceFlinger MaxVirtualDisplaySize: " << maxSize;
+#else
+ _hidl_cb({false, maxSize});
+#endif
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::useVrFlinger(useVrFlinger_cb _hidl_cb) {
+ bool value = false;
+ bool specified = false;
+#ifdef USE_VR_FLINGER
+ value = true;
+ specified = true;
+#endif
+ _hidl_cb({specified, value});
+ LOG(INFO) << "SurfaceFlinger UseVrFlinger: " << (value ? "true" : "false");
+ return Void();
}
} // namespace implementation
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.h b/configstore/1.0/default/SurfaceFlingerConfigs.h
index c9652fc..9300511 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.h
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.h
@@ -25,14 +25,21 @@
struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs {
// Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs follow.
Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
- Return<void> useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) override;
+ Return<void> vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
+ Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override;
+ Return<void> hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) override;
+ Return<void> hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) override;
+ Return<void> presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) override;
+ Return<void> useHwcForRGBtoYUV(useHwcForRGBtoYUV_cb _hidl_cb) override;
+ Return<void> maxVirtualDisplaySize(maxVirtualDisplaySize_cb _hidl_cb) override;
+ Return<void> hasSyncFramework(hasSyncFramework_cb _hidl_cb) override;
+ Return<void> useVrFlinger(useVrFlinger_cb _hidl_cb) override;
+ Return<void> maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
-extern "C" ISurfaceFlingerConfigs* HIDL_FETCH_ISurfaceFlingerConfigs(const char* name);
-
} // namespace implementation
} // namespace V1_0
} // namespace configstore
diff --git a/configstore/1.0/default/surfaceflinger.mk b/configstore/1.0/default/surfaceflinger.mk
index 5a946f4..9e3d4d4 100644
--- a/configstore/1.0/default/surfaceflinger.mk
+++ b/configstore/1.0/default/surfaceflinger.mk
@@ -5,6 +5,48 @@
LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
endif
-ifeq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),3)
- LOCAL_CFLAGS += -DUSE_TRIPLE_FRAMEBUFFER
+ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
+ LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
+
+ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true)
+ LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY
+endif
+
+ifeq ($(TARGET_HAS_HDR_DISPLAY),true)
+ LOCAL_CFLAGS += -DHAS_HDR_DISPLAY
+endif
+
+ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
+ LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
+else
+ LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0
+endif
+
+ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true)
+ LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS
+endif
+
+ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),)
+ LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION)
+endif
+
+ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
+ LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
+endif
+
+ifneq ($(USE_VR_FLINGER),)
+ LOCAL_CFLAGS += -DUSE_VR_FLINGER
+endif
+
+ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
+ LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
endif
diff --git a/contexthub/1.0/Android.bp b/contexthub/1.0/Android.bp
new file mode 100644
index 0000000..8cd4acb
--- /dev/null
+++ b/contexthub/1.0/Android.bp
@@ -0,0 +1,69 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.contexthub@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IContexthub.hal",
+ "IContexthubCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.contexthub@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.contexthub@1.0",
+ srcs: [
+ ":android.hardware.contexthub@1.0_hal",
+ ],
+ out: [
+ "android/hardware/contexthub/1.0/types.cpp",
+ "android/hardware/contexthub/1.0/ContexthubAll.cpp",
+ "android/hardware/contexthub/1.0/ContexthubCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.contexthub@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.contexthub@1.0",
+ srcs: [
+ ":android.hardware.contexthub@1.0_hal",
+ ],
+ out: [
+ "android/hardware/contexthub/1.0/types.h",
+ "android/hardware/contexthub/1.0/IContexthub.h",
+ "android/hardware/contexthub/1.0/IHwContexthub.h",
+ "android/hardware/contexthub/1.0/BnHwContexthub.h",
+ "android/hardware/contexthub/1.0/BpHwContexthub.h",
+ "android/hardware/contexthub/1.0/BsContexthub.h",
+ "android/hardware/contexthub/1.0/IContexthubCallback.h",
+ "android/hardware/contexthub/1.0/IHwContexthubCallback.h",
+ "android/hardware/contexthub/1.0/BnHwContexthubCallback.h",
+ "android/hardware/contexthub/1.0/BpHwContexthubCallback.h",
+ "android/hardware/contexthub/1.0/BsContexthubCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.contexthub@1.0",
+ generated_sources: ["android.hardware.contexthub@1.0_genc++"],
+ generated_headers: ["android.hardware.contexthub@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.contexthub@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/contexthub/1.0/Android.mk b/contexthub/1.0/Android.mk
new file mode 100644
index 0000000..a053986
--- /dev/null
+++ b/contexthub/1.0/Android.mk
@@ -0,0 +1,658 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.contexthub@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (AsyncEventType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/AsyncEventType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.AsyncEventType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ContextHub)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHub.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.ContextHub
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ContextHubMsg)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHubMsg.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.ContextHubMsg
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HostEndPoint)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HostEndPoint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HostEndPoint
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubAppInfo)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubAppInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubAppInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubMemoryFlag)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubMemoryFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubMemoryType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubMemoryType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemRange)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/MemRange.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.MemRange
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (NanoAppBinary)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppBinary.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.NanoAppBinary
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (NanoAppFlags)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.NanoAppFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PhysicalSensor)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/PhysicalSensor.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.PhysicalSensor
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SensorType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/SensorType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.SensorType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TransactionResult)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/TransactionResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.TransactionResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IContexthub.hal
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthub.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthub.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::IContexthub
+
+$(GEN): $(LOCAL_PATH)/IContexthub.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IContexthubCallback.hal
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthubCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::IContexthubCallback
+
+$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.contexthub@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (AsyncEventType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/AsyncEventType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.AsyncEventType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ContextHub)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHub.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.ContextHub
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ContextHubMsg)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHubMsg.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.ContextHubMsg
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HostEndPoint)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HostEndPoint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HostEndPoint
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubAppInfo)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubAppInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubAppInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubMemoryFlag)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubMemoryFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HubMemoryType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.HubMemoryType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemRange)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/MemRange.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.MemRange
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (NanoAppBinary)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppBinary.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.NanoAppBinary
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (NanoAppFlags)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.NanoAppFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PhysicalSensor)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/PhysicalSensor.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.PhysicalSensor
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SensorType)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/SensorType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.SensorType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TransactionResult)
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/TransactionResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::types.TransactionResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IContexthub.hal
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthub.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthub.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::IContexthub
+
+$(GEN): $(LOCAL_PATH)/IContexthub.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IContexthubCallback.hal
+#
+GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthubCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthubCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.contexthub@1.0::IContexthubCallback
+
+$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/contexthub/1.0/IContexthub.hal b/contexthub/1.0/IContexthub.hal
new file mode 100644
index 0000000..c0928d5
--- /dev/null
+++ b/contexthub/1.0/IContexthub.hal
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2016 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.contexthub@1.0;
+
+import IContexthubCallback;
+
+/*
+ * The Context Hub HAL provides an interface to a separate low-power processing
+ * domain that has direct access to contextual information, such as sensors.
+ * Native applications that run within a context hub are known as nanoapps, and
+ * they execute within the Context Hub Runtime Environment (CHRE), which is
+ * standardized via the CHRE API, defined elsewhere.
+ */
+interface IContexthub {
+ /*
+ * Enumerate all available context hubs on the system.
+ *
+ * @return hubs list of hubs on this system.
+ */
+ getHubs() generates (vec<ContextHub> hubs);
+
+ /*
+ * Register a callback for the HAL implementation to send asynchronous
+ * messages to the service from a context hub. There can be a maximum of
+ * one callback registered with the HAL. A call to this function when a
+ * callback has already been registered must override the previous
+ * registration.
+ *
+ * @param hubId identifier for the hub
+ * callback an implementation of the IContextHubCallbacks
+ *
+ * @return result OK on success
+ * BAD_VALUE if parameters are not sane
+ *
+ */
+ registerCallback(uint32_t hubId, IContexthubCallback cb) generates (Result result);
+
+ /**
+ * Send a message to a hub
+ *
+ * @param hubId identifier for hub to send message to
+ * msg message to be sent
+ *
+ * @return result OK if successful, error code otherwise
+ * BAD_VALUE if parameters are not sane
+ * TRANSACTION_FAILED if message send failed
+ */
+ sendMessageToHub(uint32_t hubId, ContextHubMsg msg)
+ generates (Result result);
+
+ /**
+ * Loads a nanoApp. After loading, the nanoApp's init method must be called.
+ * After the init method for nanoApp returns success, this must be indicated
+ * to the service by an asynchronous call to handleTxnResult.
+ *
+ * Loading a nanoapp must not take more than 30 seconds.
+ *
+ * Depending on the implementation, nanoApps loaded via this API may or may
+ * not persist across reboots of the hub. If they do persist, the
+ * implementation must initially place nanoApps in the disabled state upon a
+ * reboot, and not start them until a call is made to enableNanoApp(). In
+ * this case, the app must also be unloaded upon a factory reset of the
+ * device.
+ *
+ * @param hubId identifer of the contextHub
+ * appBinary contains the binary representation of the nanoApp, plus
+ * metadata
+ * transactionId transactionId for this call
+ *
+ * @return result OK if transation started
+ * BAD_VALUE if parameters are not sane
+ * TRANSACTION_PENDING if hub is busy with another
+ * load/unload transaction
+ * TRANSACTION_FAILED if load failed synchronously
+ *
+ */
+ loadNanoApp(uint32_t hubId,
+ NanoAppBinary appBinary,
+ uint32_t transactionId)
+ generates (Result result);
+
+ /**
+ * Unloads a nanoApp. Before the unload, the apps deinit method is called.
+ * After this, success must be indicated to the service through an
+ * asynchronous call to handleTxnResult.
+ *
+ * Unloading a nanoapp must not take more than 5 seconds.
+ *
+ * @param hubId identifer of the contextHub
+ * appId appIdentifier returned by the HAL
+ * msg message to be sent
+ *
+ * @return result OK if transation started
+ * BAD_VALUE if parameters are not sane
+ * TRANSACTION_PENDING if hub is busy with another
+ * load/unload transaction
+ * TRANSACTION_FAILED if unload failed synchronously
+ *
+ */
+ unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId)
+ generates (Result result);
+
+ /**
+ * Enables a nanoApp. The app's init method is called.
+ * After this, success must be indicated to the service through an
+ * asynchronous message.
+ *
+ * Enabling a nanoapp must not take more than 5 seconds.
+ *
+ * @param hubId identifer of the contextHub
+ * appId appIdentifier returned by the HAL
+ * msg message to be sent
+ *
+ * @return result OK if transation started
+ * BAD_VALUE if parameters are not sane
+ * TRANSACTION_PENDING if hub is busy with another
+ * load/unload transaction
+ * FAILED_TRANSACTION if load fails immediately
+ *
+ */
+ enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId)
+ generates (Result result);
+
+ /**
+ * Disables a nanoApp. The app's deinit method is called.
+ * After this, success must be indicated to the service through an
+ * asynchronous message.
+ *
+ * Disabling a nanoapp must not take more than 5 seconds.
+ *
+ * @param hubId identifer of the contextHub
+ * appId appIdentifier returned by the HAL
+ * msg message to be sent
+ *
+ * @return result OK if transation started
+ * BAD_VALUE if parameters are not sane
+ * TRANSACTION_PENDING if hub is busy with another
+ * load/unload transaction
+ * FAILED_TRANSACTION if load fails immediately
+ *
+ */
+ disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId)
+ generates (Result result);
+
+ /**
+ * Queries for Loaded apps on the hub
+ *
+ * @param hubId identifer of the contextHub
+ *
+ * @return apps all nanoApps on the hub.
+ * All nanoApps that can be modified by the service must
+ * be returned. A non-modifiable nanoapps must not be
+ * returned. A modifiable nanoApp is one that can be
+ * unloaded/disabled/enabled by the service.
+ *
+ */
+ queryApps(uint32_t hubId) generates (Result result);
+};
diff --git a/contexthub/1.0/IContexthubCallback.hal b/contexthub/1.0/IContexthubCallback.hal
new file mode 100644
index 0000000..9a6db4c
--- /dev/null
+++ b/contexthub/1.0/IContexthubCallback.hal
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.contexthub@1.0;
+
+interface IContexthubCallback {
+ /*
+ * This callback is passed by the Contexthub service to the HAL
+ * implementation to allow the HAL to send asynchronous messages back
+ * to the service and registered clients of the ContextHub service.
+ *
+ * @params msg : message
+ *
+ */
+ handleClientMsg(ContextHubMsg msg);
+
+ /*
+ * This callback is passed by the Contexthub service to the HAL
+ * implementation to allow the HAL to send the response for a
+ * transaction.
+ *
+ * @params txnId : transaction id whose result is being sent
+ * passed in by the service at start of transacation.
+ * result: result of transaction.
+ *
+ */
+ handleTxnResult(uint32_t txnId, TransactionResult result);
+
+ /*
+ * This callback is passed by the Contexthub service to the HAL
+ * implementation to allow the HAL to send an asynchronous event
+ * to the ContextHub service.
+ *
+ * @params msg : message
+ *
+ */
+ handleHubEvent(AsyncEventType evt);
+
+ /*
+ * This callback is passed by the Contexthub service to the HAL
+ * implementation to allow the HAL to send a notification to the service
+ * that a nanp-app has aborted.
+ * This method must be called when a nanoapp invokes chreAbort(...)).
+ *
+ * @params appId : app identifier
+ * : abortCode code passed by the nanoApp.
+ *
+ * Also see chreAbort(...)
+ *
+ */
+ handleAppAbort(uint64_t appId, uint32_t abortCode);
+
+ /*
+ * This callback is passed by the Contexthub service to the HAL
+ * implementation to allow the HAL to send information about the
+ * currently loaded and active nanoapps on the hub.
+ *
+ * @params appInfo : vector of HubAppinfo structure for each nanoApp
+ * on the hub that can be enabled, disabled and
+ * unloaded by the service. Any nanoApps that cannot
+ * be controlled by the service must not be reported.
+ * All nanoApps that can be controlled by the service
+ * must be reported.
+ */
+ handleAppsInfo(vec<HubAppInfo> appInfo);
+};
diff --git a/contexthub/1.0/default/Android.bp b/contexthub/1.0/default/Android.bp
new file mode 100644
index 0000000..78d27cc
--- /dev/null
+++ b/contexthub/1.0/default/Android.bp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+cc_library_shared {
+ name: "android.hardware.contexthub@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Contexthub.cpp"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.contexthub@1.0",
+ ],
+}
diff --git a/contexthub/1.0/default/Android.mk b/contexthub/1.0/default/Android.mk
new file mode 100644
index 0000000..538a6b2
--- /dev/null
+++ b/contexthub/1.0/default/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.contexthub@1.0-service
+LOCAL_INIT_RC := android.hardware.contexthub@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libdl \
+ libhardware \
+ libhardware_legacy \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ android.hardware.contexthub@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
new file mode 100644
index 0000000..4a6b3f2
--- /dev/null
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "Contexthub.h"
+
+#include <inttypes.h>
+
+#include <log/log.h>
+
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <hardware/context_hub.h>
+#include <sys/endian.h>
+
+#undef LOG_TAG
+#define LOG_TAG "ContextHubHalAdapter"
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_0 {
+namespace implementation {
+
+static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
+
+Contexthub::Contexthub()
+ : mInitCheck(NO_INIT),
+ mContextHubModule(nullptr),
+ mIsTransactionPending(false) {
+ const hw_module_t *module;
+
+ mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module);
+
+ if (mInitCheck != OK) {
+ ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck));
+ } else if (module == nullptr) {
+ ALOGE("hal returned succes but a null module!");
+ // Assign an error, this should not really happen...
+ mInitCheck = UNKNOWN_ERROR;
+ } else {
+ ALOGI("Loaded Context Hub module");
+ mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module);
+ }
+}
+
+bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) {
+ if (!isValidHubId(hubId)) {
+ ALOGW("%s: Hub information is null for hubHandle %d",
+ __FUNCTION__,
+ hubId);
+ return false;
+ } else {
+ msg->app_name = mCachedHubInfo[hubId].osAppName;
+ return true;
+ }
+}
+
+Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
+ std::vector<ContextHub> hubs;
+ if (isInitialized()) {
+ const context_hub_t *hubArray = nullptr;
+ size_t numHubs;
+
+ // Explicitly discarding const. HAL method discards it.
+ numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule),
+ &hubArray);
+ ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs);
+
+ mCachedHubInfo.clear();
+
+ for (size_t i = 0; i < numHubs; i++) {
+ CachedHubInformation info;
+ ContextHub c;
+
+ c.hubId = hubArray[i].hub_id;
+ c.name = hubArray[i].name;
+ c.vendor = hubArray[i].vendor;
+ c.toolchain = hubArray[i].toolchain;
+ c.toolchainVersion = hubArray[i].toolchain_version;
+ c.platformVersion = hubArray[i].platform_version;
+ c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len;
+ c.peakMips = hubArray[i].peak_mips;
+ c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw;
+ c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw;
+ c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw;
+
+ info.callBack = nullptr;
+ info.osAppName = hubArray[i].os_app_name;
+ mCachedHubInfo[hubArray[i].hub_id] = info;
+
+ hubs.push_back(c);
+ }
+ } else {
+ ALOGW("Context Hub Hal Adapter not initialized");
+ }
+
+ _hidl_cb(hubs);
+ return Void();
+}
+
+bool Contexthub::isValidHubId(uint32_t hubId) {
+ if (!mCachedHubInfo.count(hubId)) {
+ ALOGW("Hub information not found for hubId %" PRIu32, hubId);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) {
+ if (!isValidHubId(hubId)) {
+ return nullptr;
+ } else {
+ return mCachedHubInfo[hubId].callBack;
+ }
+}
+
+Return<Result> Contexthub::sendMessageToHub(uint32_t hubId,
+ const ContextHubMsg &msg) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) {
+ return Result::BAD_PARAMS;
+ }
+
+ hub_message_t txMsg = {
+ .app_name.id = msg.appName,
+ .message_type = msg.msgType,
+ .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above
+ .message = static_cast<const uint8_t *>(msg.msg.data()),
+ };
+
+ ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
+ txMsg.message_type,
+ txMsg.message_len,
+ txMsg.app_name.id);
+
+ if(mContextHubModule->send_message(hubId, &txMsg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ }
+
+ return Result::OK;
+}
+
+Return<Result> Contexthub::reboot(uint32_t hubId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ hub_message_t msg;
+
+ if (setOsAppAsDestination(&msg, hubId) == false) {
+ return Result::BAD_PARAMS;
+ }
+
+ msg.message_type = CONTEXT_HUB_OS_REBOOT;
+ msg.message_len = 0;
+ msg.message = nullptr;
+
+ if(mContextHubModule->send_message(hubId, &msg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ } else {
+ return Result::OK;
+ }
+}
+
+Return<Result> Contexthub::registerCallback(uint32_t hubId,
+ const sp<IContexthubCallback> &cb) {
+ Return<Result> retVal = Result::BAD_PARAMS;
+
+ if (!isInitialized()) {
+ // Not initilalized
+ ALOGW("Context hub not initialized successfully");
+ retVal = Result::NOT_INIT;
+ } else if (!isValidHubId(hubId)) {
+ // Initialized, but hubId is not valid
+ retVal = Result::BAD_PARAMS;
+ } else if (mContextHubModule->subscribe_messages(hubId,
+ contextHubCb,
+ this) == 0) {
+ // Initialized && valid hub && subscription successful
+ retVal = Result::OK;
+ mCachedHubInfo[hubId].callBack = cb;
+ } else {
+ // Initalized && valid hubId - but subscription unsuccessful
+ // This is likely an internal error in the HAL implementation, but we
+ // cannot add more information.
+ ALOGW("Could not subscribe to the hub for callback");
+ retVal = Result::UNKNOWN_FAILURE;
+ }
+
+ return retVal;
+}
+
+static bool isValidOsStatus(const uint8_t *msg,
+ size_t msgLen,
+ status_response_t *rsp) {
+ // Workaround a bug in some HALs
+ if (msgLen == 1) {
+ rsp->result = msg[0];
+ return true;
+ }
+
+ if (msg == nullptr || msgLen != sizeof(*rsp)) {
+ ALOGI("Received invalid response (is null : %d, size %zu)",
+ msg == nullptr ? 1 : 0,
+ msgLen);
+ return false;
+ }
+
+ memcpy(rsp, msg, sizeof(*rsp));
+
+ // No sanity checks on return values
+ return true;
+}
+
+int Contexthub::handleOsMessage(sp<IContexthubCallback> cb,
+ uint32_t msgType,
+ const uint8_t *msg,
+ int msgLen) {
+ int retVal = -1;
+
+
+ switch(msgType) {
+ case CONTEXT_HUB_APPS_ENABLE:
+ case CONTEXT_HUB_APPS_DISABLE:
+ case CONTEXT_HUB_LOAD_APP:
+ case CONTEXT_HUB_UNLOAD_APP:
+ {
+ struct status_response_t rsp;
+ TransactionResult result;
+ if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) {
+ retVal = 0;
+ result = TransactionResult::SUCCESS;
+ } else {
+ result = TransactionResult::FAILURE;
+ }
+
+ if (cb != nullptr) {
+ cb->handleTxnResult(mTransactionId, result);
+ }
+ retVal = 0;
+ mIsTransactionPending = false;
+ break;
+ }
+
+ case CONTEXT_HUB_QUERY_APPS:
+ {
+ std::vector<HubAppInfo> apps;
+ int numApps = msgLen / sizeof(hub_app_info);
+ const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg);
+
+ for (int i = 0; i < numApps; i++) {
+ hub_app_info query_info;
+ memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
+ HubAppInfo app;
+ app.appId = query_info.app_name.id;
+ app.version = query_info.version;
+ // TODO :: Add memory ranges
+
+ apps.push_back(app);
+ }
+
+ if (cb != nullptr) {
+ cb->handleAppsInfo(apps);
+ }
+ retVal = 0;
+ break;
+ }
+
+ case CONTEXT_HUB_QUERY_MEMORY:
+ {
+ // Deferring this use
+ retVal = 0;
+ break;
+ }
+
+ case CONTEXT_HUB_OS_REBOOT:
+ {
+ mIsTransactionPending = false;
+ if (cb != nullptr) {
+ cb->handleHubEvent(AsyncEventType::RESTARTED);
+ }
+ retVal = 0;
+ break;
+ }
+
+ default:
+ {
+ retVal = -1;
+ break;
+ }
+ }
+
+ return retVal;
+}
+
+int Contexthub::contextHubCb(uint32_t hubId,
+ const struct hub_message_t *rxMsg,
+ void *cookie) {
+ Contexthub *obj = static_cast<Contexthub *>(cookie);
+
+ if (rxMsg == nullptr) {
+ ALOGW("Ignoring NULL message");
+ return -1;
+ }
+
+ if (!obj->isValidHubId(hubId)) {
+ ALOGW("Invalid hub Id %" PRIu32, hubId);
+ return -1;
+ }
+
+ sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId);
+
+ if (cb == nullptr) {
+ // This should not ever happen
+ ALOGW("No callback registered, returning");
+ return -1;
+ }
+
+ if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
+ obj->handleOsMessage(cb,
+ rxMsg->message_type,
+ static_cast<const uint8_t *>(rxMsg->message),
+ rxMsg->message_len);
+ } else {
+ ContextHubMsg msg;
+
+ msg.appName = rxMsg->app_name.id;
+ msg.msgType = rxMsg->message_type;
+ msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
+ static_cast<const uint8_t *>(rxMsg->message) +
+ rxMsg->message_len);
+
+ cb->handleClientMsg(msg);
+ }
+
+ return 0;
+}
+
+Return<Result> Contexthub::unloadNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ if (mIsTransactionPending) {
+ return Result::TRANSACTION_PENDING;
+ }
+
+ hub_message_t msg;
+
+ if (setOsAppAsDestination(&msg, hubId) == false) {
+ return Result::BAD_PARAMS;
+ }
+
+ struct apps_disable_request_t req;
+
+ msg.message_type = CONTEXT_HUB_UNLOAD_APP;
+ msg.message_len = sizeof(req);
+ msg.message = &req;
+ req.app_name.id = appId;
+
+ if(mContextHubModule->send_message(hubId, &msg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ } else {
+ mTransactionId = transactionId;
+ mIsTransactionPending = true;
+ return Result::OK;
+ }
+}
+
+Return<Result> Contexthub::loadNanoApp(uint32_t hubId,
+ const NanoAppBinary& appBinary,
+ uint32_t transactionId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ if (mIsTransactionPending) {
+ return Result::TRANSACTION_PENDING;
+ }
+
+ hub_message_t hubMsg;
+
+ if (setOsAppAsDestination(&hubMsg, hubId) == false) {
+ return Result::BAD_PARAMS;
+ }
+
+ // Data from the nanoapp header is passed through HIDL as explicit fields,
+ // but the legacy HAL expects it prepended to the binary, therefore we must
+ // reconstruct it here prior to passing to the legacy HAL.
+ uint32_t targetChreApiVersion =
+ (appBinary.targetChreApiMajorVersion << 24) |
+ (appBinary.targetChreApiMinorVersion << 16);
+ const struct nano_app_binary_t header = {
+ .header_version = htole32(1),
+ .magic = htole32(NANOAPP_MAGIC),
+ .app_id.id = htole64(appBinary.appId),
+ .app_version = htole32(appBinary.appVersion),
+ .flags = htole32(appBinary.flags),
+ .hw_hub_type = htole64(0),
+ .reserved[0] = htole32(targetChreApiVersion),
+ .reserved[1] = 0,
+ };
+ const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header);
+
+ std::vector<uint8_t> binaryWithHeader(appBinary.customBinary);
+ binaryWithHeader.insert(binaryWithHeader.begin(),
+ headerBytes,
+ headerBytes + sizeof(header));
+
+ hubMsg.message_type = CONTEXT_HUB_LOAD_APP;
+ hubMsg.message_len = binaryWithHeader.size();
+ hubMsg.message = binaryWithHeader.data();
+
+ if (mContextHubModule->send_message(hubId, &hubMsg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ } else {
+ mTransactionId = transactionId;
+ mIsTransactionPending = true;
+ return Result::OK;
+ }
+}
+
+Return<Result> Contexthub::enableNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ if (mIsTransactionPending) {
+ return Result::TRANSACTION_PENDING;
+ }
+
+ hub_message_t msg;
+
+ if (setOsAppAsDestination(&msg, hubId) == false) {
+ return Result::BAD_PARAMS;
+ }
+
+ struct apps_enable_request_t req;
+
+ msg.message_type = CONTEXT_HUB_APPS_ENABLE;
+ msg.message_len = sizeof(req);
+ req.app_name.id = appId;
+ msg.message = &req;
+
+ if(mContextHubModule->send_message(hubId, &msg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ } else {
+ mTransactionId = transactionId;
+ mIsTransactionPending = true;
+ return Result::OK;
+ }
+}
+
+Return<Result> Contexthub::disableNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ if (mIsTransactionPending) {
+ return Result::TRANSACTION_PENDING;
+ }
+
+ hub_message_t msg;
+
+ if (setOsAppAsDestination(&msg, hubId) == false) {
+ return Result::BAD_PARAMS;
+ }
+
+ struct apps_disable_request_t req;
+
+ msg.message_type = CONTEXT_HUB_APPS_DISABLE;
+ msg.message_len = sizeof(req);
+ req.app_name.id = appId;
+ msg.message = &req;
+
+ if(mContextHubModule->send_message(hubId, &msg) != 0) {
+ return Result::TRANSACTION_FAILED;
+ } else {
+ mTransactionId = transactionId;
+ mIsTransactionPending = true;
+ return Result::OK;
+ }
+}
+
+Return<Result> Contexthub::queryApps(uint32_t hubId) {
+ if (!isInitialized()) {
+ return Result::NOT_INIT;
+ }
+
+ hub_message_t msg;
+
+ if (setOsAppAsDestination(&msg, hubId) == false) {
+ ALOGW("Could not find hubId %" PRIu32, hubId);
+ return Result::BAD_PARAMS;
+ }
+
+ query_apps_request_t payload;
+ payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter
+ msg.message = &payload;
+ msg.message_len = sizeof(payload);
+ msg.message_type = CONTEXT_HUB_QUERY_APPS;
+
+ if(mContextHubModule->send_message(hubId, &msg) != 0) {
+ ALOGW("Query Apps sendMessage failed");
+ return Result::TRANSACTION_FAILED;
+ }
+
+ return Result::OK;
+}
+
+bool Contexthub::isInitialized() {
+ return (mInitCheck == OK && mContextHubModule != nullptr);
+}
+
+IContexthub *HIDL_FETCH_IContexthub(const char * halName) {
+ ALOGI("%s Called for %s", __FUNCTION__, halName);
+ Contexthub *contexthub = new Contexthub;
+
+ if (!contexthub->isInitialized()) {
+ delete contexthub;
+ contexthub = nullptr;
+ }
+
+ return contexthub;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace contexthub
+} // namespace hardware
+} // namespace android
diff --git a/contexthub/1.0/default/Contexthub.h b/contexthub/1.0/default/Contexthub.h
new file mode 100644
index 0000000..236e079
--- /dev/null
+++ b/contexthub/1.0/default/Contexthub.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
+#define ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
+
+#include <unordered_map>
+
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <hardware/context_hub.h>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_0 {
+namespace implementation {
+
+struct Contexthub : public ::android::hardware::contexthub::V1_0::IContexthub {
+ Contexthub();
+
+ Return<void> getHubs(getHubs_cb _hidl_cb) override;
+
+ Return<Result> registerCallback(uint32_t hubId,
+ const sp<IContexthubCallback> &cb) override;
+
+ Return<Result> sendMessageToHub(uint32_t hubId,
+ const ContextHubMsg &msg) override;
+
+ Return<Result> loadNanoApp(uint32_t hubId,
+ const NanoAppBinary& appBinary,
+ uint32_t transactionId) override;
+
+ Return<Result> unloadNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) override;
+
+ Return<Result> enableNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) override;
+
+ Return<Result> disableNanoApp(uint32_t hubId,
+ uint64_t appId,
+ uint32_t transactionId) override;
+
+ Return<Result> queryApps(uint32_t hubId) override;
+
+ Return<Result> reboot(uint32_t hubId);
+
+ bool isInitialized();
+
+private:
+
+ struct CachedHubInformation{
+ struct hub_app_name_t osAppName;
+ sp<IContexthubCallback> callBack;
+ };
+
+ status_t mInitCheck;
+ const struct context_hub_module_t *mContextHubModule;
+ std::unordered_map<uint32_t, CachedHubInformation> mCachedHubInfo;
+
+ sp<IContexthubCallback> mCb;
+ bool mIsTransactionPending;
+ uint32_t mTransactionId;
+
+ bool isValidHubId(uint32_t hubId);
+
+ sp<IContexthubCallback> getCallBackForHubId(uint32_t hubId);
+
+ int handleOsMessage(sp<IContexthubCallback> cb,
+ uint32_t msgType,
+ const uint8_t *msg,
+ int msgLen);
+
+ static int contextHubCb(uint32_t hubId,
+ const struct hub_message_t *rxMsg,
+ void *cookie);
+
+ bool setOsAppAsDestination(hub_message_t *msg, int hubId);
+
+ DISALLOW_COPY_AND_ASSIGN(Contexthub);
+};
+
+extern "C" IContexthub *HIDL_FETCH_IContexthub(const char *name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace contexthub
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
new file mode 100644
index 0000000..5677ec2
--- /dev/null
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -0,0 +1,4 @@
+service contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
+ class hal
+ user system
+ group system
diff --git a/contexthub/1.0/default/service.cpp b/contexthub/1.0/default/service.cpp
new file mode 100644
index 0000000..8c676b4
--- /dev/null
+++ b/contexthub/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.contexthub@1.0-service"
+
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IContexthub>();
+}
diff --git a/contexthub/1.0/types.hal b/contexthub/1.0/types.hal
new file mode 100644
index 0000000..4950627
--- /dev/null
+++ b/contexthub/1.0/types.hal
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 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.contexthub@1.0;
+
+enum Result : uint32_t {
+ OK, // Success
+ UNKNOWN_FAILURE, // Failure, unknown reason
+ BAD_PARAMS, // Parameters not sane
+ NOT_INIT, // Not initialized
+ TRANSACTION_FAILED, // Transaction failed
+ TRANSACTION_PENDING, // Pending transaction, cannot accept a new request
+};
+
+enum NanoAppFlags : uint32_t {
+ SIGNED = 1 << 0,
+ ENCRYPTED = 1 << 1,
+};
+
+struct NanoAppBinary {
+ uint64_t appId; // Nanoapp identifier
+ uint32_t appVersion; // Version of the app (semantics defined by app)
+ bitfield<NanoAppFlags> flags;
+
+ // The version of the CHRE API that this nanoApp was compiled against. See
+ // the CHRE API header file chre/version.h for more information. The hub
+ // implementation must use this to confirm compatibility before loading
+ // this nanoApp.
+ uint8_t targetChreApiMajorVersion;
+ uint8_t targetChreApiMinorVersion;
+
+ // Implementation-specific binary nanoapp data. This does not include the
+ // common nanoapp header that contains the app ID, etc., as this data is
+ // explicitly passed through the other fields in this struct.
+ vec<uint8_t> customBinary;
+};
+
+enum SensorType : uint32_t {
+ RESERVED,
+ ACCELEROMETER,
+ GYROSCOPE,
+ MAGNETOMETER,
+ BAROMETER,
+ PROXIMITY_SENSOR,
+ AMBIENT_LIGHT_SENSOR,
+ STATIONARY_DETECT,
+ INSTANT_MOTION_DETECT,
+
+ GPS = 0x100,
+ // Reserving this space for variants on GPS
+
+ WIFI = 0x200,
+ // Reserving this space for variants on WIFI
+
+ AUDIO = 0x300,
+ // Reserving this space for variants on Audio
+
+ CAMERA = 0x400,
+ // Reserving this space for variants on Camera
+
+ BLE = 0x500,
+ // Reserving this space for variants on Bluetooth Low Energy
+
+ WWAN = 0x600,
+ // Reserving this space for variants on WWAN
+
+ PRIVATE_SENSOR_BASE = 0x10000,
+ // Sensor types beyond PRIVATE_SENSOR_BASE are custom types
+};
+
+struct PhysicalSensor{
+ SensorType sensorType; // From the definitions above eg: 100
+ string type; // Type as a string. eg: "GPS"
+ string name; // Identifier eg: "Bosch BMI160"
+ string vendor; // Vendor : eg "STM"
+ uint32_t version; // Version : eg 0x1001
+ uint32_t fifoReservedCount; // Batching possible in hardware. Please
+ // note that here hardware does not include
+ // the context hub itself. Thus, this
+ // definition may be different from say the
+ // number advertised in the sensors HAL
+ // which allows for batching in a hub.
+ uint32_t fifoMaxCount; // Maximum number of batchable events.
+ uint64_t minDelayMs; // In milliseconds, corresponding to highest
+ // sampling freq.
+ uint64_t maxDelayMs; // In milliseconds, corresponds to minimum
+ // sampling frequency
+ float peakPowerMw; // At max frequency & no batching, power
+ // in milliwatts
+};
+
+struct ContextHub {
+ string name; // Descriptive name eg: "Awesome Hub #1"
+ string vendor; // Hub hardware vendor eg: "Qualcomm"
+ string toolchain; // Toolchain to make binaries eg: "gcc ARM"
+ uint32_t platformVersion; // Version of the hardware : eg 0x20
+ uint32_t toolchainVersion; // Version of the toolchain : eg: 0x484
+ uint32_t hubId; // A device unique ID for this hub
+
+ float peakMips; // Peak MIPS platform can deliver
+ float stoppedPowerDrawMw; // If stopped, retention power, milliwatts
+ float sleepPowerDrawMw; // If sleeping, retention power, milliwatts
+ float peakPowerDrawMw; // For a busy CPU, power in milliwatts
+
+ vec<PhysicalSensor> connectedSensors; // Array of connected sensors
+
+ uint32_t maxSupportedMsgLen;// This is the maximum size of the message that can
+ // be sent to the hub in one chunk (in bytes)
+
+ // Machine-readable CHRE platform ID, returned to nanoapps in the CHRE API
+ // function call chreGetPlatformId(). This field pairs with
+ // chreApiMajorVersion, chreApiMinorVersion, and chrePatchVersion to fully
+ // specify the CHRE implementation version. See also the CHRE API header
+ // file chre/version.h.
+ uint64_t chrePlatformId;
+
+ // The version of the CHRE implementation returned to nanoApps in the CHRE
+ // API function call chreGetVersion(). The major and minor version specify
+ // the implemented version of the CHRE API, while the patch version
+ // describes the implementation version within the scope of the platform
+ // ID. See also the CHRE API header file chre/version.h.
+ uint8_t chreApiMajorVersion;
+ uint8_t chreApiMinorVersion;
+ uint16_t chrePatchVersion;
+};
+
+enum HostEndPoint : uint16_t {
+ BROADCAST = 0xFFFF, // The message endpoint is a broadcast end point.
+ // This value must never be used for a message from
+ // the host to the hub.
+ // If BROADCAST is specified as a destination for a
+ // message from the context hub to the ContextHub
+ // service, the message must be broadcast to all
+ // registered clients by the Context Hub service.
+ UNSPECIFIED = 0xFFFE, // The message endpoint is unspecified. This value
+ // must not be used for messages from the hub to host.
+ // This value may be used for messages from the host
+ // to the hub.
+};
+
+struct ContextHubMsg {
+ uint64_t appName; // Intended recipient (appId)
+ uint16_t hostEndPoint; // identifier for the endpoint. (also see enum HostEndPoint)
+ uint32_t msgType; // Identifier for message
+ vec<uint8_t> msg; // Message body
+};
+
+enum HubMemoryType : uint32_t {
+ MAIN = 0, // Main memory
+ SECONDARY = 1, // Secondary memory
+ TCM = 2, // Tightly coupled memory
+};
+
+enum HubMemoryFlag : uint32_t {
+ READ = 1 << 0, // Readable
+ WRITE = 1 << 1, // Writable
+ EXEC = 1 << 2, // Executable
+};
+
+struct MemRange {
+ uint32_t totalBytes; // Total capacity in bytes
+ uint32_t freeBytes; // Free capacity in bytes
+ HubMemoryType type; // Type of memory, see HubMemoryType
+ bitfield<HubMemoryFlag> flags;
+};
+
+enum AsyncEventType : uint32_t {
+ RESTARTED = 1, // Hub restarted unexpectedly
+};
+
+enum TransactionResult : int32_t {
+ SUCCESS, // Successful completion of transaction
+ FAILURE, // Failed transaction
+};
+
+struct HubAppInfo {
+ uint64_t appId; // Identifier of the app
+ uint32_t version; // Version of the app
+ vec<MemRange> memUsage; // Memory used by this app
+ bool enabled; // true if the app is currently enabled and running,
+ // or false if in the loaded but disabled state
+};
+
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..c35386d
--- /dev/null
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalContexthubV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.hardware.contexthub@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
+
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
new file mode 100644
index 0000000..765857f
--- /dev/null
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "contexthub_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <android/hardware/contexthub/1.0/IContexthubCallback.h>
+#include <android/hardware/contexthub/1.0/types.h>
+#include <android/log.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <cinttypes>
+#include <future>
+#include <utility>
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::contexthub::V1_0::AsyncEventType;
+using ::android::hardware::contexthub::V1_0::ContextHub;
+using ::android::hardware::contexthub::V1_0::ContextHubMsg;
+using ::android::hardware::contexthub::V1_0::HubAppInfo;
+using ::android::hardware::contexthub::V1_0::IContexthub;
+using ::android::hardware::contexthub::V1_0::IContexthubCallback;
+using ::android::hardware::contexthub::V1_0::NanoAppBinary;
+using ::android::hardware::contexthub::V1_0::Result;
+using ::android::hardware::contexthub::V1_0::TransactionResult;
+using ::android::sp;
+
+#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
+#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
+
+namespace {
+
+// App ID with vendor "GoogT" (Google Testing), app identifier 0x555555. This
+// app ID is reserved and must never appear in the list of loaded apps.
+constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
+
+// Helper that does explicit conversion of an enum class to its underlying/base
+// type. Useful for stream output of enum values.
+template<typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(
+ EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+// Synchronously queries IContexthub::getHubs() and returns the result
+hidl_vec<ContextHub> getHubsSync(sp<IContexthub> hubApi) {
+ hidl_vec<ContextHub> hubList;
+ std::promise<void> barrier;
+
+ hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) {
+ hubList = hubs;
+ barrier.set_value();
+ });
+ barrier.get_future().wait_for(std::chrono::seconds(1));
+
+ return hubList;
+}
+
+// Gets a list of valid hub IDs in the system
+std::vector<uint32_t> getHubIds() {
+ static std::vector<uint32_t> hubIds;
+
+ if (hubIds.size() == 0) {
+ sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+
+ if (hubApi != nullptr) {
+ for (ContextHub hub : getHubsSync(hubApi)) {
+ hubIds.push_back(hub.hubId);
+ }
+ }
+ }
+
+ ALOGD("Running tests against all %zu reported hubs", hubIds.size());
+ return hubIds;
+}
+
+// Base test fixture that initializes the HAL and makes the context hub API
+// handle available
+class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+ ASSERT_NE(hubApi, nullptr);
+
+ // getHubs() must be called at least once for proper initialization of the
+ // HAL implementation
+ getHubsSync(hubApi);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IContexthub> hubApi;
+};
+
+// Test fixture parameterized by hub ID
+class ContexthubHidlTest : public ContexthubHidlTestBase,
+ public ::testing::WithParamInterface<uint32_t> {
+ public:
+ uint32_t getHubId() {
+ return GetParam();
+ }
+
+ Result registerCallback(sp<IContexthubCallback> cb) {
+ Result result = hubApi->registerCallback(getHubId(), cb);
+ ALOGD("Registered callback, result %" PRIu32, result);
+ return result;
+ }
+};
+
+// Base callback implementation that just logs all callbacks by default
+class ContexthubCallbackBase : public IContexthubCallback {
+ public:
+ virtual Return<void> handleClientMsg(const ContextHubMsg& /*msg*/) override {
+ ALOGD("Got client message callback");
+ return Void();
+ }
+
+ virtual Return<void> handleTxnResult(
+ uint32_t txnId, TransactionResult result) override {
+ ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %"
+ PRId32, txnId, result);
+ return Void();
+ }
+
+ virtual Return<void> handleHubEvent(AsyncEventType evt) override {
+ ALOGD("Got hub event callback for event type %" PRIu32, evt);
+ return Void();
+ }
+
+ virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode)
+ override {
+ ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code "
+ "0x%" PRIx32, appId, abortCode);
+ return Void();
+ }
+
+ virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& /*appInfo*/)
+ override {
+ ALOGD("Got app info callback");
+ return Void();
+ }
+};
+
+// Wait for a callback to occur (signaled by the given future) up to the
+// provided timeout. If the future is invalid or the callback does not come
+// within the given time, returns false.
+template<class ReturnType>
+bool waitForCallback(
+ std::future<ReturnType> future,
+ ReturnType *result,
+ std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
+ auto expiration = std::chrono::system_clock::now() + timeout;
+
+ EXPECT_NE(result, nullptr);
+ EXPECT_TRUE(future.valid());
+ if (result != nullptr && future.valid()) {
+ std::future_status status = future.wait_until(expiration);
+ EXPECT_NE(status, std::future_status::timeout)
+ << "Timed out waiting for callback";
+
+ if (status == std::future_status::ready) {
+ *result = future.get();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Ensures that the metadata reported in getHubs() is sane
+TEST_F(ContexthubHidlTestBase, TestGetHubs) {
+ hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+ ALOGD("System reports %zu hubs", hubs.size());
+
+ for (ContextHub hub : hubs) {
+ ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+
+ EXPECT_FALSE(hub.name.empty());
+ EXPECT_FALSE(hub.vendor.empty());
+ EXPECT_FALSE(hub.toolchain.empty());
+ EXPECT_GT(hub.peakMips, 0);
+ EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+ EXPECT_GE(hub.sleepPowerDrawMw, 0);
+ EXPECT_GT(hub.peakPowerDrawMw, 0);
+
+ // Minimum 128 byte MTU as required by CHRE API v1.0
+ EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+ }
+}
+
+TEST_P(ContexthubHidlTest, TestRegisterCallback) {
+ ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
+ ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+}
+
+TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
+ ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
+ ASSERT_OK(registerCallback(nullptr));
+}
+
+// Helper callback that puts the async appInfo callback data into a promise
+class QueryAppsCallback : public ContexthubCallbackBase {
+ public:
+ virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo)
+ override {
+ ALOGD("Got app info callback with %zu apps", appInfo.size());
+ promise.set_value(appInfo);
+ return Void();
+ }
+
+ std::promise<hidl_vec<HubAppInfo>> promise;
+};
+
+// Calls queryApps() and checks the returned metadata
+TEST_P(ContexthubHidlTest, TestQueryApps) {
+ ALOGD("TestQueryApps called, hubId %u", getHubId());
+ sp<QueryAppsCallback> cb = new QueryAppsCallback();
+ ASSERT_OK(registerCallback(cb));
+
+ Result result = hubApi->queryApps(getHubId());
+ ASSERT_OK(result);
+
+ ALOGD("Waiting for app info callback");
+ hidl_vec<HubAppInfo> appList;
+ ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
+ for (const HubAppInfo &appInfo : appList) {
+ EXPECT_NE(appInfo.appId, UINT64_C(0));
+ EXPECT_NE(appInfo.appId, kNonExistentAppId);
+ }
+}
+
+// Helper callback that puts the TransactionResult for the expectedTxnId into a
+// promise
+class TxnResultCallback : public ContexthubCallbackBase {
+ public:
+ virtual Return<void> handleTxnResult(
+ uint32_t txnId, TransactionResult result) override {
+ ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %"
+ PRIu32 ") with result %" PRId32, txnId, expectedTxnId, result);
+ if (txnId == expectedTxnId) {
+ promise.set_value(result);
+ }
+ return Void();
+ }
+
+ uint32_t expectedTxnId = 0;
+ std::promise<TransactionResult> promise;
+};
+
+// Parameterized fixture that sets the callback to TxnResultCallback
+class ContexthubTxnTest : public ContexthubHidlTest {
+ public:
+ virtual void SetUp() override {
+ ContexthubHidlTest::SetUp();
+ ASSERT_OK(registerCallback(cb));
+ }
+
+ sp<TxnResultCallback> cb = new TxnResultCallback();
+};
+
+
+// Checks cases where the hub implementation is expected to return an error, but
+// that error can be returned either synchronously or in the asynchronous
+// transaction callback. Returns an AssertionResult that can be used in
+// ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional
+// allowed error code apart from OK and TRANSACTION_FAILED, which are always
+// allowed.
+::testing::AssertionResult checkFailureSyncOrAsync(
+ Result result, Result allowedSyncResult,
+ std::future<TransactionResult>&& future) {
+ if (result == Result::OK) {
+ // No error reported synchronously - this is OK, but then we should get an
+ // async callback with a failure status
+ TransactionResult asyncResult;
+ if (!waitForCallback(std::forward<std::future<TransactionResult>>(future),
+ &asyncResult)) {
+ return ::testing::AssertionFailure()
+ << "Got successful sync result, then failed to receive async cb";
+ } else if (asyncResult == TransactionResult::SUCCESS) {
+ return ::testing::AssertionFailure()
+ << "Got successful sync result, then unexpected successful async "
+ "result";
+ }
+ } else if (result != allowedSyncResult &&
+ result != Result::TRANSACTION_FAILED) {
+ return ::testing::AssertionFailure() << "Got sync result "
+ << asBaseType(result) << ", expected TRANSACTION_FAILED or "
+ << asBaseType(allowedSyncResult);
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) {
+ ContextHubMsg msg;
+ msg.appName = kNonExistentAppId;
+ msg.msgType = 1;
+ msg.msg.resize(4);
+ std::fill(msg.msg.begin(), msg.msg.end(), 0);
+
+ ALOGD("Sending message to non-existent nanoapp");
+ Result result = hubApi->sendMessageToHub(getHubId(), msg);
+ if (result != Result::OK &&
+ result != Result::BAD_PARAMS &&
+ result != Result::TRANSACTION_FAILED) {
+ FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
+ << ", or TRANSACTION_FAILED";
+ }
+}
+
+TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) {
+ cb->expectedTxnId = 0123;
+ NanoAppBinary emptyApp;
+
+ emptyApp.appId = kNonExistentAppId;
+ emptyApp.appVersion = 1;
+ emptyApp.flags = 0;
+ emptyApp.targetChreApiMajorVersion = 1;
+ emptyApp.targetChreApiMinorVersion = 0;
+
+ ALOGD("Loading empty nanoapp");
+ Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
+ EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
+ cb->promise.get_future()));
+}
+
+TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) {
+ cb->expectedTxnId = 1234;
+
+ ALOGD("Unloading nonexistent nanoapp");
+ Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId,
+ cb->expectedTxnId);
+ EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
+ cb->promise.get_future()));
+}
+
+TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) {
+ cb->expectedTxnId = 2345;
+
+ ALOGD("Enabling nonexistent nanoapp");
+ Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId,
+ cb->expectedTxnId);
+ EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
+ cb->promise.get_future()));
+}
+
+TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) {
+ cb->expectedTxnId = 3456;
+
+ ALOGD("Disabling nonexistent nanoapp");
+ Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId,
+ cb->expectedTxnId);
+ EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
+ cb->promise.get_future()));
+}
+
+// Parameterize all SingleContexthubTest tests against each valid hub ID
+INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest,
+ ::testing::ValuesIn(getHubIds()));
+INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest,
+ ::testing::ValuesIn(getHubIds()));
+
+} // anonymous namespace
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
diff --git a/contexthub/Android.bp b/contexthub/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/contexthub/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/drm/1.0/Android.bp b/drm/1.0/Android.bp
new file mode 100644
index 0000000..0241984
--- /dev/null
+++ b/drm/1.0/Android.bp
@@ -0,0 +1,90 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.drm@1.0_hal",
+ srcs: [
+ "types.hal",
+ "ICryptoFactory.hal",
+ "ICryptoPlugin.hal",
+ "IDrmFactory.hal",
+ "IDrmPlugin.hal",
+ "IDrmPluginListener.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.drm@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.drm@1.0",
+ srcs: [
+ ":android.hardware.drm@1.0_hal",
+ ],
+ out: [
+ "android/hardware/drm/1.0/types.cpp",
+ "android/hardware/drm/1.0/CryptoFactoryAll.cpp",
+ "android/hardware/drm/1.0/CryptoPluginAll.cpp",
+ "android/hardware/drm/1.0/DrmFactoryAll.cpp",
+ "android/hardware/drm/1.0/DrmPluginAll.cpp",
+ "android/hardware/drm/1.0/DrmPluginListenerAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.drm@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.drm@1.0",
+ srcs: [
+ ":android.hardware.drm@1.0_hal",
+ ],
+ out: [
+ "android/hardware/drm/1.0/types.h",
+ "android/hardware/drm/1.0/ICryptoFactory.h",
+ "android/hardware/drm/1.0/IHwCryptoFactory.h",
+ "android/hardware/drm/1.0/BnHwCryptoFactory.h",
+ "android/hardware/drm/1.0/BpHwCryptoFactory.h",
+ "android/hardware/drm/1.0/BsCryptoFactory.h",
+ "android/hardware/drm/1.0/ICryptoPlugin.h",
+ "android/hardware/drm/1.0/IHwCryptoPlugin.h",
+ "android/hardware/drm/1.0/BnHwCryptoPlugin.h",
+ "android/hardware/drm/1.0/BpHwCryptoPlugin.h",
+ "android/hardware/drm/1.0/BsCryptoPlugin.h",
+ "android/hardware/drm/1.0/IDrmFactory.h",
+ "android/hardware/drm/1.0/IHwDrmFactory.h",
+ "android/hardware/drm/1.0/BnHwDrmFactory.h",
+ "android/hardware/drm/1.0/BpHwDrmFactory.h",
+ "android/hardware/drm/1.0/BsDrmFactory.h",
+ "android/hardware/drm/1.0/IDrmPlugin.h",
+ "android/hardware/drm/1.0/IHwDrmPlugin.h",
+ "android/hardware/drm/1.0/BnHwDrmPlugin.h",
+ "android/hardware/drm/1.0/BpHwDrmPlugin.h",
+ "android/hardware/drm/1.0/BsDrmPlugin.h",
+ "android/hardware/drm/1.0/IDrmPluginListener.h",
+ "android/hardware/drm/1.0/IHwDrmPluginListener.h",
+ "android/hardware/drm/1.0/BnHwDrmPluginListener.h",
+ "android/hardware/drm/1.0/BpHwDrmPluginListener.h",
+ "android/hardware/drm/1.0/BsDrmPluginListener.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.drm@1.0",
+ generated_sources: ["android.hardware.drm@1.0_genc++"],
+ generated_headers: ["android.hardware.drm@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.drm@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/drm/1.0/ICryptoFactory.hal b/drm/1.0/ICryptoFactory.hal
new file mode 100644
index 0000000..aeab9bc
--- /dev/null
+++ b/drm/1.0/ICryptoFactory.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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.drm@1.0;
+
+import ICryptoPlugin;
+
+/**
+ * Ref: frameworks/native/include/media/hardware/CryptoAPI.h:CryptoFactory
+ *
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ */
+interface ICryptoFactory {
+ /**
+ * Determine if a crypto scheme is supported by this HAL
+ *
+ * @param uuid identifies the crypto scheme in question
+ * @return isSupported must be true only if the scheme is supported
+ */
+ isCryptoSchemeSupported(uint8_t[16] uuid) generates(bool isSupported);
+
+ /**
+ * Create a crypto plugin for the specified uuid and scheme-specific
+ * initialization data.
+ *
+ * @param uuid uniquely identifies the drm scheme. See
+ * http://dashif.org/identifiers/protection for uuid assignments
+ * @param initData scheme-specific init data.
+ * @return status the status of the call. The HAL implementation must return
+ * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin
+ * cannot be created.
+ * @return cryptoPlugin the created ICryptoPlugin
+ */
+ createPlugin(uint8_t[16] uuid, vec<uint8_t> initData)
+ generates (Status status, ICryptoPlugin cryptoPlugin);
+};
diff --git a/drm/1.0/ICryptoPlugin.hal b/drm/1.0/ICryptoPlugin.hal
new file mode 100644
index 0000000..0a7fd26
--- /dev/null
+++ b/drm/1.0/ICryptoPlugin.hal
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 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.drm@1.0;
+
+import android.hardware.drm@1.0::types;
+
+/**
+ * Ref: frameworks/native/include/media/hardware/CryptoAPI.h:CryptoPlugin
+ *
+ * ICryptoPlugin is the HAL for vendor-provided crypto plugins.
+ * It allows crypto sessions to be opened and operated on, to
+ * load crypto keys for a codec to decrypt protected video content.
+ */
+interface ICryptoPlugin {
+ /**
+ * Check if the specified mime-type requires a secure decoder
+ * component.
+ *
+ * @param mime The content mime-type
+ * @return secureRequired must be true only if a secure decoder is required
+ * for the specified mime-type
+ */
+ requiresSecureDecoderComponent(string mime)
+ generates(bool secureRequired);
+
+ /**
+ * Notify a plugin of the currently configured resolution
+ *
+ * @param width - the display resolutions's width
+ * @param height - the display resolution's height
+ */
+ notifyResolution(uint32_t width, uint32_t height);
+
+ /**
+ * Associate a mediadrm session with this crypto session
+ *
+ * @param sessionId the MediaDrm session ID to associate with this crypto
+ * session
+ * @return status the status of the call, status must be
+ * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened, or
+ * ERROR_DRM_CANNOT_HANDLE if the operation is not supported by the drm
+ * scheme.
+ */
+ setMediaDrmSession(vec<uint8_t> sessionId) generates(Status status);
+
+ /**
+ * Set a shared memory base for subsequent decrypt operations. The buffer
+ * base is a hidl_memory which maps shared memory in the HAL module.
+ * After the shared buffer base is established, the decrypt() method
+ * receives SharedBuffer instances which specify the buffer address range
+ * for decrypt source and destination addresses.
+ *
+ * There can be multiple shared buffers per crypto plugin. The buffers
+ * are distinguished by the bufferId.
+ *
+ * @param base the base IMemory of the memory buffer identified by
+ * bufferId
+ * @param bufferId identifies the specific shared buffer for which
+ * the base is being set.
+ */
+ setSharedBufferBase(memory base, uint32_t bufferId);
+
+ /**
+ * Decrypt an array of subsamples from the source memory buffer to the
+ * destination memory buffer.
+ *
+ * @param secure a flag to indicate if a secure decoder is being used. This
+ * enables the plugin to configure buffer modes to work consistently with
+ * a secure decoder.
+ * @param the keyId for the key that should be used to do the
+ * the decryption. The keyId refers to a key in the associated
+ * MediaDrm instance.
+ * @param iv the initialization vector to use
+ * @param mode the crypto mode to use
+ * @param pattern the crypto pattern to use
+ * @param subSamples a vector of subsamples indicating the number
+ * of clear and encrypted bytes to process. This allows the decrypt
+ * call to operate on a range of subsamples in a single call
+ * @param source the input buffer for the decryption
+ * @param offset the offset of the first byte of encrypted data from
+ * the base of the source buffer
+ * @param destination the output buffer for the decryption
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_NO_LICENSE if no license keys have been
+ * loaded, ERROR_DRM_LICENSE_EXPIRED if the license keys have expired,
+ * ERROR_DRM_RESOURCE_BUSY if the resources required to perform the
+ * decryption are not available, ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION
+ * if required output protections are not active,
+ * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not opened,
+ * ERROR_DRM_DECRYPT if the decrypt operation fails, and
+ * ERROR_DRM_CANNOT_HANDLE in other failure cases.
+ * @return bytesWritten the number of bytes output from the decryption
+ * @return detailedError if the error is a vendor-specific error, the
+ * vendor's crypto HAL may provide a detailed error string to help
+ * describe the error.
+ */
+ decrypt(bool secure, uint8_t[16] keyId, uint8_t[16] iv, Mode mode,
+ Pattern pattern, vec<SubSample> subSamples,
+ SharedBuffer source, uint64_t offset, DestinationBuffer destination)
+ generates(Status status, uint32_t bytesWritten, string detailedError);
+};
diff --git a/drm/1.0/IDrmFactory.hal b/drm/1.0/IDrmFactory.hal
new file mode 100644
index 0000000..f8e4779
--- /dev/null
+++ b/drm/1.0/IDrmFactory.hal
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.drm@1.0;
+
+import IDrmPlugin;
+
+/**
+ * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmFactory
+ *
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt* protected video content.
+ */
+
+interface IDrmFactory {
+ /**
+ * Determine if a crypto scheme is supported by this HAL
+ *
+ * @param uuid identifies the crypto scheme in question
+ * @return isSupported must be true only if the scheme is supported
+ */
+ isCryptoSchemeSupported(uint8_t[16] uuid) generates(bool isSupported);
+
+ /**
+ * Determine if the HAL factory is able to construct plugins that support a
+ * given media container format specified by mimeType
+ *
+ * @param mimeType identifies the mime type in question
+ * @return isSupported must be true only if the scheme is supported
+ */
+ isContentTypeSupported(string mimeType) generates(bool isSupported);
+
+ /**
+ * Create a drm plugin instance for the specified uuid and scheme-specific
+ * initialization data.
+ *
+ * @param uuid uniquely identifies the drm scheme. See
+ * http://dashif.org/identifiers/protection for uuid assignments
+ * @param appPackageName identifies the package name of the calling
+ * application.
+ * @return status the status of the call. The HAL implementation must return
+ * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin
+ * cannot be created.
+ */
+ createPlugin(uint8_t[16] uuid, string appPackageName)
+ generates (Status status, IDrmPlugin drmPlugin);
+};
diff --git a/drm/1.0/IDrmPlugin.hal b/drm/1.0/IDrmPlugin.hal
new file mode 100644
index 0000000..083b311
--- /dev/null
+++ b/drm/1.0/IDrmPlugin.hal
@@ -0,0 +1,543 @@
+/**
+ * Copyright (C) 2016 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.drm@1.0;
+
+import IDrmPluginListener;
+
+/**
+ * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmPlugin
+ *
+ * IDrmPlugin is used to interact with a specific drm plugin that was
+ * created by IDrm::createPlugin. A drm plugin provides methods for
+ * obtaining drm keys that may be used by a codec to decrypt protected
+ * video content.
+ */
+interface IDrmPlugin {
+
+ /**
+ * Open a new session with the DrmPlugin object. A session ID is returned
+ * in the sessionId parameter.
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_NOT_PROVISIONED if the device requires
+ * provisioning before it can open a session, ERROR_DRM_RESOURCE_BUSY if
+ * there are insufficent resources available to open a session,
+ * ERROR_DRM_CANNOT_HANDLE, if openSession is not supported at the time of
+ * the call or ERROR_DRM_INVALID_STATE if the HAL is in a state where a
+ * session cannot be opened.
+ * @return sessionId the session ID for the newly opened session
+ */
+ openSession() generates (Status status, SessionId sessionId);
+
+ /**
+ * Close a session on the DrmPlugin object
+ *
+ * @param sessionId the session id the call applies to
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the session cannot be closed.
+ */
+ closeSession(SessionId sessionId) generates (Status status);
+
+ /**
+ * A key request/response exchange occurs between the app and a License
+ * Server to obtain the keys required to decrypt the content.
+ * getKeyRequest() is used to obtain an opaque key request blob that is
+ * delivered to the license server.
+ *
+ * @param scope may be a sessionId or a keySetId, depending on the
+ * specified keyType. When the keyType is OFFLINE or STREAMING,
+ * scope should be set to the sessionId the keys will be provided to.
+ * When the keyType is RELEASE, scope should be set to the keySetId
+ * of the keys being released.
+ * @param initData container-specific data, its meaning is interpreted
+ * based on the mime type provided in the mimeType parameter. It could
+ * contain, for example, the content ID, key ID or other data obtained
+ * from the content metadata that is required to generate the key request.
+ * initData may be empty when keyType is RELEASE.
+ * @param mimeType identifies the mime type of the content
+ * @param keyType specifies if the keys are to be used for streaming,
+ * offline or a release
+ * @param optionalParameters included in the key request message to
+ * allow a client application to provide additional message parameters to
+ * the server.
+ *
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+ * before it can generate a key request, ERROR_DRM_CANNOT_HANDLE if
+ * getKeyRequest is not supported at the time of the call, BAD_VALUE if any
+ * parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is in a state
+ * where a key request cannot be generated.
+ * @return request if successful, the opaque key request blob is returned
+ * @return requestType indicates type information about the returned
+ * request. The type may be one of INITIAL, RENEWAL or RELEASE. An
+ * INITIAL request is the first key request for a license. RENEWAL is a
+ * subsequent key request used to refresh the keys in a license. RELEASE
+ * corresponds to a keyType of RELEASE, which indicates keys are being
+ * released.
+ * @return defaultUrl the URL that the request may be sent to, if
+ * provided by the drm HAL. The app may choose to override this
+ * URL.
+ */
+ getKeyRequest(vec<uint8_t> scope, vec<uint8_t> initData,
+ string mimeType, KeyType keyType, KeyedVector optionalParameters)
+ generates (Status status, vec<uint8_t> request,
+ KeyRequestType requestType, string defaultUrl);
+
+ /**
+ * After a key response is received by the app, it is provided to the
+ * Drm plugin using provideKeyResponse.
+ *
+ * @param scope may be a sessionId or a keySetId depending on the type
+ * of the response. Scope should be set to the sessionId when the response
+ * is for either streaming or offline key requests. Scope should be set to
+ * the keySetId when the response is for a release request.
+ * @param response the response from the key server that is being
+ * provided to the drm HAL.
+ *
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning
+ * before it can handle the key response, ERROR_DRM_DEVICE_REVOKED if the
+ * device has been disabled by the license policy, ERROR_DRM_CANNOT_HANDLE
+ * if provideKeyResponse is not supported at the time of the call, BAD_VALUE
+ * if any parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is
+ * in a state where a key response cannot be handled.
+ * @return keySetId when the response is for an offline key request, a
+ * keySetId is returned in the keySetId vector parameter that can be used
+ * to later restore the keys to a new session with the method restoreKeys.
+ * When the response is for a streaming or release request, no keySetId is
+ * returned.
+ */
+ provideKeyResponse(vec<uint8_t> scope, vec<uint8_t> response)
+ generates (Status status, vec<uint8_t> keySetId);
+
+ /**
+ * Remove the current keys from a session
+ *
+ * @param sessionId the session id the call applies to
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the keys cannot be removed.
+ */
+ removeKeys(SessionId sessionId) generates (Status status);
+
+ /**
+ * Restore persisted offline keys into a new session
+ *
+ * @param sessionId the session id the call applies to
+ * @param keySetId identifies the keys to load, obtained from a prior
+ * call to provideKeyResponse().
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where keys cannot be restored.
+ */
+ restoreKeys(SessionId sessionId,
+ vec<uint8_t> keySetId) generates (Status status);
+
+ /**
+ * Request an informative description of the license for the session. The
+ * status is in the form of {name, value} pairs. Since DRM license policies
+ * vary by vendor, the specific status field names are determined by each
+ * DRM vendor. Refer to your DRM provider documentation for definitions of
+ * the field names for a particular drm scheme.
+ *
+ * @param sessionId the session id the call applies to
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where key status cannot be queried.
+ * @return infoList a list of name value pairs describing the license
+ */
+ queryKeyStatus(SessionId sessionId)
+ generates (Status status, KeyedVector infoList);
+
+ /**
+ * A provision request/response exchange occurs between the app and a
+ * provisioning server to retrieve a device certificate. getProvisionRequest
+ * is used to obtain an opaque provisioning request blob that is delivered
+ * to the provisioning server.
+ *
+ * @param certificateType the type of certificate requested, e.g. "X.509"
+ * @param certificateAuthority identifies the certificate authority. A
+ * certificate authority (CA) is an entity which issues digital certificates
+ * for use by other parties. It is an example of a trusted third party.
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the sessionId is invalid,
+ * ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require provisioning
+ * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
+ * request cannot be generated.
+ * @return request if successful the opaque certificate request blob
+ * is returned
+ * @return defaultUrl URL that the provisioning request should be
+ * sent to, if known by the HAL implementation. If the HAL implementation
+ * does not provide a defaultUrl, the returned string must be empty.
+ */
+ getProvisionRequest(string certificateType, string certificateAuthority)
+ generates (Status status, vec<uint8_t> request, string defaultUrl);
+
+ /**
+ * After a provision response is received by the app from a provisioning
+ * server, it is provided to the Drm HAL using provideProvisionResponse.
+ * The HAL implementation must receive the provision request and
+ * store the provisioned credentials.
+ *
+ * @param response the opaque provisioning response received by the
+ * app from a provisioning server.
+
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_DEVICE_REVOKED if the device has been
+ * disabled by the license policy, BAD_VALUE if any parameters are invalid
+ * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision
+ * response cannot be handled.
+ * @return certificate the public certificate resulting from the provisioning
+ * operation, if any. An empty vector indicates that no certificate was
+ * returned.
+ * @return wrappedKey an opaque object containing encrypted private key
+ * material to be used by signRSA when computing an RSA signature on a
+ * message, see the signRSA method.
+ */
+ provideProvisionResponse(vec<uint8_t> response) generates (Status status,
+ vec<uint8_t> certificate, vec<uint8_t> wrappedKey);
+
+ /**
+ * SecureStop is a way of enforcing the concurrent stream limit per
+ * subscriber. It can securely monitor the lifetime of sessions across
+ * device reboots by periodically persisting the session lifetime
+ * status in secure storage.
+ *
+ * A signed version of the sessionID is written to persistent storage on the
+ * device when each MediaCrypto object is created and periodically during
+ * playback. The sessionID is signed by the device private key to prevent
+ * tampering.
+ *
+ * When playback is completed the session is destroyed, and the secure
+ * stops are queried by the app. The app then delivers the secure stop
+ * message to a server which verifies the signature to confirm that the
+ * session and its keys have been removed from the device. The persisted
+ * record on the device is removed after receiving and verifying the
+ * signed response from the server.
+ */
+
+ /**
+ * Get all secure stops on the device
+ *
+ * @return status the status of the call. The status must be OK or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stops
+ * cannot be returned.
+ * @return secureStops a list of the secure stop opaque objects
+ */
+ getSecureStops() generates
+ (Status status, vec<SecureStop> secureStops);
+
+ /**
+ * Get all secure stops by secure stop ID
+ *
+ * @param secureStopId the ID of the secure stop to return. The
+ * secure stop ID is delivered by the key server as part of the key
+ * response and must also be known by the app.
+ *
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the secureStopId is invalid or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+ * cannot be returned.
+ * @return secureStop the secure stop opaque object
+ */
+
+ getSecureStop(SecureStopId secureStopId)
+ generates (Status status, SecureStop secureStop);
+
+ /**
+ * Release all secure stops on the device
+ *
+ * @return status the status of the call. The status must be OK or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure
+ * stops cannot be released.
+ */
+ releaseAllSecureStops() generates (Status status);
+
+ /**
+ * Release a secure stop by secure stop ID
+ *
+ * @param secureStopId the ID of the secure stop to release. The
+ * secure stop ID is delivered by the key server as part of the key
+ * response and must also be known by the app.
+ *
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the secureStopId is invalid or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+ * cannot be released.
+ */
+ releaseSecureStop(vec<uint8_t> secureStopId) generates (Status status);
+
+ /**
+ * A drm scheme can have properties that are settable and readable
+ * by an app. There are a few forms of property access methods,
+ * depending on the data type of the property.
+ *
+ * Property values defined by the public API are:
+ * "vendor" [string] identifies the maker of the drm scheme
+ * "version" [string] identifies the version of the drm scheme
+ * "description" [string] describes the drm scheme
+ * 'deviceUniqueId' [byte array] The device unique identifier is
+ * established during device provisioning and provides a means of
+ * uniquely identifying each device.
+ *
+ * Since drm scheme properties may vary, additional field names may be
+ * defined by each DRM vendor. Refer to your DRM provider documentation
+ * for definitions of its additional field names.
+ */
+
+ /**
+ * Read a string property value given the property name.
+ *
+ * @param propertyName the name of the property
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the property name is invalid,
+ * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+ * cannot be obtained.
+ * @return value the property value string
+ */
+ getPropertyString(string propertyName)
+ generates (Status status, string value);
+
+ /**
+ * Read a byte array property value given the property name.
+ *
+ * @param propertyName the name of the property
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the property name is invalid,
+ * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+ * cannot be obtained.
+ * @return value the property value byte array
+ */
+ getPropertyByteArray(string propertyName)
+ generates (Status status, vec<uint8_t> value);
+
+ /**
+ * Write a property string value given the property name
+ *
+ * @param propertyName the name of the property
+ * @param value the value to write
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the property name is invalid,
+ * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+ * cannot be set.
+ */
+ setPropertyString(string propertyName, string value)
+ generates (Status status);
+
+ /**
+ * Write a property byte array value given the property name
+ *
+ * @param propertyName the name of the property
+ * @param value the value to write
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: BAD_VALUE if the property name is invalid,
+ * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property
+ * cannot be set.
+ */
+ setPropertyByteArray(string propertyName, vec<uint8_t> value )
+ generates (Status status);
+
+ /**
+ * The following methods implement operations on a CryptoSession to support
+ * encrypt, decrypt, sign verify operations on operator-provided
+ * session keys.
+ */
+
+ /**
+ * Set the cipher algorithm to be used for the specified session.
+ *
+ * @param sessionId the session id the call applies to
+ * @param algorithm the algorithm to use. The string conforms to JCA
+ * Standard Names for Cipher Transforms and is case insensitive. An
+ * example algorithm is "AES/CBC/PKCS5Padding".
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the algorithm cannot be set.
+ */
+ setCipherAlgorithm(SessionId sessionId, string algorithm)
+ generates (Status status);
+
+ /**
+ * Set the MAC algorithm to be used for computing hashes in a session.
+ *
+ * @param sessionId the session id the call applies to
+ * @param algorithm the algorithm to use. The string conforms to JCA
+ * Standard Names for Mac Algorithms and is case insensitive. An example MAC
+ * algorithm string is "HmacSHA256".
+ * @return status the status of the call. The status must be OK or one of the
+ * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the algorithm cannot be set.
+ */
+ setMacAlgorithm(SessionId sessionId, string algorithm)
+ generates (Status status);
+
+ /**
+ * Encrypt the provided input buffer with the cipher algorithm specified by
+ * setCipherAlgorithm and the key selected by keyId, and return the
+ * encrypted data.
+ *
+ * @param sessionId the session id the call applies to
+ * @param keyId the ID of the key to use for encryption
+ * @param input the input data to encrypt
+ * @param iv the initialization vector to use for encryption
+ * @return status the status of the call. The status must be OK or one of the
+ * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not opened,
+ * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the encrypt operation cannot be performed.
+ * @return output the decrypted data
+ */
+ encrypt(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> input,
+ vec<uint8_t> iv) generates (Status status, vec<uint8_t> output);
+
+ /**
+ * Decrypt the provided input buffer with the cipher algorithm
+ * specified by setCipherAlgorithm and the key selected by keyId,
+ * and return the decrypted data.
+ *
+ * @param sessionId the session id the call applies to
+ * @param keyId the ID of the key to use for decryption
+ * @param input the input data to decrypt
+ * @param iv the initialization vector to use for decryption
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the decrypt operation cannot be
+ * performed.
+ * @return output the decrypted data
+ */
+ decrypt(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> input,
+ vec<uint8_t> iv) generates (Status status, vec<uint8_t> output);
+
+ /**
+ * Compute a signature over the provided message using the mac algorithm
+ * specified by setMacAlgorithm and the key selected by keyId and return
+ * the signature.
+ *
+ * @param sessionId the session id the call applies to
+ * @param keyId the ID of the key to use for decryption
+ * @param message the message to compute a signature over
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the sign operation cannot be
+ * performed.
+ * @return signature the computed signature
+ */
+ sign(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> message)
+ generates (Status status, vec<uint8_t> signature);
+
+ /**
+ * Compute a hash of the provided message using the mac algorithm specified
+ * by setMacAlgorithm and the key selected by keyId, and compare with the
+ * expected result.
+ *
+ * @param sessionId the session id the call applies to
+ * @param keyId the ID of the key to use for decryption
+ * @param message the message to compute a hash of
+ * @param signature the signature to verify
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not
+ * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE
+ * if the HAL is in a state where the verify operation cannot be
+ * performed.
+ * @return match true if the signature is verified positively,
+ * false otherwise.
+ */
+ verify(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> message,
+ vec<uint8_t> signature) generates (Status status, bool match);
+
+ /**
+ * Compute an RSA signature on the provided message using the specified
+ * algorithm.
+ *
+ * @param sessionId the session id the call applies to
+ * @param algorithm the signing algorithm, such as "RSASSA-PSS-SHA1"
+ * or "PKCS1-BlockType1"
+ * @param message the message to compute the signature on
+ * @param wrappedKey the private key returned during provisioning as
+ * returned by provideProvisionResponse.
+ * @return status the status of the call. The status must be OK or one of
+ * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is
+ * not opened, BAD_VALUE if any parameters are invalid or
+ * ERROR_DRM_INVALID_STATE if the HAL is in a state where the signRSA
+ * operation cannot be performed.
+ * @return signature the RSA signature computed over the message
+ */
+ signRSA(SessionId sessionId, string algorithm, vec<uint8_t> message,
+ vec<uint8_t> wrappedkey)
+ generates (Status status, vec<uint8_t> signature);
+
+ /**
+ * Plugins call the following methods to deliver events to the
+ * java app.
+ */
+
+ /**
+ * Set a listener for a drm session. This allows the drm HAL to
+ * make asynchronous calls back to the client of IDrm.
+ *
+ * @param listener instance of IDrmPluginListener to receive the events
+ */
+ setListener(IDrmPluginListener listener);
+
+ /**
+ * Legacy event sending method, it sends events of various types using a
+ * single overloaded set of parameters. This form is deprecated.
+ *
+ * @param eventType the type of the event
+ * @param sessionId identifies the session the event originated from
+ * @param data event-specific data blob
+ */
+ sendEvent(EventType eventType, SessionId sessionId, vec<uint8_t> data);
+
+ /**
+ * Send a license expiration update to the listener. The expiration
+ * update indicates how long the current license is valid before it
+ * needs to be renewed.
+ *
+ * @param sessionId identifies the session the event originated from
+ * @param expiryTimeInMS the time when the keys need to be renewed.
+ * The time is in milliseconds, relative to the Unix epoch. A time of 0
+ * indicates that the keys never expire.
+ */
+ sendExpirationUpdate(SessionId sessionId, int64_t expiryTimeInMS);
+
+ /**
+ * Send a keys change event to the listener. The keys change event
+ * indicates the status of each key in the session. Keys can be
+ * indicated as being usable, expired, outputnotallowed or statuspending.
+ *
+ * @param sessionId identifies the session the event originated from
+ * @param keyStatusList indicates the status for each key ID in the
+ * session.
+ * @param hasNewUsableKey indicates if the event includes at least one
+ * key that has become usable.
+ */
+ sendKeysChange(SessionId sessionId, vec<KeyStatus> keyStatusList,
+ bool hasNewUsableKey);
+};
diff --git a/drm/1.0/IDrmPluginListener.hal b/drm/1.0/IDrmPluginListener.hal
new file mode 100644
index 0000000..15ce008
--- /dev/null
+++ b/drm/1.0/IDrmPluginListener.hal
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 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.drm@1.0;
+
+import android.hardware.drm@1.0::types;
+
+/**
+ * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmPluginListener
+ */
+
+/**
+ * IDrmPluginListener is a listener interface for Drm events sent from an
+ * IDrmPlugin instance.
+ */
+interface IDrmPluginListener {
+
+ /**
+ * Legacy event sending method, it sends events of various types using a
+ * single overloaded set of parameters. This form is deprecated.
+ *
+ * @param eventType the type of the event
+ * @param sessionId identifies the session the event originated from
+ * @param data event-specific data blob
+ */
+ oneway sendEvent(EventType eventType, SessionId sessionId,
+ vec<uint8_t> data);
+
+ /**
+ * Send a license expiration update to the listener. The expiration
+ * update indicates how long the current keys are valid before they
+ * need to be renewed.
+ *
+ * @param sessionId identifies the session the event originated from
+ * @param expiryTimeInMS the time when the keys need to be renewed.
+ * The time is in milliseconds, relative to the Unix epoch. A time
+ * of 0 indicates that the keys never expire.
+ */
+ oneway sendExpirationUpdate(SessionId sessionId, int64_t expiryTimeInMS);
+
+ /**
+ * Send a keys change event to the listener. The keys change event
+ * indicates the status of each key in the session. Keys can be
+ * indicated as being usable, expired, outputnotallowed or statuspending.
+ *
+ * @param sessionId identifies the session the event originated from
+ * @param keyStatusList indicates the status for each key ID in the
+ * session.
+ * @param hasNewUsableKey indicates if the event includes at least one
+ * key that has become usable.
+ */
+ oneway sendKeysChange(SessionId sessionId, vec<KeyStatus> keyStatusList,
+ bool hasNewUsableKey);
+};
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk
new file mode 100644
index 0000000..f2334a0
--- /dev/null
+++ b/drm/1.0/default/Android.mk
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2016 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.
+
+
+############# Build legacy drm service ############
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.drm@1.0-service
+LOCAL_INIT_RC := android.hardware.drm@1.0-service.rc
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.drm@1.0 \
+ android.hidl.memory@1.0 \
+ libhidlbase \
+ libhidltransport \
+ libhardware \
+ liblog \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ hardware/interfaces/drm
+
+# TODO: The legacy DRM plugins only support 32-bit. They need
+# to be migrated to 64-bit (b/18948909)
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_EXECUTABLE)
+
+############# Build legacy drm impl library ############
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.drm@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ DrmFactory.cpp \
+ DrmPlugin.cpp \
+ CryptoFactory.cpp \
+ CryptoPlugin.cpp \
+ TypeConvert.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.drm@1.0 \
+ android.hidl.memory@1.0 \
+ libhidlbase \
+ libhidlmemory \
+ libhidltransport \
+ liblog \
+ libmediadrm \
+ libstagefright_foundation \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/native/include \
+ frameworks/av/include
+
+# TODO: The legacy DRM plugins only support 32-bit. They need
+# to be migrated to 64-bit (b/18948909)
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/1.0/default/CryptoFactory.cpp b/drm/1.0/default/CryptoFactory.cpp
new file mode 100644
index 0000000..e46233d
--- /dev/null
+++ b/drm/1.0/default/CryptoFactory.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-impl"
+
+#include "CryptoFactory.h"
+#include "CryptoPlugin.h"
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+ CryptoFactory::CryptoFactory() :
+ loader("/vendor/lib/mediadrm", "createCryptoFactory") {
+ }
+
+ // Methods from ::android::hardware::drm::V1_0::ICryptoFactory follow.
+ Return<bool> CryptoFactory::isCryptoSchemeSupported(
+ const hidl_array<uint8_t, 16>& uuid) {
+ for (size_t i = 0; i < loader.factoryCount(); i++) {
+ if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Return<void> CryptoFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid,
+ const hidl_vec<uint8_t>& initData, createPlugin_cb _hidl_cb) {
+ for (size_t i = 0; i < loader.factoryCount(); i++) {
+ if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) {
+ android::CryptoPlugin *legacyPlugin = NULL;
+ status_t status = loader.getFactory(i)->createPlugin(uuid.data(),
+ initData.data(), initData.size(), &legacyPlugin);
+ CryptoPlugin *newPlugin = NULL;
+ if (legacyPlugin == NULL) {
+ ALOGE("Crypto legacy HAL: failed to create crypto plugin");
+ } else {
+ newPlugin = new CryptoPlugin(legacyPlugin);
+ }
+ _hidl_cb(toStatus(status), newPlugin);
+ return Void();
+ }
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, NULL);
+ return Void();
+ }
+
+ ICryptoFactory* HIDL_FETCH_ICryptoFactory(const char* /* name */) {
+ return new CryptoFactory();
+ }
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/CryptoFactory.h b/drm/1.0/default/CryptoFactory.h
new file mode 100644
index 0000000..412b557
--- /dev/null
+++ b/drm/1.0/default/CryptoFactory.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H
+#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <hidl/Status.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/PluginLoader.h>
+#include <media/SharedLibrary.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::drm::V1_0::ICryptoFactory;
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct CryptoFactory : public ICryptoFactory {
+ CryptoFactory();
+ virtual ~CryptoFactory() {}
+
+ // Methods from ::android::hardware::drm::V1_0::ICryptoFactory follow.
+
+ Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
+ override;
+
+ Return<void> createPlugin(const hidl_array<uint8_t, 16>& uuid,
+ const hidl_vec<uint8_t>& initData, createPlugin_cb _hidl_cb)
+ override;
+
+private:
+ android::PluginLoader<android::CryptoFactory> loader;
+
+ CryptoFactory(const CryptoFactory &) = delete;
+ void operator=(const CryptoFactory &) = delete;
+};
+
+extern "C" ICryptoFactory* HIDL_FETCH_ICryptoFactory(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
new file mode 100644
index 0000000..9c51b15
--- /dev/null
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-impl"
+
+#include "CryptoPlugin.h"
+#include "TypeConvert.h"
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/Log.h>
+
+using android::hardware::hidl_memory;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+ // Methods from ::android::hardware::drm::V1_0::ICryptoPlugin follow
+ Return<bool> CryptoPlugin::requiresSecureDecoderComponent(
+ const hidl_string& mime) {
+ return mLegacyPlugin->requiresSecureDecoderComponent(mime);
+ }
+
+ Return<void> CryptoPlugin::notifyResolution(uint32_t width,
+ uint32_t height) {
+ mLegacyPlugin->notifyResolution(width, height);
+ return Void();
+ }
+
+ Return<Status> CryptoPlugin::setMediaDrmSession(
+ const hidl_vec<uint8_t>& sessionId) {
+ return toStatus(mLegacyPlugin->setMediaDrmSession(toVector(sessionId)));
+ }
+
+ Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base,
+ uint32_t bufferId) {
+ mSharedBufferMap[bufferId] = mapMemory(base);
+ return Void();
+ }
+
+ Return<void> CryptoPlugin::decrypt(bool secure,
+ const hidl_array<uint8_t, 16>& keyId,
+ const hidl_array<uint8_t, 16>& iv, Mode mode,
+ const Pattern& pattern, const hidl_vec<SubSample>& subSamples,
+ const SharedBuffer& source, uint64_t offset,
+ const DestinationBuffer& destination,
+ decrypt_cb _hidl_cb) {
+
+ if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set");
+ return Void();
+ }
+
+ if (destination.type == BufferType::SHARED_MEMORY) {
+ const SharedBuffer& dest = destination.nonsecureMemory;
+ if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination decrypt buffer base not set");
+ return Void();
+ }
+ }
+
+ android::CryptoPlugin::Mode legacyMode;
+ switch(mode) {
+ case Mode::UNENCRYPTED:
+ legacyMode = android::CryptoPlugin::kMode_Unencrypted;
+ break;
+ case Mode::AES_CTR:
+ legacyMode = android::CryptoPlugin::kMode_AES_CTR;
+ break;
+ case Mode::AES_CBC_CTS:
+ legacyMode = android::CryptoPlugin::kMode_AES_WV;
+ break;
+ case Mode::AES_CBC:
+ legacyMode = android::CryptoPlugin::kMode_AES_CBC;
+ break;
+ }
+ android::CryptoPlugin::Pattern legacyPattern;
+ legacyPattern.mEncryptBlocks = pattern.encryptBlocks;
+ legacyPattern.mSkipBlocks = pattern.skipBlocks;
+
+ android::CryptoPlugin::SubSample *legacySubSamples =
+ new android::CryptoPlugin::SubSample[subSamples.size()];
+
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ legacySubSamples[i].mNumBytesOfClearData
+ = subSamples[i].numBytesOfClearData;
+ legacySubSamples[i].mNumBytesOfEncryptedData
+ = subSamples[i].numBytesOfEncryptedData;
+ }
+
+ AString detailMessage;
+ sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
+
+ if (source.offset + offset + source.size > sourceBase->getSize()) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+ return Void();
+ }
+
+ uint8_t *base = static_cast<uint8_t *>
+ (static_cast<void *>(sourceBase->getPointer()));
+ void *srcPtr = static_cast<void *>(base + source.offset + offset);
+
+ void *destPtr = NULL;
+ if (destination.type == BufferType::SHARED_MEMORY) {
+ const SharedBuffer& destBuffer = destination.nonsecureMemory;
+ sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
+ if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+ return Void();
+ }
+ destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+ } else if (destination.type == BufferType::NATIVE_HANDLE) {
+ native_handle_t *handle = const_cast<native_handle_t *>(
+ destination.secureMemory.getNativeHandle());
+ destPtr = static_cast<void *>(handle);
+ }
+ ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
+ legacyMode, legacyPattern, srcPtr, legacySubSamples,
+ subSamples.size(), destPtr, &detailMessage);
+
+ delete[] legacySubSamples;
+
+ uint32_t status;
+ uint32_t bytesWritten;
+
+ if (result >= 0) {
+ status = android::OK;
+ bytesWritten = result;
+ } else {
+ status = result;
+ bytesWritten = 0;
+ }
+
+ _hidl_cb(toStatus(status), bytesWritten, detailMessage.c_str());
+ return Void();
+ }
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/CryptoPlugin.h b/drm/1.0/default/CryptoPlugin.h
new file mode 100644
index 0000000..11cc2aa
--- /dev/null
+++ b/drm/1.0/default/CryptoPlugin.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
+#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <hidl/Status.h>
+#include <media/hardware/CryptoAPI.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::drm::V1_0::Mode;
+using ::android::hardware::drm::V1_0::Pattern;
+using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+struct CryptoPlugin : public ICryptoPlugin {
+ CryptoPlugin(android::CryptoPlugin *plugin) : mLegacyPlugin(plugin) {}
+
+ ~CryptoPlugin() {delete mLegacyPlugin;}
+
+ // Methods from ::android::hardware::drm::V1_0::ICryptoPlugin
+ // follow.
+
+ Return<bool> requiresSecureDecoderComponent(const hidl_string& mime)
+ override;
+
+ Return<void> notifyResolution(uint32_t width, uint32_t height) override;
+
+ Return<Status> setMediaDrmSession(const hidl_vec<uint8_t>& sessionId)
+ override;
+
+ Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base,
+ uint32_t bufferId) override;
+
+ Return<void> decrypt(bool secure, const hidl_array<uint8_t, 16>& keyId,
+ const hidl_array<uint8_t, 16>& iv, Mode mode, const Pattern& pattern,
+ const hidl_vec<SubSample>& subSamples, const SharedBuffer& source,
+ uint64_t offset, const DestinationBuffer& destination,
+ decrypt_cb _hidl_cb) override;
+
+private:
+ android::CryptoPlugin *mLegacyPlugin;
+ std::map<uint32_t, sp<IMemory> > mSharedBufferMap;
+
+ CryptoPlugin() = delete;
+ CryptoPlugin(const CryptoPlugin &) = delete;
+ void operator=(const CryptoPlugin &) = delete;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
diff --git a/drm/1.0/default/DrmFactory.cpp b/drm/1.0/default/DrmFactory.cpp
new file mode 100644
index 0000000..9ec0ab7
--- /dev/null
+++ b/drm/1.0/default/DrmFactory.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-impl"
+
+#include "DrmFactory.h"
+#include "DrmPlugin.h"
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+ DrmFactory::DrmFactory() :
+ loader("/vendor/lib/mediadrm", "createDrmFactory") {
+ }
+
+ // Methods from ::android::hardware::drm::V1_0::IDrmFactory follow.
+ Return<bool> DrmFactory::isCryptoSchemeSupported (
+ const hidl_array<uint8_t, 16>& uuid) {
+ for (size_t i = 0; i < loader.factoryCount(); i++) {
+ if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Return<bool> DrmFactory::isContentTypeSupported (
+ const hidl_string& mimeType) {
+ for (size_t i = 0; i < loader.factoryCount(); i++) {
+ if (loader.getFactory(i)->isContentTypeSupported(String8(mimeType.c_str()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Return<void> DrmFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid,
+ const hidl_string& /* appPackageName */, createPlugin_cb _hidl_cb) {
+
+ for (size_t i = 0; i < loader.factoryCount(); i++) {
+ if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) {
+ android::DrmPlugin *legacyPlugin = NULL;
+ status_t status = loader.getFactory(i)->createDrmPlugin(
+ uuid.data(), &legacyPlugin);
+ DrmPlugin *newPlugin = NULL;
+ if (legacyPlugin == NULL) {
+ ALOGE("Drm legacy HAL: failed to create drm plugin");
+ } else {
+ newPlugin = new DrmPlugin(legacyPlugin);
+ }
+ _hidl_cb(toStatus(status), newPlugin);
+ return Void();
+ }
+ }
+ _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, NULL);
+ return Void();
+ }
+
+ IDrmFactory* HIDL_FETCH_IDrmFactory(const char* /* name */) {
+ return new DrmFactory();
+ }
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/DrmFactory.h b/drm/1.0/default/DrmFactory.h
new file mode 100644
index 0000000..a008844
--- /dev/null
+++ b/drm/1.0/default/DrmFactory.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H
+#define ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H
+
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <hidl/Status.h>
+#include <media/drm/DrmAPI.h>
+#include <media/PluginLoader.h>
+#include <media/SharedLibrary.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::drm::V1_0::IDrmFactory;
+using ::android::hardware::drm::V1_0::IDrmPlugin;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct DrmFactory : public IDrmFactory {
+ DrmFactory();
+ virtual ~DrmFactory() {}
+
+ // Methods from ::android::hardware::drm::V1_0::IDrmFactory follow.
+
+ Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
+ override;
+
+ Return<bool> isContentTypeSupported(const hidl_string &mimeType)
+ override;
+
+ Return<void> createPlugin(const hidl_array<uint8_t, 16>& uuid,
+ const hidl_string& appPackageName, createPlugin_cb _hidl_cb) override;
+
+private:
+ android::PluginLoader<android::DrmFactory> loader;
+
+ DrmFactory(const DrmFactory &) = delete;
+ void operator=(const DrmFactory &) = delete;
+};
+
+extern "C" IDrmFactory* HIDL_FETCH_IDrmFactory(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H
diff --git a/drm/1.0/default/DrmPlugin.cpp b/drm/1.0/default/DrmPlugin.cpp
new file mode 100644
index 0000000..6f51e0e
--- /dev/null
+++ b/drm/1.0/default/DrmPlugin.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-impl"
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+#include "DrmPlugin.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+ // Methods from ::android::hardware::drm::V1_0::IDrmPlugin follow.
+
+ Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
+ Vector<uint8_t> legacySessionId;
+ status_t status = mLegacyPlugin->openSession(legacySessionId);
+ _hidl_cb(toStatus(status), toHidlVec(legacySessionId));
+ return Void();
+ }
+
+ Return<Status> DrmPlugin::closeSession(const hidl_vec<uint8_t>& sessionId) {
+ return toStatus(mLegacyPlugin->closeSession(toVector(sessionId)));
+ }
+
+ Return<void> DrmPlugin::getKeyRequest(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData, const hidl_string& mimeType,
+ KeyType keyType, const hidl_vec<KeyValue>& optionalParameters,
+ getKeyRequest_cb _hidl_cb) {
+
+ status_t status = android::OK;
+
+ android::DrmPlugin::KeyType legacyKeyType;
+ switch(keyType) {
+ case KeyType::OFFLINE:
+ legacyKeyType = android::DrmPlugin::kKeyType_Offline;
+ break;
+ case KeyType::STREAMING:
+ legacyKeyType = android::DrmPlugin::kKeyType_Streaming;
+ break;
+ case KeyType::RELEASE:
+ legacyKeyType = android::DrmPlugin::kKeyType_Release;
+ break;
+ default:
+ status = android::BAD_VALUE;
+ break;
+ }
+
+ Vector<uint8_t> legacyRequest;
+ KeyRequestType requestType = KeyRequestType::UNKNOWN;
+ String8 defaultUrl;
+
+ if (status == android::OK) {
+ android::KeyedVector<String8, String8> legacyOptionalParameters;
+ for (size_t i = 0; i < optionalParameters.size(); i++) {
+ legacyOptionalParameters.add(String8(optionalParameters[i].key),
+ String8(optionalParameters[i].value));
+ }
+
+ android::DrmPlugin::KeyRequestType legacyRequestType =
+ android::DrmPlugin::kKeyRequestType_Unknown;
+
+ status_t status = mLegacyPlugin->getKeyRequest(toVector(scope),
+ toVector(initData), String8(mimeType), legacyKeyType,
+ legacyOptionalParameters, legacyRequest, defaultUrl,
+ &legacyRequestType);
+
+ switch(legacyRequestType) {
+ case android::DrmPlugin::kKeyRequestType_Initial:
+ requestType = KeyRequestType::INITIAL;
+ break;
+ case android::DrmPlugin::kKeyRequestType_Renewal:
+ requestType = KeyRequestType::RENEWAL;
+ break;
+ case android::DrmPlugin::kKeyRequestType_Release:
+ requestType = KeyRequestType::RELEASE;
+ break;
+ case android::DrmPlugin::kKeyRequestType_Unknown:
+ status = android::BAD_VALUE;
+ break;
+ }
+ }
+ _hidl_cb(toStatus(status), toHidlVec(legacyRequest), requestType,
+ defaultUrl.string());
+ return Void();
+ }
+
+ Return<void> DrmPlugin::provideKeyResponse(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& response, provideKeyResponse_cb _hidl_cb) {
+
+ Vector<uint8_t> keySetId;
+ status_t status = mLegacyPlugin->provideKeyResponse(toVector(scope),
+ toVector(response), keySetId);
+ _hidl_cb(toStatus(status), toHidlVec(keySetId));
+ return Void();
+ }
+
+ Return<Status> DrmPlugin::removeKeys(const hidl_vec<uint8_t>& sessionId) {
+ return toStatus(mLegacyPlugin->removeKeys(toVector(sessionId)));
+ }
+
+ Return<Status> DrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keySetId) {
+ status_t legacyStatus = mLegacyPlugin->restoreKeys(toVector(sessionId),
+ toVector(keySetId));
+ return toStatus(legacyStatus);
+ }
+
+ Return<void> DrmPlugin::queryKeyStatus(const hidl_vec<uint8_t>& sessionId,
+ queryKeyStatus_cb _hidl_cb) {
+
+ android::KeyedVector<String8, String8> legacyInfoMap;
+ status_t status = mLegacyPlugin->queryKeyStatus(toVector(sessionId),
+ legacyInfoMap);
+
+ Vector<KeyValue> infoMapVec;
+ for (size_t i = 0; i < legacyInfoMap.size(); i++) {
+ KeyValue keyValuePair;
+ keyValuePair.key = String8(legacyInfoMap.keyAt(i));
+ keyValuePair.value = String8(legacyInfoMap.valueAt(i));
+ infoMapVec.push_back(keyValuePair);
+ }
+ _hidl_cb(toStatus(status), toHidlVec(infoMapVec));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::getProvisionRequest(
+ const hidl_string& certificateType,
+ const hidl_string& certificateAuthority,
+ getProvisionRequest_cb _hidl_cb) {
+
+ Vector<uint8_t> legacyRequest;
+ String8 legacyDefaultUrl;
+ status_t status = mLegacyPlugin->getProvisionRequest(
+ String8(certificateType), String8(certificateAuthority),
+ legacyRequest, legacyDefaultUrl);
+
+ _hidl_cb(toStatus(status), toHidlVec(legacyRequest),
+ hidl_string(legacyDefaultUrl));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::provideProvisionResponse(
+ const hidl_vec<uint8_t>& response,
+ provideProvisionResponse_cb _hidl_cb) {
+
+ Vector<uint8_t> certificate;
+ Vector<uint8_t> wrappedKey;
+
+ status_t legacyStatus = mLegacyPlugin->provideProvisionResponse(
+ toVector(response), certificate, wrappedKey);
+
+ _hidl_cb(toStatus(legacyStatus), toHidlVec(certificate),
+ toHidlVec(wrappedKey));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+ List<Vector<uint8_t> > legacySecureStops;
+ status_t status = mLegacyPlugin->getSecureStops(legacySecureStops);
+
+ Vector<SecureStop> secureStopsVec;
+ List<Vector<uint8_t> >::iterator iter = legacySecureStops.begin();
+
+ while (iter != legacySecureStops.end()) {
+ SecureStop secureStop;
+ secureStop.opaqueData = toHidlVec(*iter++);
+ secureStopsVec.push_back(secureStop);
+ }
+
+ _hidl_cb(toStatus(status), toHidlVec(secureStopsVec));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb) {
+
+ Vector<uint8_t> legacySecureStop;
+ status_t status = mLegacyPlugin->getSecureStop(toVector(secureStopId),
+ legacySecureStop);
+
+ SecureStop secureStop;
+ secureStop.opaqueData = toHidlVec(legacySecureStop);
+ _hidl_cb(toStatus(status), secureStop);
+ return Void();
+ }
+
+ Return<Status> DrmPlugin::releaseAllSecureStops() {
+ return toStatus(mLegacyPlugin->releaseAllSecureStops());
+ }
+
+ Return<Status> DrmPlugin::releaseSecureStop(
+ const hidl_vec<uint8_t>& secureStopId) {
+ status_t legacyStatus =
+ mLegacyPlugin->releaseSecureStops(toVector(secureStopId));
+ return toStatus(legacyStatus);
+ }
+
+ Return<void> DrmPlugin::getPropertyString(const hidl_string& propertyName,
+ getPropertyString_cb _hidl_cb) {
+ String8 legacyValue;
+ status_t status = mLegacyPlugin->getPropertyString(
+ String8(propertyName), legacyValue);
+ _hidl_cb(toStatus(status), legacyValue.string());
+ return Void();
+ }
+
+ Return<void> DrmPlugin::getPropertyByteArray(const hidl_string& propertyName,
+ getPropertyByteArray_cb _hidl_cb) {
+ Vector<uint8_t> legacyValue;
+ status_t status = mLegacyPlugin->getPropertyByteArray(
+ String8(propertyName), legacyValue);
+ _hidl_cb(toStatus(status), toHidlVec(legacyValue));
+ return Void();
+ }
+
+ Return<Status> DrmPlugin::setPropertyString(const hidl_string& propertyName,
+ const hidl_string& value) {
+ status_t legacyStatus =
+ mLegacyPlugin->setPropertyString(String8(propertyName),
+ String8(value));
+ return toStatus(legacyStatus);
+ }
+
+ Return<Status> DrmPlugin::setPropertyByteArray(
+ const hidl_string& propertyName, const hidl_vec<uint8_t>& value) {
+ status_t legacyStatus =
+ mLegacyPlugin->setPropertyByteArray(String8(propertyName),
+ toVector(value));
+ return toStatus(legacyStatus);
+ }
+
+ Return<Status> DrmPlugin::setCipherAlgorithm(
+ const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
+ status_t legacyStatus =
+ mLegacyPlugin->setCipherAlgorithm(toVector(sessionId),
+ String8(algorithm));
+ return toStatus(legacyStatus);
+ }
+
+ Return<Status> DrmPlugin::setMacAlgorithm(
+ const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
+ status_t legacyStatus =
+ mLegacyPlugin->setMacAlgorithm(toVector(sessionId),
+ String8(algorithm));
+ return toStatus(legacyStatus);
+ }
+
+ Return<void> DrmPlugin::encrypt(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv, encrypt_cb _hidl_cb) {
+
+ Vector<uint8_t> legacyOutput;
+ status_t status = mLegacyPlugin->encrypt(toVector(sessionId),
+ toVector(keyId), toVector(input), toVector(iv), legacyOutput);
+ _hidl_cb(toStatus(status), toHidlVec(legacyOutput));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::decrypt(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv, decrypt_cb _hidl_cb) {
+
+ Vector<uint8_t> legacyOutput;
+ status_t status = mLegacyPlugin->decrypt(toVector(sessionId),
+ toVector(keyId), toVector(input), toVector(iv), legacyOutput);
+ _hidl_cb(toStatus(status), toHidlVec(legacyOutput));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::sign(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message,
+ sign_cb _hidl_cb) {
+ Vector<uint8_t> legacySignature;
+ status_t status = mLegacyPlugin->sign(toVector(sessionId),
+ toVector(keyId), toVector(message), legacySignature);
+ _hidl_cb(toStatus(status), toHidlVec(legacySignature));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::verify(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& signature, verify_cb _hidl_cb) {
+
+ bool match;
+ status_t status = mLegacyPlugin->verify(toVector(sessionId),
+ toVector(keyId), toVector(message), toVector(signature),
+ match);
+ _hidl_cb(toStatus(status), match);
+ return Void();
+ }
+
+ Return<void> DrmPlugin::signRSA(const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& algorithm, const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& wrappedKey, signRSA_cb _hidl_cb) {
+
+ Vector<uint8_t> legacySignature;
+ status_t status = mLegacyPlugin->signRSA(toVector(sessionId),
+ String8(algorithm), toVector(message), toVector(wrappedKey),
+ legacySignature);
+ _hidl_cb(toStatus(status), toHidlVec(legacySignature));
+ return Void();
+ }
+
+ Return<void> DrmPlugin::setListener(const sp<IDrmPluginListener>& listener) {
+ mListener = listener;
+ mLegacyPlugin->setListener(listener == NULL ? NULL : this);
+ return Void();
+ }
+
+ Return<void> DrmPlugin::sendEvent(EventType eventType,
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
+ mListener->sendEvent(eventType, sessionId, data);
+ return Void();
+ }
+
+ Return<void> DrmPlugin::sendExpirationUpdate(
+ const hidl_vec<uint8_t>& sessionId, int64_t expiryTimeInMS) {
+ mListener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ return Void();
+ }
+
+ Return<void> DrmPlugin::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+ mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ return Void();
+ }
+
+
+ // Methods from android::DrmPluginListener
+
+ void DrmPlugin::sendEvent(android::DrmPlugin::EventType legacyEventType,
+ int /*unused*/, Vector<uint8_t> const *sessionId,
+ Vector<uint8_t> const *data) {
+
+ EventType eventType;
+ bool sendEvent = true;
+ switch(legacyEventType) {
+ case android::DrmPlugin::kDrmPluginEventProvisionRequired:
+ eventType = EventType::PROVISION_REQUIRED;
+ break;
+ case android::DrmPlugin::kDrmPluginEventKeyNeeded:
+ eventType = EventType::KEY_NEEDED;
+ break;
+ case android::DrmPlugin::kDrmPluginEventKeyExpired:
+ eventType = EventType::KEY_EXPIRED;
+ break;
+ case android::DrmPlugin::kDrmPluginEventVendorDefined:
+ eventType = EventType::VENDOR_DEFINED;
+ break;
+ case android::DrmPlugin::kDrmPluginEventSessionReclaimed:
+ eventType = EventType::SESSION_RECLAIMED;
+ break;
+ default:
+ sendEvent = false;
+ break;
+ }
+ if (sendEvent) {
+ Vector<uint8_t> emptyVector;
+ mListener->sendEvent(eventType,
+ toHidlVec(sessionId == NULL ? emptyVector: *sessionId),
+ toHidlVec(data == NULL ? emptyVector: *data));
+ }
+ }
+
+ void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS) {
+ mListener->sendExpirationUpdate(toHidlVec(*sessionId), expiryTimeInMS);
+ }
+
+ void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<android::DrmPlugin::KeyStatus> const *legacyKeyStatusList,
+ bool hasNewUsableKey) {
+
+ Vector<KeyStatus> keyStatusVec;
+ for (size_t i = 0; i < legacyKeyStatusList->size(); i++) {
+ const android::DrmPlugin::KeyStatus &legacyKeyStatus =
+ legacyKeyStatusList->itemAt(i);
+
+ KeyStatus keyStatus;
+
+ switch(legacyKeyStatus.mType) {
+ case android::DrmPlugin::kKeyStatusType_Usable:
+ keyStatus.type = KeyStatusType::USABLE;
+ break;
+ case android::DrmPlugin::kKeyStatusType_Expired:
+ keyStatus.type = KeyStatusType::EXPIRED;
+ break;
+ case android::DrmPlugin::kKeyStatusType_OutputNotAllowed:
+ keyStatus.type = KeyStatusType::OUTPUTNOTALLOWED;
+ break;
+ case android::DrmPlugin::kKeyStatusType_StatusPending:
+ keyStatus.type = KeyStatusType::STATUSPENDING;
+ break;
+ case android::DrmPlugin::kKeyStatusType_InternalError:
+ default:
+ keyStatus.type = KeyStatusType::INTERNALERROR;
+ break;
+ }
+
+ keyStatus.keyId = toHidlVec(legacyKeyStatus.mKeyId);
+ keyStatusVec.push_back(keyStatus);
+ }
+ mListener->sendKeysChange(toHidlVec(*sessionId),
+ toHidlVec(keyStatusVec), hasNewUsableKey);
+ }
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/DrmPlugin.h b/drm/1.0/default/DrmPlugin.h
new file mode 100644
index 0000000..dce6c0c
--- /dev/null
+++ b/drm/1.0/default/DrmPlugin.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H
+#define ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H
+
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPluginListener.h>
+#include <hidl/Status.h>
+#include <media/drm/DrmAPI.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_0::IDrmPlugin;
+using ::android::hardware::drm::V1_0::IDrmPluginListener;
+using ::android::hardware::drm::V1_0::KeyRequestType;
+using ::android::hardware::drm::V1_0::KeyStatus;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct DrmPlugin : public IDrmPlugin, android::DrmPluginListener {
+
+ DrmPlugin(android::DrmPlugin *plugin) : mLegacyPlugin(plugin) {}
+ ~DrmPlugin() {delete mLegacyPlugin;}
+
+ // Methods from ::android::hardware::drm::V1_0::IDrmPlugin follow.
+
+ Return<void> openSession(openSession_cb _hidl_cb) override;
+
+ Return<Status> closeSession(const hidl_vec<uint8_t>& sessionId) override;
+
+ Return<void> getKeyRequest(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData, const hidl_string& mimeType,
+ KeyType keyType, const hidl_vec<KeyValue>& optionalParameters,
+ getKeyRequest_cb _hidl_cb) override;
+
+ Return<void> provideKeyResponse(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& response, provideKeyResponse_cb _hidl_cb)
+ override;
+
+ Return<Status> removeKeys(const hidl_vec<uint8_t>& sessionId) override;
+
+ Return<Status> restoreKeys(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keySetId) override;
+
+ Return<void> queryKeyStatus(const hidl_vec<uint8_t>& sessionId,
+ queryKeyStatus_cb _hidl_cb) override;
+
+ Return<void> getProvisionRequest(const hidl_string& certificateType,
+ const hidl_string& certificateAuthority,
+ getProvisionRequest_cb _hidl_cb) override;
+
+ Return<void> provideProvisionResponse(const hidl_vec<uint8_t>& response,
+ provideProvisionResponse_cb _hidl_cb) override;
+
+ Return<void> getSecureStops(getSecureStops_cb _hidl_cb) override;
+
+ Return<void> getSecureStop(const hidl_vec<uint8_t>& secureStopId,
+ getSecureStop_cb _hidl_cb) override;
+
+ Return<Status> releaseAllSecureStops() override;
+
+ Return<Status> releaseSecureStop(const hidl_vec<uint8_t>& secureStopId)
+ override;
+
+ Return<void> getPropertyString(const hidl_string& propertyName,
+ getPropertyString_cb _hidl_cb) override;
+
+ Return<void> getPropertyByteArray(const hidl_string& propertyName,
+ getPropertyByteArray_cb _hidl_cb) override;
+
+ Return<Status> setPropertyString(const hidl_string& propertyName,
+ const hidl_string& value) override;
+
+ Return<Status> setPropertyByteArray(const hidl_string& propertyName,
+ const hidl_vec<uint8_t>& value) override;
+
+ Return<Status> setCipherAlgorithm(const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& algorithm) override;
+
+ Return<Status> setMacAlgorithm(const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& algorithm) override;
+
+ Return<void> encrypt(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv, encrypt_cb _hidl_cb) override;
+
+ Return<void> decrypt(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& iv, decrypt_cb _hidl_cb) override;
+
+ Return<void> sign(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message,
+ sign_cb _hidl_cb) override;
+
+ Return<void> verify(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& signature, verify_cb _hidl_cb) override;
+
+ Return<void> signRSA(const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& algorithm, const hidl_vec<uint8_t>& message,
+ const hidl_vec<uint8_t>& wrappedkey, signRSA_cb _hidl_cb) override;
+
+ Return<void> setListener(const sp<IDrmPluginListener>& listener) override;
+
+ Return<void> sendEvent(EventType eventType,
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data)
+ override;
+
+ Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) override;
+
+ Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey)
+ override;
+
+ // Methods from android::DrmPluginListener follow
+
+ virtual void sendEvent(android::DrmPlugin::EventType eventType, int extra,
+ Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data);
+
+ virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS);
+
+ virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<android::DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey);
+
+private:
+ android::DrmPlugin *mLegacyPlugin;
+ sp<IDrmPluginListener> mListener;
+
+ DrmPlugin() = delete;
+ DrmPlugin(const DrmPlugin &) = delete;
+ void operator=(const DrmPlugin &) = delete;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H
diff --git a/drm/1.0/default/TypeConvert.cpp b/drm/1.0/default/TypeConvert.cpp
new file mode 100644
index 0000000..3a262c3
--- /dev/null
+++ b/drm/1.0/default/TypeConvert.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-impl"
+
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+ Status status;
+ switch(legacyStatus) {
+ case android::OK:
+ status = Status::OK;
+ break;
+ case android::ERROR_DRM_NO_LICENSE:
+ status = Status::ERROR_DRM_NO_LICENSE;
+ break;
+ case android::ERROR_DRM_LICENSE_EXPIRED:
+ status = Status::ERROR_DRM_LICENSE_EXPIRED;
+ break;
+ case android::ERROR_DRM_SESSION_NOT_OPENED:
+ status = Status::ERROR_DRM_SESSION_NOT_OPENED;
+ break;
+ case android::ERROR_DRM_CANNOT_HANDLE:
+ status = Status::ERROR_DRM_CANNOT_HANDLE;
+ break;
+ case android::ERROR_DRM_TAMPER_DETECTED:
+ status = Status::ERROR_DRM_INVALID_STATE;
+ break;
+ case android::BAD_VALUE:
+ status = Status::BAD_VALUE;
+ break;
+ case android::ERROR_DRM_NOT_PROVISIONED:
+ status = Status::ERROR_DRM_NOT_PROVISIONED;
+ break;
+ case android::ERROR_DRM_RESOURCE_BUSY:
+ status = Status::ERROR_DRM_RESOURCE_BUSY;
+ break;
+ case android::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ status = Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+ break;
+ case android::ERROR_DRM_DEVICE_REVOKED:
+ status = Status::ERROR_DRM_DEVICE_REVOKED;
+ break;
+ case android::ERROR_DRM_DECRYPT:
+ status = Status::ERROR_DRM_DECRYPT;
+ break;
+ default:
+ ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN",
+ legacyStatus);
+ status = Status::ERROR_DRM_UNKNOWN;
+ break;
+ }
+ return status;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.0/default/TypeConvert.h b/drm/1.0/default/TypeConvert.h
new file mode 100644
index 0000000..107fda5
--- /dev/null
+++ b/drm/1.0/default/TypeConvert.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
+#define ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
+
+#include <android/hardware/drm/1.0/types.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+template<typename T> const hidl_vec<T> toHidlVec(const Vector<T> &Vector) {
+ hidl_vec<T> vec;
+ vec.setToExternal(const_cast<T *>(Vector.array()), Vector.size());
+ return vec;
+}
+
+template<typename T> hidl_vec<T> toHidlVec(Vector<T> &Vector) {
+ hidl_vec<T> vec;
+ vec.setToExternal(Vector.editArray(), Vector.size());
+ return vec;
+}
+
+template<typename T> const Vector<T> toVector(const hidl_vec<T> &vec) {
+ Vector<T> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<T> *>(&vector);
+}
+
+template<typename T> Vector<T> toVector(hidl_vec<T> &vec) {
+ Vector<T> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return vector;
+}
+
+template<typename T, size_t SIZE> const Vector<T> toVector(
+ const hidl_array<T, SIZE> &array) {
+ Vector<T> vector;
+ vector.appendArray(array.data(), array.size());
+ return vector;
+}
+
+template<typename T, size_t SIZE> Vector<T> toVector(
+ hidl_array<T, SIZE> &array) {
+ Vector<T> vector;
+ vector.appendArray(array.data(), array.size());
+ return vector;
+}
+
+Status toStatus(status_t legacyStatus);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
diff --git a/drm/1.0/default/android.hardware.drm@1.0-service.rc b/drm/1.0/default/android.hardware.drm@1.0-service.rc
new file mode 100644
index 0000000..e7beca3
--- /dev/null
+++ b/drm/1.0/default/android.hardware.drm@1.0-service.rc
@@ -0,0 +1,6 @@
+service drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/1.0/default/service.cpp b/drm/1.0/default/service.cpp
new file mode 100644
index 0000000..a112aaf
--- /dev/null
+++ b/drm/1.0/default/service.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 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.
+ */
+#define LOG_TAG "android.hardware.drm@1.0-service"
+
+#include <1.0/default/CryptoFactory.h>
+#include <1.0/default/DrmFactory.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+
+using android::hardware::drm::V1_0::ICryptoFactory;
+using android::hardware::drm::V1_0::IDrmFactory;
+
+int main() {
+ ALOGD("android.hardware.drm@1.0-service starting...");
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+ android::status_t status =
+ registerPassthroughServiceImplementation<IDrmFactory>("drm");
+ LOG_ALWAYS_FATAL_IF(
+ status != android::OK,
+ "Error while registering drm service: %d", status);
+ status = registerPassthroughServiceImplementation<ICryptoFactory>("crypto");
+ LOG_ALWAYS_FATAL_IF(
+ status != android::OK,
+ "Error while registering crypto service: %d", status);
+ joinRpcThreadpool();
+}
diff --git a/drm/1.0/types.hal b/drm/1.0/types.hal
new file mode 100644
index 0000000..cea5b16
--- /dev/null
+++ b/drm/1.0/types.hal
@@ -0,0 +1,348 @@
+/**
+ * Copyright (C) 2016 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.drm@1.0;
+
+enum Status : uint32_t {
+ /**
+ * The DRM plugin must return OK when an operation completes without any
+ * errors.
+ */
+ OK,
+
+ /**
+ * The DRM plugin must return ERROR_DRM_NO_LICENSE, when decryption is
+ * attempted and no license keys have been provided.
+ */
+ ERROR_DRM_NO_LICENSE,
+
+ /**
+ * ERROR_DRM_LICENSE_EXPIRED must be returned when an attempt is made
+ * to use a license and the keys in that license have expired.
+ */
+ ERROR_DRM_LICENSE_EXPIRED,
+
+ /**
+ * The DRM plugin must return ERROR_DRM_SESSION_NOT_OPENED when an
+ * attempt is made to use a session that has not been opened.
+ */
+ ERROR_DRM_SESSION_NOT_OPENED,
+
+ /**
+ * The DRM plugin must return ERROR_DRM_CANNOT_HANDLE when an unsupported
+ * data format or operation is attempted.
+ */
+ ERROR_DRM_CANNOT_HANDLE,
+
+ /**
+ * ERROR_DRM_INVALID_STATE must be returned when the device is in a state
+ * where it is not able to perform decryption.
+ */
+ ERROR_DRM_INVALID_STATE,
+
+ /**
+ * The DRM plugin must return BAD_VALUE whenever an illegal parameter is
+ * passed to one of the interface functions.
+ */
+ BAD_VALUE,
+
+ /**
+ * The DRM plugin must return ERROR_DRM_NOT_PROVISIONED from getKeyRequest,
+ * openSession or provideKeyResponse when the device has not yet been
+ * provisioned.
+ */
+ ERROR_DRM_NOT_PROVISIONED,
+
+ /**
+ * ERROR_DRM_RESOURCE_BUSY must be returned when resources, such as drm
+ * sessions or secure buffers are not available to perform a requested
+ * operation because they are already in use.
+ */
+ ERROR_DRM_RESOURCE_BUSY,
+
+ /**
+ * The DRM Plugin must return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION
+ * when the output protection level enabled on the device is not
+ * sufficient to meet the requirements in the license policy. HDCP is an
+ * example of a form of output protection.
+ */
+ ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION,
+
+ /**
+ * The DRM Plugin must return ERROR_DRM_DEVICE_REVOKED from
+ * provideProvisionResponse and provideKeyResponse if the response indicates
+ * that the device has been revoked. Device revocation means that the device
+ * is no longer permitted to play content.
+ */
+ ERROR_DRM_DEVICE_REVOKED,
+
+ /**
+ * The DRM Plugin must return ERROR_DRM_DECRYPT if the CryptoPlugin
+ * decrypt operation fails.
+ */
+ ERROR_DRM_DECRYPT,
+
+ /**
+ * ERROR_DRM_UNKNOWN must be returned when a fatal failure occurs and no
+ * other defined error is appropriate.
+ */
+ ERROR_DRM_UNKNOWN,
+};
+
+
+/**
+ * EventType enumerates the events that can be delivered by sendEvent
+ */
+enum EventType : uint32_t {
+ /**
+ * This event type indicates that the app needs to request a certificate
+ * from the provisioning server. The request message data is obtained using
+ * getProvisionRequest().
+ */
+ PROVISION_REQUIRED,
+
+ /**
+ * This event type indicates that the app needs to request keys from a
+ * license server. The request message data is obtained using getKeyRequest.
+ */
+ KEY_NEEDED,
+
+ /**
+ * This event type indicates that the licensed usage duration for keys in a
+ * session has expired. The keys are no longer valid.
+ */
+ KEY_EXPIRED,
+
+ /**
+ * This event may indicate some specific vendor-defined condition, see your
+ * DRM provider documentation for details.
+ */
+ VENDOR_DEFINED,
+
+ /**
+ * This event indicates that a session opened by the app has been reclaimed
+ * by the resource manager.
+ */
+ SESSION_RECLAIMED,
+};
+
+enum KeyType : uint32_t {
+ /**
+ * Drm keys can be for offline content or for online streaming.
+ * Offline keys are persisted on the device and may be used when the device
+ * is disconnected from the network.
+ */
+ OFFLINE,
+
+ /**
+ * Keys for streaming are not persisted and require the device to be
+ * connected to the network for periodic renewal.
+ */
+ STREAMING,
+
+ /**
+ * The Release type is used to request that offline keys be no longer
+ * restricted to offline use.
+ */
+ RELEASE,
+};
+
+/**
+ * Enumerate KeyRequestTypes to allow an app to determine the type of a key
+ * request returned from getKeyRequest.
+ */
+enum KeyRequestType : uint32_t {
+ /**
+ * Key request type is for an initial license request
+ */
+ INITIAL,
+
+ /**
+ * Key request type is for license renewal. Renewal requests are used
+ * to extend the validity period for streaming keys.
+ */
+ RENEWAL,
+
+ /**
+ * Key request type is a release. A key release causes offline keys
+ * to become available for streaming.
+ */
+ RELEASE,
+
+ /**
+ * Key request type is unknown due to some error condition.
+ */
+ UNKNOWN,
+};
+
+/**
+ * Enumerate KeyStatusTypes which indicate the state of a key
+ */
+enum KeyStatusType : uint32_t {
+ /**
+ * The key is currently usable to decrypt media data.
+ */
+ USABLE,
+
+ /**
+ * The key is no longer usable to decrypt media data because its expiration
+ * time has passed.
+ */
+ EXPIRED,
+
+ /**
+ * The key is not currently usable to decrypt media data because its output
+ * requirements cannot currently be met.
+ */
+ OUTPUTNOTALLOWED,
+
+ /**
+ * The status of the key is not yet known and is being determined.
+ */
+ STATUSPENDING,
+
+ /**
+ * The key is not currently usable to decrypt media data because of an
+ * internal error in processing unrelated to input parameters.
+ */
+ INTERNALERROR,
+};
+
+typedef vec<uint8_t> SessionId;
+
+/**
+ * Used by sendKeysChange to report the usability status of each key to the
+ * app.
+ */
+struct KeyStatus
+{
+ vec<uint8_t> keyId;
+ KeyStatusType type;
+};
+
+/**
+ * Simulates a KeyedVector<String8, String8>
+ */
+struct KeyValue {
+ string key;
+ string value;
+};
+
+typedef vec<KeyValue> KeyedVector;
+
+/**
+ * Encapsulates a secure stop opaque object
+ */
+struct SecureStop {
+ vec<uint8_t> opaqueData;
+};
+
+typedef vec<uint8_t> SecureStopId;
+
+
+/**
+ * Enumerate the supported crypto modes
+ */
+enum Mode : uint32_t {
+ UNENCRYPTED = 0, // Samples are unencrypted
+ AES_CTR = 1, // Samples are encrypted with AES CTR mode
+ AES_CBC_CTS = 2, // Samples are encrypted with AES CBC CTS mode
+ AES_CBC = 3, // Samples are encrypted with AES CBC mode
+};
+
+/**
+ * A subsample consists of some number of bytes of clear (unencrypted)
+ * data followed by a number of bytes of encrypted data.
+ */
+struct SubSample {
+ uint32_t numBytesOfClearData;
+ uint32_t numBytesOfEncryptedData;
+};
+
+/**
+ * A crypto Pattern is a repeating sequence of encrypted and clear blocks
+ * occuring within the bytes indicated by mNumBytesOfEncryptedDatad bytes
+ * of a subsample. Patterns are used to reduce the CPU overhead of
+ * decrypting samples. As an example, HLS uses 1:9 patterns where every
+ * 10th block is encrypted.
+ */
+struct Pattern {
+ /**
+ * The number of blocks to be encrypted in the pattern. If zero,
+ * pattern encryption is inoperative.
+ */
+ uint32_t encryptBlocks;
+
+ /**
+ * The number of blocks to be skipped (left clear) in the pattern. If
+ * zero, pattern encryption is inoperative.
+ */
+ uint32_t skipBlocks;
+};
+
+enum BufferType : uint32_t {
+ SHARED_MEMORY = 0,
+ NATIVE_HANDLE = 1,
+};
+
+/**
+ * SharedBuffer describes a decrypt buffer which is defined by a bufferId, an
+ * offset and a size. The offset is relative to the shared memory base for the
+ * memory region identified by bufferId, which is established by
+ * setSharedMemoryBase().
+ */
+struct SharedBuffer {
+ /**
+ * The unique buffer identifier
+ */
+ uint32_t bufferId;
+
+ /**
+ * The offset from the shared memory base
+ */
+ uint64_t offset;
+
+ /**
+ * The size of the shared buffer in bytes
+ */
+ uint64_t size;
+};
+
+
+/**
+ * A decrypt destination buffer can be either normal user-space shared
+ * memory for the non-secure decrypt case, or it can be a secure buffer
+ * which is referenced by a native-handle. The native handle is allocated
+ * by the vendor's buffer allocator.
+ */
+struct DestinationBuffer {
+ /**
+ * The type of the buffer
+ */
+ BufferType type;
+
+ /**
+ * If type == SHARED_MEMORY, the decrypted data must be written
+ * to user-space non-secure shared memory.
+ */
+ SharedBuffer nonsecureMemory;
+
+ /**
+ * If type == NATIVE_HANDLE, the decrypted data must be written
+ * to secure memory referenced by the vendor's buffer allocator.
+ */
+ handle secureMemory;
+};
diff --git a/drm/Android.bp b/drm/Android.bp
new file mode 100644
index 0000000..bbb3e4b
--- /dev/null
+++ b/drm/Android.bp
@@ -0,0 +1,4 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+]
diff --git a/dumpstate/1.0/Android.bp b/dumpstate/1.0/Android.bp
new file mode 100644
index 0000000..1b473bc
--- /dev/null
+++ b/dumpstate/1.0/Android.bp
@@ -0,0 +1,59 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.dumpstate@1.0_hal",
+ srcs: [
+ "IDumpstateDevice.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.dumpstate@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.dumpstate@1.0",
+ srcs: [
+ ":android.hardware.dumpstate@1.0_hal",
+ ],
+ out: [
+ "android/hardware/dumpstate/1.0/DumpstateDeviceAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.dumpstate@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.dumpstate@1.0",
+ srcs: [
+ ":android.hardware.dumpstate@1.0_hal",
+ ],
+ out: [
+ "android/hardware/dumpstate/1.0/IDumpstateDevice.h",
+ "android/hardware/dumpstate/1.0/IHwDumpstateDevice.h",
+ "android/hardware/dumpstate/1.0/BnHwDumpstateDevice.h",
+ "android/hardware/dumpstate/1.0/BpHwDumpstateDevice.h",
+ "android/hardware/dumpstate/1.0/BsDumpstateDevice.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.dumpstate@1.0",
+ generated_sources: ["android.hardware.dumpstate@1.0_genc++"],
+ generated_headers: ["android.hardware.dumpstate@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.dumpstate@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/dumpstate/1.0/IDumpstateDevice.hal b/dumpstate/1.0/IDumpstateDevice.hal
new file mode 100644
index 0000000..fec3eb4
--- /dev/null
+++ b/dumpstate/1.0/IDumpstateDevice.hal
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.dumpstate@1.0;
+
+interface IDumpstateDevice {
+ /*
+ * Dumps device-specific state into the given file descriptor.
+ */
+ dumpstateBoard(handle h);
+};
diff --git a/dumpstate/1.0/default/Android.mk b/dumpstate/1.0/default/Android.mk
new file mode 100644
index 0000000..0b07f49
--- /dev/null
+++ b/dumpstate/1.0/default/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.dumpstate@1.0-service
+LOCAL_INIT_RC := android.hardware.dumpstate@1.0-service.rc
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SRC_FILES := \
+ DumpstateDevice.cpp \
+ service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.dumpstate@1.0 \
+ libbase \
+ libcutils \
+ libdumpstateutil \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils
+
+include $(BUILD_EXECUTABLE)
diff --git a/dumpstate/1.0/default/DumpstateDevice.cpp b/dumpstate/1.0/default/DumpstateDevice.cpp
new file mode 100644
index 0000000..8000d85
--- /dev/null
+++ b/dumpstate/1.0/default/DumpstateDevice.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateDevice.h"
+
+#include <log/log.h>
+
+#include "DumpstateUtil.h"
+
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::RunCommandToFd;
+
+namespace android {
+namespace hardware {
+namespace dumpstate {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow.
+Return<void> DumpstateDevice::dumpstateBoard(const hidl_handle& handle) {
+ // NOTE: this is just an example on how to use the DumpstateUtil.h functions to implement
+ // this interface - since HIDL_FETCH_IDumpstateDevice() is not defined, this function will never
+ // be called by dumpstate.
+
+ if (handle->numFds < 1) {
+ ALOGE("no FDs\n");
+ return Void();
+ }
+
+ int fd = handle->data[0];
+ if (fd < 0) {
+ ALOGE("invalid FD: %d\n", handle->data[0]);
+ return Void();
+ }
+ ALOGD("DumpstateDevice::dumpstateBoard() FD: %d\n", fd);
+ ALOGI("Dumpstate HIDL not provided by device\n");
+ dprintf(fd, "Dumpstate HIDL not provided by device; providing bogus data.\n");
+
+ // Shows some examples on how to use the libdumpstateutil API.
+ RunCommandToFd(fd, "DATE", {"/system/bin/date"});
+ DumpFileToFd(fd, "HOSTS", "/system/etc/hosts");
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace dumpstate
+} // namespace hardware
+} // namespace android
diff --git a/dumpstate/1.0/default/DumpstateDevice.h b/dumpstate/1.0/default/DumpstateDevice.h
new file mode 100644
index 0000000..f8585f5
--- /dev/null
+++ b/dumpstate/1.0/default/DumpstateDevice.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
+#define ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
+
+#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace dumpstate {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct DumpstateDevice : public IDumpstateDevice {
+ // Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow.
+ Return<void> dumpstateBoard(const hidl_handle& h) override;
+
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace dumpstate
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
diff --git a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
new file mode 100644
index 0000000..0f27248
--- /dev/null
+++ b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
@@ -0,0 +1,4 @@
+service dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service
+ class hal
+ user system
+ group system
diff --git a/dumpstate/1.0/default/service.cpp b/dumpstate/1.0/default/service.cpp
new file mode 100644
index 0000000..85bea12
--- /dev/null
+++ b/dumpstate/1.0/default/service.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.dumpstate@1.0-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "DumpstateDevice.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_0::implementation::DumpstateDevice;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+int main (int /* argc */, char * /* argv */ []) {
+ sp<IDumpstateDevice> dumpstate = new DumpstateDevice;
+ configureRpcThreadpool(1, true);
+ dumpstate->registerAsService();
+ joinRpcThreadpool();
+}
diff --git a/dumpstate/Android.bp b/dumpstate/Android.bp
new file mode 100644
index 0000000..bbb3e4b
--- /dev/null
+++ b/dumpstate/Android.bp
@@ -0,0 +1,4 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+]
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
new file mode 100644
index 0000000..2697e4c
--- /dev/null
+++ b/gatekeeper/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.gatekeeper@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IGatekeeper.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.gatekeeper@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gatekeeper@1.0",
+ srcs: [
+ ":android.hardware.gatekeeper@1.0_hal",
+ ],
+ out: [
+ "android/hardware/gatekeeper/1.0/types.cpp",
+ "android/hardware/gatekeeper/1.0/GatekeeperAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.gatekeeper@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gatekeeper@1.0",
+ srcs: [
+ ":android.hardware.gatekeeper@1.0_hal",
+ ],
+ out: [
+ "android/hardware/gatekeeper/1.0/types.h",
+ "android/hardware/gatekeeper/1.0/IGatekeeper.h",
+ "android/hardware/gatekeeper/1.0/IHwGatekeeper.h",
+ "android/hardware/gatekeeper/1.0/BnHwGatekeeper.h",
+ "android/hardware/gatekeeper/1.0/BpHwGatekeeper.h",
+ "android/hardware/gatekeeper/1.0/BsGatekeeper.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.gatekeeper@1.0",
+ generated_sources: ["android.hardware.gatekeeper@1.0_genc++"],
+ generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/gatekeeper/1.0/Android.mk b/gatekeeper/1.0/Android.mk
new file mode 100644
index 0000000..70206ff
--- /dev/null
+++ b/gatekeeper/1.0/Android.mk
@@ -0,0 +1,156 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (GatekeeperResponse)
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperResponse.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::types.GatekeeperResponse
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GatekeeperStatusCode)
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperStatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::types.GatekeeperStatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGatekeeper.hal
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/IGatekeeper.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGatekeeper.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::IGatekeeper
+
+$(GEN): $(LOCAL_PATH)/IGatekeeper.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (GatekeeperResponse)
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperResponse.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::types.GatekeeperResponse
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GatekeeperStatusCode)
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperStatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::types.GatekeeperStatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGatekeeper.hal
+#
+GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/IGatekeeper.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGatekeeper.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gatekeeper@1.0::IGatekeeper
+
+$(GEN): $(LOCAL_PATH)/IGatekeeper.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal
new file mode 100644
index 0000000..c193477
--- /dev/null
+++ b/gatekeeper/1.0/IGatekeeper.hal
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 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.gatekeeper@1.0;
+
+interface IGatekeeper {
+
+/**
+ * Enrolls desiredPassword, which may be derived from a user selected pin
+ * or password, with the private key used only for enrolling authentication
+ * factor data.
+ *
+ * If there was already a password enrolled, current password handle must be
+ * passed in currentPasswordHandle, and current password must be passed in
+ * currentPassword. Valid currentPassword must verify() against
+ * currentPasswordHandle.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param currentPasswordHandle The currently enrolled password handle the user
+ * wants to replace. May be empty only if there's no currently enrolled
+ * password. Otherwise must be non-empty.
+ *
+ * @param currentPassword The user's current password in plain text.
+ * it MUST verify against current_password_handle if the latter is not-empty
+ *
+ * @param desiredPassword The new password the user wishes to enroll in
+ * plaintext.
+ *
+ * @return response
+ * On success, data buffer must contain the new password handle referencing
+ * the password provided in desiredPassword.
+ * This buffer can be used on subsequent calls to enroll or
+ * verify. On error, this buffer must be empty.
+ * response.code must always contain operation completion status.
+ * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ * failure. It must return STATUS_OK on success.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+enroll(uint32_t uid,
+ vec<uint8_t> currentPasswordHandle,
+ vec<uint8_t> currentPassword,
+ vec<uint8_t> desiredPassword)
+ generates (GatekeeperResponse response);
+
+/**
+ * Verifies that providedPassword matches enrolledPasswordHandle.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, returns verification token in response.data, which shall be
+ * usable to attest password verification to other trusted services.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param challenge An optional challenge to authenticate against, or 0.
+ * Used when a separate authenticator requests password verification,
+ * or for transactional password authentication.
+ *
+ * @param enrolledPasswordHandle The currently enrolled password handle that
+ * user wishes to verify against. Must be non-empty.
+ *
+ * @param providedPassword The plaintext password to be verified against the
+ * enrolledPasswordHandle
+ *
+ * @return response
+ * On success, a non-empty data buffer containing the
+ * authentication token resulting from this verification is returned.
+ * On error, data buffer must be empty.
+ * response.code must always contain operation completion status.
+ * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ * failure. It must return STATUS_OK on success.
+ * If password re-enrollment is necessary, it must return STATUS_REENROLL.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+verify(uint32_t uid, uint64_t challenge,
+ vec<uint8_t> enrolledPasswordHandle,
+ vec<uint8_t> providedPassword)
+ generates (GatekeeperResponse response);
+
+/*
+ * Deletes the enrolledPasswordHandle associated with the uid. Once deleted
+ * the user cannot be verified anymore.
+ * This is an optional method.
+ *
+ * @param uid The Android user identifier
+ *
+ * @return response
+ * response.code must always contain operation completion status.
+ * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ * failure. It must return STATUS_OK on success.
+ * If not implemented, it must return ERROR_NOT_IMPLEMENTED.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+deleteUser(uint32_t uid) generates (GatekeeperResponse response);
+
+/*
+ * Deletes all the enrolled_password_handles for all uid's. Once called,
+ * no users must be enrolled on the device.
+ * This is an optional method.
+ *
+ * @return response
+ * response.code must always contain operation completion status.
+ * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ * failure. It must return STATUS_OK on success.
+ * If not implemented, it must return ERROR_NOT_IMPLEMENTED.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+deleteAllUsers() generates (GatekeeperResponse response);
+};
diff --git a/gatekeeper/1.0/default/Android.mk b/gatekeeper/1.0/default/Android.mk
new file mode 100644
index 0000000..d084535
--- /dev/null
+++ b/gatekeeper/1.0/default/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-impl
+
+LOCAL_SRC_FILES := \
+ Gatekeeper.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.gatekeeper@1.0 \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-service
+LOCAL_INIT_RC := android.hardware.gatekeeper@1.0-service.rc
+
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.gatekeeper@1.0 \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ liblog \
+
+include $(BUILD_EXECUTABLE)
diff --git a/gatekeeper/1.0/default/Gatekeeper.cpp b/gatekeeper/1.0/default/Gatekeeper.cpp
new file mode 100644
index 0000000..dce06e6
--- /dev/null
+++ b/gatekeeper/1.0/default/Gatekeeper.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.gatekeeper@1.0-service"
+
+#include <dlfcn.h>
+
+#include <log/log.h>
+
+#include "Gatekeeper.h"
+
+namespace android {
+namespace hardware {
+namespace gatekeeper {
+namespace V1_0 {
+namespace implementation {
+
+Gatekeeper::Gatekeeper()
+{
+ int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
+ device = NULL;
+
+ if (!ret) {
+ ret = gatekeeper_open(module, &device);
+ }
+ if (ret < 0) {
+ LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
+ }
+}
+
+Gatekeeper::~Gatekeeper()
+{
+ if (device != nullptr) {
+ int ret = gatekeeper_close(device);
+ if (ret < 0) {
+ ALOGE("Unable to close GateKeeper HAL");
+ }
+ }
+ dlclose(module->dso);
+}
+
+// Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow.
+Return<void> Gatekeeper::enroll(uint32_t uid,
+ const hidl_vec<uint8_t>& currentPasswordHandle,
+ const hidl_vec<uint8_t>& currentPassword,
+ const hidl_vec<uint8_t>& desiredPassword,
+ enroll_cb cb)
+{
+ GatekeeperResponse rsp;
+ uint8_t *enrolled_password_handle = nullptr;
+ uint32_t enrolled_password_handle_length = 0;
+
+ int ret = device->enroll(device, uid,
+ currentPasswordHandle.data(), currentPasswordHandle.size(),
+ currentPassword.data(), currentPassword.size(),
+ desiredPassword.data(), desiredPassword.size(),
+ &enrolled_password_handle, &enrolled_password_handle_length);
+ if (!ret) {
+ rsp.data.setToExternal(enrolled_password_handle,
+ enrolled_password_handle_length,
+ true);
+ rsp.code = GatekeeperStatusCode::STATUS_OK;
+ } else if (ret > 0) {
+ rsp.timeout = ret;
+ rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+ }
+ cb(rsp);
+ return Void();
+}
+
+Return<void> Gatekeeper::verify(uint32_t uid,
+ uint64_t challenge,
+ const hidl_vec<uint8_t>& enrolledPasswordHandle,
+ const hidl_vec<uint8_t>& providedPassword,
+ verify_cb cb)
+{
+ GatekeeperResponse rsp;
+ uint8_t *auth_token = nullptr;
+ uint32_t auth_token_length = 0;
+ bool request_reenroll = false;
+
+ int ret = device->verify(device, uid, challenge,
+ enrolledPasswordHandle.data(), enrolledPasswordHandle.size(),
+ providedPassword.data(), providedPassword.size(),
+ &auth_token, &auth_token_length,
+ &request_reenroll);
+ if (!ret) {
+ rsp.data.setToExternal(auth_token, auth_token_length, true);
+ if (request_reenroll) {
+ rsp.code = GatekeeperStatusCode::STATUS_REENROLL;
+ } else {
+ rsp.code = GatekeeperStatusCode::STATUS_OK;
+ }
+ } else if (ret > 0) {
+ rsp.timeout = ret;
+ rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+ }
+ cb(rsp);
+ return Void();
+}
+
+Return<void> Gatekeeper::deleteUser(uint32_t uid, deleteUser_cb cb) {
+ GatekeeperResponse rsp;
+
+ if (device->delete_user != nullptr) {
+ int ret = device->delete_user(device, uid);
+ if (!ret) {
+ rsp.code = GatekeeperStatusCode::STATUS_OK;
+ } else if (ret > 0) {
+ rsp.timeout = ret;
+ rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+ }
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED;
+ }
+ cb(rsp);
+ return Void();
+}
+
+Return<void> Gatekeeper::deleteAllUsers(deleteAllUsers_cb cb) {
+ GatekeeperResponse rsp;
+ if (device->delete_all_users != nullptr) {
+ int ret = device->delete_all_users(device);
+ if (!ret) {
+ rsp.code = GatekeeperStatusCode::STATUS_OK;
+ } else if (ret > 0) {
+ rsp.timeout = ret;
+ rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+ }
+ } else {
+ rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED;
+ }
+ cb(rsp);
+ return Void();
+}
+
+IGatekeeper* HIDL_FETCH_IGatekeeper(const char* /* name */) {
+ return new Gatekeeper();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gatekeeper
+} // namespace hardware
+} // namespace android
diff --git a/gatekeeper/1.0/default/Gatekeeper.h b/gatekeeper/1.0/default/Gatekeeper.h
new file mode 100644
index 0000000..4cc01f6
--- /dev/null
+++ b/gatekeeper/1.0/default/Gatekeeper.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H
+#define ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gatekeeper.h>
+
+namespace android {
+namespace hardware {
+namespace gatekeeper {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class Gatekeeper : public IGatekeeper {
+public:
+ Gatekeeper();
+ ~Gatekeeper();
+
+ // Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow.
+ Return<void> enroll(uint32_t uid,
+ const hidl_vec<uint8_t>& currentPasswordHandle,
+ const hidl_vec<uint8_t>& currentPassword,
+ const hidl_vec<uint8_t>& desiredPassword,
+ enroll_cb _hidl_cb) override;
+ Return<void> verify(uint32_t uid,
+ uint64_t challenge,
+ const hidl_vec<uint8_t>& enrolledPasswordHandle,
+ const hidl_vec<uint8_t>& providedPassword,
+ verify_cb _hidl_cb) override;
+ Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override;
+ Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb) override;
+private:
+ gatekeeper_device_t *device;
+ const hw_module_t *module;
+};
+
+extern "C" IGatekeeper* HIDL_FETCH_IGatekeeper(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gatekeeper
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
new file mode 100644
index 0000000..d3f5e9d
--- /dev/null
+++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -0,0 +1,4 @@
+service gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service
+ class hal
+ user system
+ group system
diff --git a/gatekeeper/1.0/default/service.cpp b/gatekeeper/1.0/default/service.cpp
new file mode 100644
index 0000000..5cbdafb
--- /dev/null
+++ b/gatekeeper/1.0/default/service.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.gatekeeper@1.0-service"
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+#include <hidl/LegacySupport.h>
+
+// Generated HIDL files
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IGatekeeper>();
+}
diff --git a/gatekeeper/1.0/types.hal b/gatekeeper/1.0/types.hal
new file mode 100644
index 0000000..8c184ee
--- /dev/null
+++ b/gatekeeper/1.0/types.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 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.gatekeeper@1.0;
+
+/**
+ * Gatekeeper response codes; success >= 0; error < 0
+ */
+enum GatekeeperStatusCode : int32_t {
+ STATUS_REENROLL = 1, // success, but upper layers should re-enroll
+ // the verified password due to a version change
+ STATUS_OK = 0, // operation is successful
+ ERROR_GENERAL_FAILURE = -1, // operation failed
+ ERROR_RETRY_TIMEOUT = -2, // operation should be retried after timeout
+ ERROR_NOT_IMPLEMENTED = -3, // operation is not implemented
+};
+
+/**
+ * Gatekeeper response to any/all requests has this structure as mandatory part
+ */
+struct GatekeeperResponse {
+ /* request completion status */
+ GatekeeperStatusCode code;
+ /* retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+ * otherwise unused (0)
+ */
+ uint32_t timeout;
+ /* optional crypto blob */
+ vec<uint8_t> data;
+};
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..70cb615
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalGatekeeperV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.gatekeeper@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
new file mode 100644
index 0000000..391dea0
--- /dev/null
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "gatekeeper_hidl_hal_test"
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include <android/log.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <android/hardware/gatekeeper/1.0/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct GatekeeperRequest {
+ uint32_t uid;
+ uint64_t challenge;
+ hidl_vec<uint8_t> curPwdHandle;
+ hidl_vec<uint8_t> curPwd;
+ hidl_vec<uint8_t> newPwd;
+ GatekeeperRequest() : uid(0), challenge(0) {}
+};
+
+// ASSERT_* macros generate return "void" internally
+// we have to use EXPECT_* if we return anything but "void"
+static const hw_auth_token_t *toAuthToken(GatekeeperResponse &rsp) {
+ const hw_auth_token_t *auth_token =
+ reinterpret_cast<hw_auth_token_t *>(rsp.data.data());
+ const size_t auth_token_size = rsp.data.size();
+
+ EXPECT_NE(nullptr, auth_token);
+ EXPECT_EQ(sizeof(hw_auth_token_t), auth_token_size);
+
+ if (auth_token != nullptr && auth_token_size >= sizeof(*auth_token)) {
+ // these are in network order: translate to host
+ uint32_t auth_type = ntohl(auth_token->authenticator_type);
+ uint64_t auth_tstamp = ntohq(auth_token->timestamp);
+
+ EXPECT_EQ(HW_AUTH_PASSWORD, auth_type);
+ EXPECT_NE(UINT64_C(~0), auth_tstamp);
+ EXPECT_EQ(HW_AUTH_TOKEN_VERSION, auth_token->version);
+ // EXPECT_NE(UINT64_C(0), auth_token->authenticator_id);
+ ALOGI("Authenticator ID: %016" PRIX64, auth_token->authenticator_id);
+ EXPECT_NE(UINT32_C(0), auth_token->user_id);
+ }
+ return auth_token;
+}
+
+// The main test class for Gatekeeper HIDL HAL.
+class GatekeeperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void setUid(uint32_t uid) { uid_ = uid; }
+
+ void doEnroll(GatekeeperRequest &req, GatekeeperResponse &rsp) {
+ while (true) {
+ auto ret = gatekeeper_->enroll(
+ uid_, req.curPwdHandle, req.curPwd, req.newPwd,
+ [&rsp](const GatekeeperResponse &cbRsp) { rsp = cbRsp; });
+ ASSERT_TRUE(ret.isOk());
+ if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ }
+
+ void doVerify(GatekeeperRequest &req, GatekeeperResponse &rsp) {
+ while (true) {
+ auto ret = gatekeeper_->verify(
+ uid_, req.challenge, req.curPwdHandle, req.newPwd,
+ [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+ ASSERT_TRUE(ret.isOk());
+ if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ }
+
+ void doDeleteUser(GatekeeperResponse &rsp) {
+ while (true) {
+ auto ret = gatekeeper_->deleteUser(
+ uid_, [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+ ASSERT_TRUE(ret.isOk());
+ if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ }
+
+ void doDeleteAllUsers(GatekeeperResponse &rsp) {
+ while (true) {
+ auto ret = gatekeeper_->deleteAllUsers(
+ [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; });
+ ASSERT_TRUE(ret.isOk());
+ if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ }
+
+ void generatePassword(hidl_vec<uint8_t> &password, uint8_t seed) {
+ password.resize(16);
+ memset(password.data(), seed, password.size());
+ }
+
+ void checkEnroll(GatekeeperResponse &rsp, bool expectSuccess) {
+ if (expectSuccess) {
+ EXPECT_EQ(GatekeeperStatusCode::STATUS_OK, rsp.code);
+ EXPECT_NE(nullptr, rsp.data.data());
+ EXPECT_GT(rsp.data.size(), UINT32_C(0));
+ } else {
+ EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code);
+ EXPECT_EQ(UINT32_C(0), rsp.data.size());
+ }
+ }
+
+ void checkVerify(GatekeeperResponse &rsp, uint64_t challenge,
+ bool expectSuccess) {
+ if (expectSuccess) {
+ EXPECT_GE(rsp.code, GatekeeperStatusCode::STATUS_OK);
+ EXPECT_LE(rsp.code, GatekeeperStatusCode::STATUS_REENROLL);
+
+ const hw_auth_token_t *auth_token = toAuthToken(rsp);
+ ASSERT_NE(nullptr, auth_token);
+ EXPECT_EQ(challenge, auth_token->challenge);
+ } else {
+ EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code);
+ EXPECT_EQ(UINT32_C(0), rsp.data.size());
+ }
+ }
+
+ void enrollNewPassword(hidl_vec<uint8_t> &password, GatekeeperResponse &rsp,
+ bool expectSuccess) {
+ GatekeeperRequest req;
+ req.newPwd.setToExternal(password.data(), password.size());
+ doEnroll(req, rsp);
+ checkEnroll(rsp, expectSuccess);
+ }
+
+ void verifyPassword(hidl_vec<uint8_t> &password,
+ hidl_vec<uint8_t> &passwordHandle, uint64_t challenge,
+ GatekeeperResponse &verifyRsp, bool expectSuccess) {
+ GatekeeperRequest verifyReq;
+
+ // build verify request for the same password (we want it to succeed)
+ verifyReq.newPwd = password;
+ // use enrolled password handle we've got
+ verifyReq.curPwdHandle = passwordHandle;
+ verifyReq.challenge = challenge;
+ doVerify(verifyReq, verifyRsp);
+ checkVerify(verifyRsp, challenge, expectSuccess);
+ }
+
+ protected:
+ sp<IGatekeeper> gatekeeper_;
+ uint32_t uid_;
+
+ public:
+ GatekeeperHidlTest() : uid_(0) {}
+ virtual void SetUp() override {
+ GatekeeperResponse rsp;
+ gatekeeper_ = ::testing::VtsHalHidlTargetTestBase::getService<IGatekeeper>();
+ ASSERT_NE(nullptr, gatekeeper_.get());
+ doDeleteAllUsers(rsp);
+ }
+
+ virtual void TearDown() override {
+ GatekeeperResponse rsp;
+ doDeleteAllUsers(rsp);
+ }
+};
+
+/**
+ * Ensure we can enroll new password
+ */
+TEST_F(GatekeeperHidlTest, EnrollSuccess) {
+ hidl_vec<uint8_t> password;
+ GatekeeperResponse rsp;
+ ALOGI("Testing Enroll (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, rsp, true);
+ ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can not enroll empty password
+ */
+TEST_F(GatekeeperHidlTest, EnrollNoPassword) {
+ hidl_vec<uint8_t> password;
+ GatekeeperResponse rsp;
+ ALOGI("Testing Enroll (expected failure)");
+ enrollNewPassword(password, rsp, false);
+ ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can successfully verify previously enrolled password
+ */
+TEST_F(GatekeeperHidlTest, VerifySuccess) {
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ hidl_vec<uint8_t> password;
+
+ ALOGI("Testing Enroll+Verify (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+ ALOGI("Testing Enroll+Verify done");
+}
+
+/**
+ * Ensure we can securely update password (keep the same
+ * secure user_id) if we prove we know old password
+ */
+TEST_F(GatekeeperHidlTest, TrustedReenroll) {
+ GatekeeperResponse enrollRsp;
+ GatekeeperRequest reenrollReq;
+ GatekeeperResponse reenrollRsp;
+ GatekeeperResponse verifyRsp;
+ GatekeeperResponse reenrollVerifyRsp;
+ hidl_vec<uint8_t> password;
+ hidl_vec<uint8_t> newPassword;
+
+ generatePassword(password, 0);
+
+ ALOGI("Testing Trusted Reenroll (expected success)");
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Primary Enroll+Verify done");
+
+ generatePassword(newPassword, 1);
+ reenrollReq.newPwd.setToExternal(newPassword.data(), newPassword.size());
+ reenrollReq.curPwd.setToExternal(password.data(), password.size());
+ reenrollReq.curPwdHandle.setToExternal(enrollRsp.data.data(),
+ enrollRsp.data.size());
+
+ doEnroll(reenrollReq, reenrollRsp);
+ checkEnroll(reenrollRsp, true);
+ verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+ ALOGI("Trusted ReEnroll+Verify done");
+
+ const hw_auth_token_t *first = toAuthToken(verifyRsp);
+ const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp);
+ if (first != nullptr && second != nullptr) {
+ EXPECT_EQ(first->user_id, second->user_id);
+ }
+ ALOGI("Testing Trusted Reenroll done");
+}
+
+/**
+ * Ensure we can update password (and get new
+ * secure user_id) if we don't know old password
+ */
+TEST_F(GatekeeperHidlTest, UntrustedReenroll) {
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse reenrollRsp;
+ GatekeeperResponse verifyRsp;
+ GatekeeperResponse reenrollVerifyRsp;
+ hidl_vec<uint8_t> password;
+ hidl_vec<uint8_t> newPassword;
+
+ ALOGI("Testing Untrusted Reenroll (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Primary Enroll+Verify done");
+
+ generatePassword(newPassword, 1);
+ enrollNewPassword(newPassword, reenrollRsp, true);
+ verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+ ALOGI("Untrusted ReEnroll+Verify done");
+
+ const hw_auth_token_t *first = toAuthToken(verifyRsp);
+ const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp);
+ if (first != nullptr && second != nullptr) {
+ EXPECT_NE(first->user_id, second->user_id);
+ }
+ ALOGI("Testing Untrusted Reenroll done");
+}
+
+/**
+ * Ensure we dont get successful verify with invalid data
+ */
+TEST_F(GatekeeperHidlTest, VerifyNoData) {
+ hidl_vec<uint8_t> password;
+ hidl_vec<uint8_t> passwordHandle;
+ GatekeeperResponse verifyRsp;
+
+ ALOGI("Testing Verify (expected failure)");
+ verifyPassword(password, passwordHandle, 0, verifyRsp, false);
+ EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code);
+ ALOGI("Testing Verify done");
+}
+
+/**
+ * Ensure we can not verify password after we enrolled it and then deleted user
+ */
+TEST_F(GatekeeperHidlTest, DeleteUserTest) {
+ hidl_vec<uint8_t> password;
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ GatekeeperResponse delRsp;
+ ALOGI("Testing deleteUser (expected success)");
+ setUid(10001);
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Enroll+Verify done");
+ doDeleteUser(delRsp);
+ EXPECT_EQ(UINT32_C(0), delRsp.data.size());
+ EXPECT_TRUE(delRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+ delRsp.code == GatekeeperStatusCode::STATUS_OK);
+ ALOGI("DeleteUser done");
+ if (delRsp.code == GatekeeperStatusCode::STATUS_OK) {
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, false);
+ EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code);
+ ALOGI("Verify after Delete done (must fail)");
+ }
+ ALOGI("Testing deleteUser done: rsp=%" PRIi32, delRsp.code);
+}
+
+/**
+ * Ensure we can not delete a user that does not exist
+ */
+TEST_F(GatekeeperHidlTest, DeleteInvalidUserTest) {
+ hidl_vec<uint8_t> password;
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ GatekeeperResponse delRsp1;
+ GatekeeperResponse delRsp2;
+ ALOGI("Testing deleteUser (expected failure)");
+ setUid(10002);
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Enroll+Verify done");
+
+ // Delete the user
+ doDeleteUser(delRsp1);
+ EXPECT_EQ(UINT32_C(0), delRsp1.data.size());
+ EXPECT_TRUE(delRsp1.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+ delRsp1.code == GatekeeperStatusCode::STATUS_OK);
+
+ // Delete the user again
+ doDeleteUser(delRsp2);
+ EXPECT_EQ(UINT32_C(0), delRsp2.data.size());
+ EXPECT_TRUE(delRsp2.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+ delRsp2.code == GatekeeperStatusCode::ERROR_GENERAL_FAILURE);
+ ALOGI("DeleteUser done");
+ ALOGI("Testing deleteUser done: rsp=%" PRIi32, delRsp2.code);
+}
+
+/**
+ * Ensure we can not verify passwords after we enrolled them and then deleted
+ * all users
+ */
+TEST_F(GatekeeperHidlTest, DeleteAllUsersTest) {
+ struct UserData {
+ uint32_t userId;
+ hidl_vec<uint8_t> password;
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ UserData(int id) { userId = id; }
+ } users[3]{10001, 10002, 10003};
+ GatekeeperResponse delAllRsp;
+ ALOGI("Testing deleteAllUsers (expected success)");
+
+ // enroll multiple users
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ generatePassword(users[i].password, (i % 255) + 1);
+ enrollNewPassword(users[i].password, users[i].enrollRsp, true);
+ }
+ ALOGI("Multiple users enrolled");
+
+ // verify multiple users
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ verifyPassword(users[i].password, users[i].enrollRsp.data, 0,
+ users[i].verifyRsp, true);
+ }
+ ALOGI("Multiple users verified");
+
+ doDeleteAllUsers(delAllRsp);
+ EXPECT_EQ(UINT32_C(0), delAllRsp.data.size());
+ EXPECT_TRUE(delAllRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED ||
+ delAllRsp.code == GatekeeperStatusCode::STATUS_OK);
+ ALOGI("All users deleted");
+
+ if (delAllRsp.code == GatekeeperStatusCode::STATUS_OK) {
+ // verify multiple users after they are deleted; all must fail
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ verifyPassword(users[i].password, users[i].enrollRsp.data, 0,
+ users[i].verifyRsp, false);
+ EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE,
+ users[i].verifyRsp.code);
+ }
+ ALOGI("Multiple users verified after delete (all must fail)");
+ }
+
+ ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, delAllRsp.code);
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp
new file mode 100644
index 0000000..33f70eb
--- /dev/null
+++ b/gatekeeper/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/vts/functional",
+]
diff --git a/gnss/1.0/Android.bp b/gnss/1.0/Android.bp
new file mode 100644
index 0000000..16895b6
--- /dev/null
+++ b/gnss/1.0/Android.bp
@@ -0,0 +1,195 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.gnss@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IAGnss.hal",
+ "IAGnssCallback.hal",
+ "IAGnssRil.hal",
+ "IAGnssRilCallback.hal",
+ "IGnss.hal",
+ "IGnssBatching.hal",
+ "IGnssBatchingCallback.hal",
+ "IGnssCallback.hal",
+ "IGnssConfiguration.hal",
+ "IGnssDebug.hal",
+ "IGnssGeofenceCallback.hal",
+ "IGnssGeofencing.hal",
+ "IGnssMeasurement.hal",
+ "IGnssMeasurementCallback.hal",
+ "IGnssNavigationMessage.hal",
+ "IGnssNavigationMessageCallback.hal",
+ "IGnssNi.hal",
+ "IGnssNiCallback.hal",
+ "IGnssXtra.hal",
+ "IGnssXtraCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.gnss@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gnss@1.0",
+ srcs: [
+ ":android.hardware.gnss@1.0_hal",
+ ],
+ out: [
+ "android/hardware/gnss/1.0/types.cpp",
+ "android/hardware/gnss/1.0/AGnssAll.cpp",
+ "android/hardware/gnss/1.0/AGnssCallbackAll.cpp",
+ "android/hardware/gnss/1.0/AGnssRilAll.cpp",
+ "android/hardware/gnss/1.0/AGnssRilCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssAll.cpp",
+ "android/hardware/gnss/1.0/GnssBatchingAll.cpp",
+ "android/hardware/gnss/1.0/GnssBatchingCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssConfigurationAll.cpp",
+ "android/hardware/gnss/1.0/GnssDebugAll.cpp",
+ "android/hardware/gnss/1.0/GnssGeofenceCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssGeofencingAll.cpp",
+ "android/hardware/gnss/1.0/GnssMeasurementAll.cpp",
+ "android/hardware/gnss/1.0/GnssMeasurementCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssNavigationMessageAll.cpp",
+ "android/hardware/gnss/1.0/GnssNavigationMessageCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssNiAll.cpp",
+ "android/hardware/gnss/1.0/GnssNiCallbackAll.cpp",
+ "android/hardware/gnss/1.0/GnssXtraAll.cpp",
+ "android/hardware/gnss/1.0/GnssXtraCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.gnss@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gnss@1.0",
+ srcs: [
+ ":android.hardware.gnss@1.0_hal",
+ ],
+ out: [
+ "android/hardware/gnss/1.0/types.h",
+ "android/hardware/gnss/1.0/IAGnss.h",
+ "android/hardware/gnss/1.0/IHwAGnss.h",
+ "android/hardware/gnss/1.0/BnHwAGnss.h",
+ "android/hardware/gnss/1.0/BpHwAGnss.h",
+ "android/hardware/gnss/1.0/BsAGnss.h",
+ "android/hardware/gnss/1.0/IAGnssCallback.h",
+ "android/hardware/gnss/1.0/IHwAGnssCallback.h",
+ "android/hardware/gnss/1.0/BnHwAGnssCallback.h",
+ "android/hardware/gnss/1.0/BpHwAGnssCallback.h",
+ "android/hardware/gnss/1.0/BsAGnssCallback.h",
+ "android/hardware/gnss/1.0/IAGnssRil.h",
+ "android/hardware/gnss/1.0/IHwAGnssRil.h",
+ "android/hardware/gnss/1.0/BnHwAGnssRil.h",
+ "android/hardware/gnss/1.0/BpHwAGnssRil.h",
+ "android/hardware/gnss/1.0/BsAGnssRil.h",
+ "android/hardware/gnss/1.0/IAGnssRilCallback.h",
+ "android/hardware/gnss/1.0/IHwAGnssRilCallback.h",
+ "android/hardware/gnss/1.0/BnHwAGnssRilCallback.h",
+ "android/hardware/gnss/1.0/BpHwAGnssRilCallback.h",
+ "android/hardware/gnss/1.0/BsAGnssRilCallback.h",
+ "android/hardware/gnss/1.0/IGnss.h",
+ "android/hardware/gnss/1.0/IHwGnss.h",
+ "android/hardware/gnss/1.0/BnHwGnss.h",
+ "android/hardware/gnss/1.0/BpHwGnss.h",
+ "android/hardware/gnss/1.0/BsGnss.h",
+ "android/hardware/gnss/1.0/IGnssBatching.h",
+ "android/hardware/gnss/1.0/IHwGnssBatching.h",
+ "android/hardware/gnss/1.0/BnHwGnssBatching.h",
+ "android/hardware/gnss/1.0/BpHwGnssBatching.h",
+ "android/hardware/gnss/1.0/BsGnssBatching.h",
+ "android/hardware/gnss/1.0/IGnssBatchingCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssBatchingCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssBatchingCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssBatchingCallback.h",
+ "android/hardware/gnss/1.0/BsGnssBatchingCallback.h",
+ "android/hardware/gnss/1.0/IGnssCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssCallback.h",
+ "android/hardware/gnss/1.0/BsGnssCallback.h",
+ "android/hardware/gnss/1.0/IGnssConfiguration.h",
+ "android/hardware/gnss/1.0/IHwGnssConfiguration.h",
+ "android/hardware/gnss/1.0/BnHwGnssConfiguration.h",
+ "android/hardware/gnss/1.0/BpHwGnssConfiguration.h",
+ "android/hardware/gnss/1.0/BsGnssConfiguration.h",
+ "android/hardware/gnss/1.0/IGnssDebug.h",
+ "android/hardware/gnss/1.0/IHwGnssDebug.h",
+ "android/hardware/gnss/1.0/BnHwGnssDebug.h",
+ "android/hardware/gnss/1.0/BpHwGnssDebug.h",
+ "android/hardware/gnss/1.0/BsGnssDebug.h",
+ "android/hardware/gnss/1.0/IGnssGeofenceCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssGeofenceCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssGeofenceCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssGeofenceCallback.h",
+ "android/hardware/gnss/1.0/BsGnssGeofenceCallback.h",
+ "android/hardware/gnss/1.0/IGnssGeofencing.h",
+ "android/hardware/gnss/1.0/IHwGnssGeofencing.h",
+ "android/hardware/gnss/1.0/BnHwGnssGeofencing.h",
+ "android/hardware/gnss/1.0/BpHwGnssGeofencing.h",
+ "android/hardware/gnss/1.0/BsGnssGeofencing.h",
+ "android/hardware/gnss/1.0/IGnssMeasurement.h",
+ "android/hardware/gnss/1.0/IHwGnssMeasurement.h",
+ "android/hardware/gnss/1.0/BnHwGnssMeasurement.h",
+ "android/hardware/gnss/1.0/BpHwGnssMeasurement.h",
+ "android/hardware/gnss/1.0/BsGnssMeasurement.h",
+ "android/hardware/gnss/1.0/IGnssMeasurementCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssMeasurementCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssMeasurementCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssMeasurementCallback.h",
+ "android/hardware/gnss/1.0/BsGnssMeasurementCallback.h",
+ "android/hardware/gnss/1.0/IGnssNavigationMessage.h",
+ "android/hardware/gnss/1.0/IHwGnssNavigationMessage.h",
+ "android/hardware/gnss/1.0/BnHwGnssNavigationMessage.h",
+ "android/hardware/gnss/1.0/BpHwGnssNavigationMessage.h",
+ "android/hardware/gnss/1.0/BsGnssNavigationMessage.h",
+ "android/hardware/gnss/1.0/IGnssNavigationMessageCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssNavigationMessageCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssNavigationMessageCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssNavigationMessageCallback.h",
+ "android/hardware/gnss/1.0/BsGnssNavigationMessageCallback.h",
+ "android/hardware/gnss/1.0/IGnssNi.h",
+ "android/hardware/gnss/1.0/IHwGnssNi.h",
+ "android/hardware/gnss/1.0/BnHwGnssNi.h",
+ "android/hardware/gnss/1.0/BpHwGnssNi.h",
+ "android/hardware/gnss/1.0/BsGnssNi.h",
+ "android/hardware/gnss/1.0/IGnssNiCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssNiCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssNiCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssNiCallback.h",
+ "android/hardware/gnss/1.0/BsGnssNiCallback.h",
+ "android/hardware/gnss/1.0/IGnssXtra.h",
+ "android/hardware/gnss/1.0/IHwGnssXtra.h",
+ "android/hardware/gnss/1.0/BnHwGnssXtra.h",
+ "android/hardware/gnss/1.0/BpHwGnssXtra.h",
+ "android/hardware/gnss/1.0/BsGnssXtra.h",
+ "android/hardware/gnss/1.0/IGnssXtraCallback.h",
+ "android/hardware/gnss/1.0/IHwGnssXtraCallback.h",
+ "android/hardware/gnss/1.0/BnHwGnssXtraCallback.h",
+ "android/hardware/gnss/1.0/BpHwGnssXtraCallback.h",
+ "android/hardware/gnss/1.0/BsGnssXtraCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.gnss@1.0",
+ generated_sources: ["android.hardware.gnss@1.0_genc++"],
+ generated_headers: ["android.hardware.gnss@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.gnss@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/gnss/1.0/Android.mk b/gnss/1.0/Android.mk
new file mode 100644
index 0000000..5985c87
--- /dev/null
+++ b/gnss/1.0/Android.mk
@@ -0,0 +1,1103 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (GnssConstellationType)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssConstellationType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssConstellationType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssLocation)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocation.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssLocation
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssLocationFlags)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocationFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssLocationFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssMax)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssMax.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssMax
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnss.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnss.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnss
+
+$(GEN): $(LOCAL_PATH)/IAGnss.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssCallback
+
+$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssRil.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRil.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssRil
+
+$(GEN): $(LOCAL_PATH)/IAGnssRil.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssRilCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRilCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssRilCallback
+
+$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnss.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnss.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnss.hal
+$(GEN): $(LOCAL_PATH)/IAGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnss
+
+$(GEN): $(LOCAL_PATH)/IGnss.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssBatching.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatching.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssBatching
+
+$(GEN): $(LOCAL_PATH)/IGnssBatching.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssBatchingCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatchingCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssBatchingCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssConfiguration.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssConfiguration.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssConfiguration
+
+$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssDebug.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssDebug.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssDebug
+
+$(GEN): $(LOCAL_PATH)/IGnssDebug.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssGeofenceCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofenceCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssGeofenceCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssGeofencing.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofencing.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssGeofencing
+
+$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssMeasurement.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurement.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssMeasurement
+
+$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssMeasurementCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurementCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssMeasurementCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNavigationMessage.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNavigationMessage
+
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNavigationMessageCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessageCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNi.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNi.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNi
+
+$(GEN): $(LOCAL_PATH)/IGnssNi.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNiCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNiCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNiCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssXtra.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtra.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssXtra
+
+$(GEN): $(LOCAL_PATH)/IGnssXtra.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssXtraCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtraCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssXtraCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (GnssConstellationType)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssConstellationType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssConstellationType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssLocation)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocation.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssLocation
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssLocationFlags)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocationFlags.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssLocationFlags
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (GnssMax)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssMax.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::types.GnssMax
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnss.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnss.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnss
+
+$(GEN): $(LOCAL_PATH)/IAGnss.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssCallback
+
+$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssRil.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRil.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssRil
+
+$(GEN): $(LOCAL_PATH)/IAGnssRil.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IAGnssRilCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRilCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IAGnssRilCallback
+
+$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnss.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnss.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnss.hal
+$(GEN): $(LOCAL_PATH)/IAGnss.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnss
+
+$(GEN): $(LOCAL_PATH)/IGnss.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssBatching.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatching.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssBatching
+
+$(GEN): $(LOCAL_PATH)/IGnssBatching.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssBatchingCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatchingCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssBatchingCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssConfiguration.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssConfiguration.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssConfiguration
+
+$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssDebug.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssDebug.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssDebug
+
+$(GEN): $(LOCAL_PATH)/IGnssDebug.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssGeofenceCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofenceCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssGeofenceCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssGeofencing.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofencing.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssGeofencing
+
+$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssMeasurement.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurement.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssMeasurement
+
+$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssMeasurementCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurementCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssMeasurementCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNavigationMessage.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNavigationMessage
+
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNavigationMessageCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessageCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNi.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNi.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNi
+
+$(GEN): $(LOCAL_PATH)/IGnssNi.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssNiCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNiCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssNiCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssXtra.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtra.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssXtra
+
+$(GEN): $(LOCAL_PATH)/IGnssXtra.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IGnssXtraCallback.hal
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtraCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtraCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0::IGnssXtraCallback
+
+$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/gnss/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IAGnss.hal
+$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRil.hal
+$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnss.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatching.hal
+$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal
+$(GEN): $(LOCAL_PATH)/IGnssDebug.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal
+$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal
+$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssNi.hal
+$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtra.hal
+$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.gnss@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/gnss/1.0/IAGnss.hal b/gnss/1.0/IAGnss.hal
new file mode 100644
index 0000000..b8f5746
--- /dev/null
+++ b/gnss/1.0/IAGnss.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IAGnssCallback;
+
+/*
+ * Extended interface for AGNSS support.
+ */
+interface IAGnss {
+ @export(name="", value_prefix="APN_IP_")
+ enum ApnIpType : uint8_t {
+ INVALID = 0,
+ IPV4 = 1,
+ IPV6 = 2,
+ IPV4V6 = 3
+ };
+
+ /*
+ * Opens the AGNSS interface and provides the callback routines to the
+ * implementation of this interface.
+ *
+ * @param callback Handle to the AGNSS status callback interface.
+ */
+ setCallback(IAGnssCallback callback);
+
+ /*
+ * Notifies that the AGNSS data connection has been closed.
+ *
+ * @return success True if the operation is successful.
+ */
+ dataConnClosed() generates (bool success);
+
+ /*
+ * Notifies that a data connection is not available for AGNSS.
+ *
+ * @return success True if the operation is successful.
+ */
+ dataConnFailed() generates (bool success);
+
+ /*
+ * Sets the hostname and port for the AGNSS server.
+ *
+ * @param type Specifies if SUPL or C2K.
+ * @param hostname Hostname of the AGNSS server.
+ * @param port Port number associated with the server.
+ *
+ * @return success True if the operation is successful.
+ */
+ setServer(AGnssType type, string hostname, int32_t port)
+ generates (bool success);
+
+ /*
+ * Notifies that a data connection is available and sets the name of the
+ * APN, and its IP type, to be used for SUPL connections.
+ *
+ * @param apn Access Point Name(follows regular APN naming convention).
+ * @param apnIpType Specifies if SUPL or C2K.
+ *
+ * @return success True if the operation is successful.
+ */
+ dataConnOpen(string apn, ApnIpType apnIpType)
+ generates (bool success);
+};
diff --git a/gnss/1.0/IAGnssCallback.hal b/gnss/1.0/IAGnssCallback.hal
new file mode 100644
index 0000000..fe2e101
--- /dev/null
+++ b/gnss/1.0/IAGnssCallback.hal
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/** Callback structure for the AGNSS interface. */
+interface IAGnssCallback {
+ /** AGNSS type **/
+ @export(name="", value_prefix="AGPS_")
+ enum AGnssType : uint8_t {
+ TYPE_SUPL = 1,
+ TYPE_C2K = 2
+ };
+
+ @export(name="", value_prefix="GNSS_")
+ enum AGnssStatusValue : uint8_t {
+ /** GNSS requests data connection for AGNSS. */
+ REQUEST_AGNSS_DATA_CONN = 1,
+ /** GNSS releases the AGNSS data connection. */
+ RELEASE_AGNSS_DATA_CONN = 2,
+ /** AGNSS data connection initiated */
+ AGNSS_DATA_CONNECTED = 3,
+ /** AGNSS data connection completed */
+ AGNSS_DATA_CONN_DONE = 4,
+ /** AGNSS data connection failed */
+ AGNSS_DATA_CONN_FAILED = 5
+ };
+
+ /*
+ * Represents the status of AGNSS augmented to support IPv4.
+ */
+ @export(name="", value_prefix="GPS_")
+ struct AGnssStatusIpV4 {
+ AGnssType type;
+ AGnssStatusValue status;
+ /*
+ * 32-bit IPv4 address.
+ */
+ uint32_t ipV4Addr;
+ };
+
+ /*
+ * Represents the status of AGNSS augmented to support IPv6.
+ */
+ struct AGnssStatusIpV6 {
+ AGnssType type;
+ AGnssStatusValue status;
+ /*
+ * 128-bit IPv6 address.
+ */
+ uint8_t[16] ipV6Addr;
+ };
+
+ /*
+ * Callback with AGNSS(IpV4) status information.
+ *
+ * @param status Will be of type AGnssStatusIpV4.
+ */
+ agnssStatusIpV4Cb(AGnssStatusIpV4 status);
+
+ /*
+ * Callback with AGNSS(IpV6) status information.
+ *
+ * @param status Will be of type AGnssStatusIpV6.
+ */
+ agnssStatusIpV6Cb(AGnssStatusIpV6 status);
+
+};
diff --git a/gnss/1.0/IAGnssRil.hal b/gnss/1.0/IAGnssRil.hal
new file mode 100644
index 0000000..6292273
--- /dev/null
+++ b/gnss/1.0/IAGnssRil.hal
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IAGnssRilCallback;
+
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface
+ * Layer interface allows the GNSS chipset to request radio interface layer
+ * information from Android platform. Examples of such information are reference
+ * location, unique subscriber ID, phone number string and network availability changes.
+ */
+interface IAGnssRil {
+ @export(name="", value_prefix="AGPS_SETID_TYPE_")
+ enum SetIDType : uint8_t {
+ NONE = 0,
+ IMSI = 1,
+ MSISDM = 2
+ };
+
+ @export(name="", value_prefix="AGPS_RIL_NETWORK_TYPE_")
+ enum NetworkType : uint8_t {
+ MOBILE = 0,
+ WIFI = 1,
+ MMS = 2,
+ SUPL = 3,
+ DUN = 4,
+ HIPRI = 5,
+ WIMAX = 6,
+ };
+
+ @export(name="", value_prefix="AGPS_REF_LOCATION_TYPE_")
+ enum AGnssRefLocationType : uint8_t {
+ GSM_CELLID = 1,
+ UMTS_CELLID = 2,
+ LTE_CELLID = 4,
+ };
+
+ /* CellID for 2G, 3G and LTE, used in AGNSS. */
+ struct AGnssRefLocationCellID {
+ AGnssRefLocationType type;
+
+ /* Mobile Country Code. */
+ uint16_t mcc;
+
+ /* Mobile Network Code .*/
+ uint16_t mnc;
+
+ /*
+ * Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+ * lac is populated with tac, to ensure that we don't break old clients that
+ * might rely in the old (wrong) behavior.
+ */
+ uint16_t lac;
+
+ /* Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
+ uint32_t cid;
+
+ /* Tracking Area Code in LTE. */
+ uint16_t tac;
+
+ /* Physical Cell id in LTE (not used in 2G and 3G) */
+ uint16_t pcid;
+ };
+
+ /* Represents ref locations */
+ struct AGnssRefLocation {
+ AGnssRefLocationType type;
+
+ AGnssRefLocationCellID cellID;
+ };
+
+ /*
+ * Opens the AGNSS interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Interface for AGnssRil callbacks.
+ */
+ setCallback(IAGnssRilCallback callback);
+
+ /*
+ * Sets the reference location.
+ *
+ * @param agnssReflocation AGNSS reference location CellID.
+ */
+ setRefLocation(AGnssRefLocation agnssReflocation);
+
+ /*
+ * Sets the SET ID.
+ *
+ * @param type Must be populated with either IMSI or MSISDN or NONE.
+ * @param setid If type is IMSI then setid is populated with
+ * a string representing the unique Subscriber ID, for example, the IMSI for
+ * a GMS phone. If type is MSISDN, then setid must contain
+ * the phone number string for line 1. For example, the MSISDN for a GSM phone.
+ * If the type is NONE, then the string must be empty.
+ *
+ * @return success True if all parameters were valid and operation was
+ * successful.
+ */
+ setSetId(SetIDType type, string setid) generates (bool success);
+
+ /*
+ * Notify GNSS of network status changes.
+ *
+ * @param connected Indicates whether network connectivity exists and
+ * it is possible to establish connections and pass data.
+ * @param type Indicates the kind of network, for eg. mobile, wifi etc.
+ * @param roaming Indicates whether the device is currently roaming on
+ * this network.
+ *
+ * @return success True is all parameters were valid and operation was
+ * successful.
+ */
+ updateNetworkState(bool connected, NetworkType type, bool roaming)
+ generates (bool success);
+
+ /*
+ * Notify GNSS of network status changes.
+ *
+ * @param available Indicates whether network connectivity is available.
+ * @param apn String containing the Access Point Name.
+ *
+ * @return success True if all parameters were valid and the operation was
+ * successful.
+ * TODO(b/32022567): Add VTS test to validate the format of APN.
+ */
+ updateNetworkAvailability(bool available, string apn) generates (bool success);
+
+};
diff --git a/gnss/1.0/IAGnssRilCallback.hal b/gnss/1.0/IAGnssRilCallback.hal
new file mode 100644
index 0000000..2d64e54
--- /dev/null
+++ b/gnss/1.0/IAGnssRilCallback.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/*
+ * Callback for IAGnssRil interface. Used to request SET ID and
+ * Reference Location.
+ */
+interface IAGnssRilCallback {
+ /* Kinds of SET ID that can be requested */
+ @export(name="", value_prefix="AGPS_RIL_REQUEST_SETID_")
+ enum ID : uint32_t {
+ IMSI = 1 << 0L,
+ MSISDN = 1 << 1L,
+ };
+
+ /*
+ * The Hal uses this API to request a SET ID.
+ *
+ * @param setIdflag Specifies the kind of SET ID that is required by the HAL.
+ */
+ requestSetIdCb(bitfield<ID> setIdflag);
+
+ /*
+ * The Hal uses this API to request a reference location.
+ *
+ */
+ requestRefLocCb();
+
+};
diff --git a/gnss/1.0/IGnss.hal b/gnss/1.0/IGnss.hal
new file mode 100644
index 0000000..5cde79e
--- /dev/null
+++ b/gnss/1.0/IGnss.hal
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IAGnss;
+import IAGnssRil;
+import IGnssBatching;
+import IGnssCallback;
+import IGnssConfiguration;
+import IGnssDebug;
+import IGnssMeasurement;
+import IGnssNavigationMessage;
+import IGnssGeofencing;
+import IGnssNi;
+import IGnssXtra;
+
+/* Represents the standard GNSS (Global Navigation Satellite System) interface. */
+interface IGnss {
+ /* Requested operational mode for GNSS operation. */
+ @export(name="", value_prefix="GPS_POSITION_MODE_")
+ enum GnssPositionMode : uint8_t {
+ /** Mode for running GNSS standalone (no assistance). */
+ STANDALONE = 0,
+ /** AGNSS MS-Based mode. */
+ MS_BASED = 1,
+ /*
+ * AGNSS MS-Assisted mode. This mode is not maintained by the platform anymore.
+ * It is strongly recommended to use MS_BASED instead.
+ */
+ MS_ASSISTED = 2,
+ };
+
+ /* Requested recurrence mode for GNSS operation. */
+ @export(name="", value_prefix="GPS_POSITION_")
+ enum GnssPositionRecurrence : uint32_t {
+ /** Receive GNSS fixes on a recurring basis at a specified period. */
+ RECURRENCE_PERIODIC = 0,
+ /** Request a single shot GNSS fix. */
+ RECURRENCE_SINGLE = 1
+ };
+
+ /*
+ * Flags used to specify which aiding data to delete when calling
+ * deleteAidingData().
+ */
+ @export(name="", value_prefix="GPS_")
+ enum GnssAidingData : uint16_t {
+ DELETE_EPHEMERIS = 0x0001,
+ DELETE_ALMANAC = 0x0002,
+ DELETE_POSITION = 0x0004,
+ DELETE_TIME = 0x0008,
+ DELETE_IONO = 0x0010,
+ DELETE_UTC = 0x0020,
+ DELETE_HEALTH = 0x0040,
+ DELETE_SVDIR = 0x0080,
+ DELETE_SVSTEER = 0x0100,
+ DELETE_SADATA = 0x0200,
+ DELETE_RTI = 0x0400,
+ DELETE_CELLDB_INFO = 0x8000,
+ DELETE_ALL = 0xFFFF
+ };
+
+ /*
+ * Opens the interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Callback interface for IGnss.
+ *
+ * @return success Returns true on success.
+ */
+ setCallback(IGnssCallback callback) generates (bool success);
+
+ /*
+ * Starts a location output stream using the IGnssCallback
+ * gnssLocationCb(), following the settings from the most recent call to
+ * setPositionMode().
+ *
+ * This output must operate independently of any GNSS location batching
+ * operations, see the IGnssBatching.hal for details.
+ *
+ * @return success Returns true on success.
+ */
+ start() generates (bool success);
+
+ /*
+ * Stops the location output stream.
+ *
+ * @return success Returns true on success.
+ */
+ stop() generates (bool success);
+
+ /*
+ * Closes the interface.
+ */
+ cleanup();
+
+ /*
+ * Injects the current time.
+ *
+ * @param timeMs This is the UTC time received from the NTP server, its value
+ * is given in milliseconds since January 1, 1970.
+ * @param timeReferenceMs The corresponding value of
+ * SystemClock.elapsedRealtime() from the device when the NTP response was
+ * received in milliseconds.
+ * @param uncertaintyMs Uncertainty associated with the value represented by
+ * time. Represented in milliseconds.
+ *
+ * @return success Returns true if the operation is successful.
+ */
+ injectTime(GnssUtcTime timeMs, int64_t timeReferenceMs, int32_t uncertaintyMs)
+ generates (bool success);
+
+ /*
+ * Injects current location from another location provider (typically cell
+ * ID).
+ *
+ * @param latitudeDegrees Measured in Degrees.
+ * @param longitudeDegrees Measured in Degrees.
+ * @param accuracyMeters Measured in meters.
+ *
+ * @return success Returns true if successful.
+ */
+ injectLocation(double latitudeDegrees, double longitudeDegrees, float accuracyMeters)
+ generates (bool success);
+
+ /*
+ * Specifies that the next call to start will not use the
+ * information defined in the flags. GnssAidingData value of DELETE_ALL is
+ * passed for a cold start.
+ *
+ * @param aidingDataFlags Flags specifying the aiding data to be deleted.
+ */
+ deleteAidingData(GnssAidingData aidingDataFlags);
+
+ /*
+ * Sets the GnssPositionMode parameter,its associated recurrence value,
+ * the time between fixes,requested fix accuracy and time to first fix.
+ *
+ * @param mode Parameter must be one of MS_BASED or STANDALONE.
+ * It is allowed by the platform (and it is recommended) to fallback to
+ * MS_BASED if MS_ASSISTED is passed in, and MS_BASED is supported.
+ * @recurrence GNSS postion recurrence value, either periodic or single.
+ * @param minIntervalMs Represents the time between fixes in milliseconds.
+ * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
+ * @param preferredTimeMs Represents the requested time to first fix in milliseconds.
+
+ * @return success Returns true if successful.
+ */
+ setPositionMode(GnssPositionMode mode, GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs)
+ generates (bool success);
+
+ /*
+ * This method returns the IAGnssRil Interface.
+ *
+ * @return aGnssRilIface Handle to the IAGnssRil interface.
+ */
+ getExtensionAGnssRil() generates (IAGnssRil aGnssRilIface);
+
+ /*
+ * This method returns the IGnssGeofencing Interface.
+ *
+ * @return gnssGeofencingIface Handle to the IGnssGeofencing interface.
+ */
+ getExtensionGnssGeofencing() generates(IGnssGeofencing gnssGeofencingIface);
+
+ /*
+ * This method returns the IAGnss Interface.
+ *
+ * @return aGnssIface Handle to the IAGnss interface.
+ */
+ getExtensionAGnss() generates (IAGnss aGnssIface);
+
+ /*
+ * This method returns the IGnssNi interface.
+ *
+ * @return gnssNiIface Handle to the IGnssNi interface.
+ */
+ getExtensionGnssNi() generates (IGnssNi gnssNiIface);
+
+ /*
+ * This method returns the IGnssMeasurement interface.
+ *
+ * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+ */
+ getExtensionGnssMeasurement() generates (IGnssMeasurement gnssMeasurementIface);
+
+ /*
+ * This method returns the IGnssNavigationMessage interface.
+ *
+ * @return gnssNavigationIface gnssNavigationIface to the IGnssNavigationMessage interface.
+ */
+ getExtensionGnssNavigationMessage() generates (IGnssNavigationMessage gnssNavigationIface);
+
+ /*
+ * This method returns the IGnssXtra interface.
+ *
+ * @return xtraIface Handle to the IGnssXtra interface.
+ */
+ getExtensionXtra() generates (IGnssXtra xtraIface);
+
+ /*
+ * This method returns the IGnssConfiguration interface.
+ *
+ * @return gnssConfigIface Handle to the IGnssConfiguration interface.
+ */
+ getExtensionGnssConfiguration() generates (IGnssConfiguration gnssConfigIface);
+
+ /*
+ * This method returns the IGnssDebug interface.
+ *
+ * @return debugIface Handle to the IGnssDebug interface.
+ */
+ getExtensionGnssDebug() generates (IGnssDebug debugIface);
+
+ /*
+ * This method returns the IGnssBatching interface.
+ *
+ * @return batchingIface Handle to the IGnssBatching interface.
+ */
+ getExtensionGnssBatching() generates (IGnssBatching batchingIface);
+};
diff --git a/gnss/1.0/IGnssBatching.hal b/gnss/1.0/IGnssBatching.hal
new file mode 100644
index 0000000..6f2dde6
--- /dev/null
+++ b/gnss/1.0/IGnssBatching.hal
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IGnssBatchingCallback;
+
+/*
+ * Extended interface for GNSS Batching support.
+ *
+ * If this interface is supported, this batching request must be able to run in
+ * parallel with, or without, non-batched location requested by the
+ * IGnss start() & stop() - i.e. both requests must be handled independently,
+ * and not interfere with each other.
+ *
+ * For example, if a 1Hz continuous output is underway on the IGnssCallback,
+ * due to an IGnss start() operation,
+ * and then a IGnssBatching start() is called for a location every 10
+ * seconds, the newly added batching request must not disrupt the 1Hz
+ * continuous location output on the IGnssCallback.
+ *
+ * As with GNSS Location outputs, source of location must be GNSS satellite
+ * measurements, optionally using interial and baro sensors to improve
+ * relative motion filtering. No additional absolute positioning information,
+ * such as WiFi derived location, may be mixed with the GNSS information.
+ */
+
+interface IGnssBatching {
+ /*
+ * Enum which holds the bit masks for batching control.
+ */
+ @export(name="", value_prefix="FLP_BATCH_")
+ enum Flag : uint8_t {
+ /*
+ * If this flag is set, the hardware implementation
+ * must wake up the application processor when the FIFO is full, and
+ * call IGnssBatchingCallback to return the locations.
+ *
+ * If the flag is not set, the hardware implementation must drop
+ * the oldest data when the FIFO is full.
+ */
+ WAKEUP_ON_FIFO_FULL = 0x01
+ };
+
+ struct Options {
+ /*
+ * Time interval between samples in the location batch, in nano
+ * seconds.
+ */
+ int64_t periodNanos;
+
+ /*
+ * Flags controlling how batching should behave.
+ */
+ bitfield<Flag> flags;
+ };
+
+ /*
+ * Opens the interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Callback interface for IGnssBatching.
+ *
+ * @return success Returns true on success.
+ */
+ init(IGnssBatchingCallback callback) generates (bool success);
+
+ /*
+ * Return the batch size (in number of GnssLocation objects)
+ * available in this hardware implementation.
+ *
+ * If the available size is variable, for example, based on other operations
+ * consuming memory, this is the minimum size guaranteed to be available
+ * for batching operations.
+ *
+ * This may, for example, be used by the upper layer, to decide on the
+ * batching interval and whether the AP should be woken up or not.
+ *
+ * @return batchSize number of location objects supported per batch
+ */
+ getBatchSize() generates (uint16_t batchSize);
+
+ /*
+ * Start batching locations. This API is primarily used when the AP is
+ * asleep and the device can batch locations in the hardware.
+ *
+ * IGnssBatchingCallback is used to return the locations.
+ *
+ * When the buffer is full and WAKEUP_ON_FIFO_FULL is used,
+ * IGnssBatchingCallback must be called to return the locations.
+ *
+ * When the buffer is full and WAKEUP_ON_FIFO_FULL is not set,
+ * the oldest location object is dropped. In this case the AP must not be
+ * woken up. The AP would then generally be responsible for using
+ * flushBatchedLocation to explicitly ask for the location as needed,
+ * to avoid it being dropped.
+ *
+ * @param options See struct Options definition.
+ *
+ * @return success Returns true on success.
+ */
+ start(Options options) generates (bool success);
+
+ /**
+ * Retrieve all batched locations currently stored.
+ *
+ * IGnssBatchingCallback is used to return the location.
+ *
+ * IGnssBatchingCallback must be called in response, even if there are
+ * no locations to flush (in which case the Location vector must be empty).
+ *
+ * Subsequent calls to flushBatchedLocation
+ * must not return any of the locations returned in this call.
+ */
+ flush();
+
+ /**
+ * Stop batching.
+ *
+ * @return success Returns true on success.
+ */
+ stop() generates (bool success);
+
+ /**
+ * Closes the interface. If any batch operations are in progress,
+ * they must be stopped. If any locations are in the hardware batch, they
+ * must be deleted (and not sent via callback.)
+ *
+ * init() may be called again, after this, if the interface is to be restored
+ */
+ cleanup();
+
+};
diff --git a/gnss/1.0/IGnssBatchingCallback.hal b/gnss/1.0/IGnssBatchingCallback.hal
new file mode 100644
index 0000000..a8f4b88
--- /dev/null
+++ b/gnss/1.0/IGnssBatchingCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/* The callback interface to report measurements from the HAL. */
+interface IGnssBatchingCallback {
+ /*
+ * Called when a batch of locations is output, by various means, including
+ * a flush request, as well as the buffer becoming full (if appropriate option
+ * is set.)
+ *
+ * All locations returned by this callback must be cleared from the hardware
+ * buffer, such the sequential calls of this callback do not return any
+ * redundant locations. (Same lat/lon, at a new time, is acceptable.)
+ *
+ * @param locations GNSS Location information from HAL.
+ */
+ gnssLocationBatchCb(vec<GnssLocation> locations);
+};
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
new file mode 100644
index 0000000..0c3b9f0
--- /dev/null
+++ b/gnss/1.0/IGnssCallback.hal
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/*
+ * The interface is required for the HAL to communicate certain information
+ * like status and location info back to the platform, the platform implements
+ * the interfaces and passes a handle to the HAL.
+ */
+interface IGnssCallback {
+ /* Flags for the gnssSetCapabilities callback. */
+ @export(name="", value_prefix="GPS_CAPABILITY_")
+ enum Capabilities : uint32_t {
+ /*
+ * GNSS HAL schedules fixes for RECURRENCE_PERIODIC mode.
+ * If this is not set, then the framework will use 1000ms for
+ * minInterval and will call start() and stop() to schedule the GNSS.
+ */
+ SCHEDULING = 1 << 0,
+ /** GNSS supports MS-Based AGNSS mode */
+ MSB = 1 << 1,
+ /** GNSS supports MS-Assisted AGNSS mode */
+ MSA = 1 << 2,
+ /** GNSS supports single-shot fixes */
+ SINGLE_SHOT = 1 << 3,
+ /** GNSS supports on demand time injection */
+ ON_DEMAND_TIME = 1 << 4,
+ /** GNSS supports Geofencing */
+ GEOFENCING = 1 << 5,
+ /** GNSS supports Measurements for at least GPS. */
+ MEASUREMENTS = 1 << 6,
+ /** GNSS supports Navigation Messages */
+ NAV_MESSAGES = 1 << 7
+ };
+
+ /* GNSS status event values. */
+ @export(name="", value_prefix="GPS_STATUS_")
+ enum GnssStatusValue : uint8_t {
+ /** GNSS status unknown. */
+ NONE = 0,
+ /** GNSS has begun navigating. */
+ SESSION_BEGIN = 1,
+ /** GNSS has stopped navigating. */
+ SESSION_END = 2,
+ /** GNSS has powered on but is not navigating. */
+ ENGINE_ON = 3,
+ /** GNSS is powered off. */
+ ENGINE_OFF = 4
+ };
+
+ /*
+ * Flags that indicate information about the satellite
+ */
+ @export(name="", value_prefix="GNSS_SV_FLAGS_")
+ enum GnssSvFlags : uint8_t {
+ NONE = 0,
+ HAS_EPHEMERIS_DATA = 1 << 0,
+ HAS_ALMANAC_DATA = 1 << 1,
+ USED_IN_FIX = 1 << 2,
+ HAS_CARRIER_FREQUENCY = 1 << 3
+ };
+
+ struct GnssSvInfo {
+ /*
+ * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The
+ * distinction is made by looking at constellation field. Values must be
+ * in the range of:
+ *
+ * - GNSS: 1-32
+ * - SBAS: 120-151, 183-192
+ * - GLONASS: 1-24, the orbital slot number (OSN), if known. Or, if not:
+ * 93-106, the frequency channel number (FCN) (-7 to +6) offset by
+ * + 100
+ * i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6
+ * as 106.
+ * - QZSS: 193-200
+ * - Galileo: 1-36
+ * - Beidou: 1-37
+ */
+ int16_t svid;
+
+ /*
+ * Defines the constellation of the given SV.
+ */
+ GnssConstellationType constellation;
+
+ /*
+ * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+ * It contains the measured C/N0 value for the signal at the antenna port.
+ *
+ * This is a mandatory value.
+ */
+ float cN0Dbhz;
+
+ /** Elevation of SV in degrees. */
+ float elevationDegrees;
+
+ /** Azimuth of SV in degrees. */
+ float azimuthDegrees;
+
+ /*
+ * Carrier frequency of the signal tracked, for example it can be the
+ * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+ * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
+ * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
+ * for GPS.
+ *
+ * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+ * time, two GnssSvInfo structs must be reported for this same
+ * satellite, in one of the structs, all the values related
+ * to L1 must be filled, and in the other all of the values related to
+ * L5 must be filled.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_CARRIER_FREQUENCY.
+ */
+ float carrierFrequencyHz;
+
+ /*
+ * Contains additional data about the given SV.
+ */
+ bitfield<GnssSvFlags> svFlag;
+ };
+
+ /*
+ * Represents SV status.
+ */
+ struct GnssSvStatus {
+ /*
+ * Number of GNSS SVs currently visible, refers to the SVs stored in sv_list
+ */
+ uint32_t numSvs;
+
+ /*
+ * Pointer to an array of SVs information for all GNSS constellations,
+ * except GNSS, which is reported using svList
+ */
+ GnssSvInfo[GnssMax:SVS_COUNT] gnssSvList;
+
+ };
+
+ /*
+ * Called when a GNSS location is available.
+ *
+ * @param location Location information from HAL.
+ */
+ gnssLocationCb(GnssLocation location);
+
+ /*
+ * Called to communicate the status of the GNSS engine.
+ *
+ * @param status Status information from HAL.
+ */
+ gnssStatusCb(GnssStatusValue status);
+
+ /*
+ * @param svInfo SV status information from HAL.
+ */
+ gnssSvStatusCb(GnssSvStatus svInfo);
+
+ /*
+ * Called when NMEA data is available.
+ * Callback for reporting NMEA sentences.
+ *
+ * @param timestamp Marks the instance of reporting.
+ * @param nmea Follows standard NMEA 0183. Each sentence begins with a '$'
+ * and ends with a carriage return/line feed sequence and can be no longer
+ * than 80 characters of visible text (plus the line terminators). The data
+ * is contained within this single line with data items separated by commas.
+ * The data itself is just ascii text and may extend over multiple sentences
+ * in certain specialized instances but is normally fully contained in one
+ * variable length sentence. The data may vary in the amount of precision
+ * contained in the message. For example time might be indicated to decimal
+ * parts of a second or location may be shown with 3 or even 4 digits after
+ * the decimal point. Programs that read the data must only use the commas
+ * to determine the field boundaries and not depend on column positions.
+ * There is a provision for a checksum at the end of each sentence which may
+ * or may not be checked by the unit that reads the data. The checksum field
+ * consists of a '*' and two hex digits representing an 8 bit exclusive OR
+ * of all characters between, but not including, the '$' and '*'.
+ */
+ gnssNmeaCb(GnssUtcTime timestamp, string nmea);
+
+ /*
+ * Callback to inform framework of the GNSS engine's capabilities.
+ *
+ * @param capabilities Capability parameter is a bit field of
+ * the Capabilities enum.
+ */
+ gnssSetCapabilitesCb(bitfield<Capabilities> capabilities);
+
+ /*
+ * Callback utility for acquiring the GNSS wakelock. This can be used to prevent
+ * the CPU from suspending while handling GNSS events.
+ */
+ gnssAcquireWakelockCb();
+
+ /** Callback utility for releasing the GNSS wakelock. */
+ gnssReleaseWakelockCb();
+
+ /** Callback for requesting NTP time */
+ gnssRequestTimeCb();
+
+ /*
+ * Provides information about how new the underlying GPS/GNSS hardware and
+ * software is.
+ *
+ * This information will be available for Android Test Applications. If a GNSS
+ * HAL does not provide this information, it will be considered "2015 or
+ * earlier".
+ *
+ * If a GNSS HAL does provide this information, then newer years will need to
+ * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level
+ * GnssMeasurement support will be verified.
+ */
+ struct GnssSystemInfo{
+ /*
+ * year in which the last update was made to the underlying hardware/firmware
+ * used to capture GNSS signals, e.g. 2016
+ */
+ uint16_t yearOfHw;
+ };
+
+ /*
+ * Callback to inform framework of the engine's hardware version information.
+ *
+ * @param info GnssSystemInfo about the GPS/GNSS hardware.
+ */
+ gnssSetSystemInfoCb(GnssSystemInfo info);
+};
diff --git a/gnss/1.0/IGnssConfiguration.hal b/gnss/1.0/IGnssConfiguration.hal
new file mode 100644
index 0000000..2fb6e4e
--- /dev/null
+++ b/gnss/1.0/IGnssConfiguration.hal
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+interface IGnssConfiguration {
+ /*
+ * Enum which holds the bit masks for SUPL_MODE configuration parameter.
+ */
+ enum SuplMode : uint8_t {
+ /* Mobile Station Based */
+ MSB = 0x01,
+
+ /* Mobile Station Assisted */
+ MSA = 0x02
+ };
+
+ /*
+ * Enum which holds the bit masks for GPS_LOCK configuration parameter.
+ */
+ enum GpsLock : uint8_t {
+ /* Lock Mobile Originated GPS functionalitues. */
+ MO = 0x01,
+
+ /* Lock Network initiated GPS functionalities. */
+ NI = 0x02
+ };
+
+ /*
+ * Enum that hold the bit masks for various LTE Positioning Profile settings (LPP_PROFILE
+ * configuration parameter). If none of the bits in the enum are set, the default setting is
+ * Radio Resource Location Protocol(RRLP).
+ */
+ enum LppProfile : uint8_t {
+ /* Enable LTE Positioning Protocol user plane */
+ USER_PLANE = 0x01,
+
+ /* Enable LTE Positioning Protocol Control plane */
+ CONTROL_PLANE = 0x02
+ };
+
+ /*
+ * Enum which holds the bit masks for A_GLONASS_POS_PROTOCOL_SELECT
+ * configuration parameter.
+ */
+ enum GlonassPosProtocol : uint8_t {
+ /* Radio Resource Control(RRC) control-plane. */
+ RRC_CPLANE = 0x01,
+
+ /* Radio Resource Location user-plane. */
+ RRLP_CPLANE = 0x02,
+
+ /* LTE Positioning Protocol User plane */
+ LPP_UPLANE = 0x04
+ };
+
+ /*
+ * IMPORTANT: GNSS HAL must expect the below methods to be called multiple
+ * times. They can be called even when GnssLocationProvider is already
+ * constructed and enabled. GNSS HAL must maintain the existing requests
+ * for various callbacks regardless the change in configuration data.
+ */
+
+ /*
+ * This method enables or disables emergency SUPL.
+ *
+ * @param enabled True if emergency SUPL is to be enabled.
+ *
+ * @return success True if operation was successful.
+ */
+ setSuplEs(bool enabled) generates (bool success);
+
+ /*
+ * This method sets the SUPL version requested by Carrier. The GNSS HAL
+ * must use this version of the SUPL protocol if supported.
+ *
+ * @param version SUPL version requested by carrier. This is a bit mask
+ * with bits 0:7 representing a service indicator field, bits 8:15
+ * representing the minor version and bits 16:23 representing the
+ * major version.
+ *
+ * @return success True if operation was successful.
+ */
+ setSuplVersion(uint32_t version) generates (bool success);
+
+ /*
+ * This method sets the SUPL mode.
+ *
+ * @param mode Bit mask that specifies the SUPL mode which is set with the SuplMode enum.
+ *
+ * @return success True if operation was successful.
+ */
+ setSuplMode(bitfield<SuplMode> mode) generates (bool success);
+
+ /*
+ * This setting configures how GPS functionalities should be locked when
+ * user turns off GPS On setting.
+ *
+ * @param lock Bitmask that specifies the GPS functionalities to be be
+ * locked as per the GpsLock enum.
+ *
+ * @return success True if operation was successful.
+ */
+ setGpsLock(bitfield<GpsLock> lock) generates (bool success);
+
+ /*
+ * This method sets the LTE Positioning Profile configuration.
+ *
+ * @param lppProfile Bitmask that specifies the LTE Positioning Profile
+ * configuration to be set as per the LppProfile enum.
+ *
+ * @return success True if operation was successful.
+ */
+ setLppProfile(bitfield<LppProfile> lppProfile) generates (bool success);
+
+ /*
+ * This method selects positioning protocol on A-Glonass system.
+ *
+ * @param protocol Bitmask that specifies the positioning protocol to be
+ * set as per GlonassPosProtocol enum.
+ *
+ * @return success True if operation was successful.
+ */
+ setGlonassPositioningProtocol(bitfield<GlonassPosProtocol> protocol) generates (bool success);
+
+ /*
+ * This method configures which PDN to use.
+ *
+ * @param enable Use emergency PDN if true and regular PDN if false.
+ * @return success True if operation was successful.
+ */
+ setEmergencySuplPdn(bool enable) generates (bool success);
+};
diff --git a/gnss/1.0/IGnssDebug.hal b/gnss/1.0/IGnssDebug.hal
new file mode 100644
index 0000000..8784d1a
--- /dev/null
+++ b/gnss/1.0/IGnssDebug.hal
@@ -0,0 +1,139 @@
+package android.hardware.gnss@1.0;
+
+/* Extended interface for DEBUG support. */
+interface IGnssDebug {
+ enum SatelliteEphemerisType : uint8_t {
+ /* no information is known to the gnss hardware, about this satellite */
+ UNKNOWN,
+ /* this satellite is known to exist */
+ KNOWN,
+ /* this satellite is not known to exist */
+ NONEXISTENT,
+ /* Only Almanac (approximate) location known for this satellite */
+ ALMANAC_ONLY,
+ /* Ephemeris is known from demodulating the signal on device */
+ DEMODULATED,
+ /* Ephemeris has been provided by SUPL */
+ SUPL_PROVIDED,
+ /* Ephemeris has been provided by another server */
+ OTHER_SERVER_PROVIDED,
+ /*
+ * Predicted ephemeris has been provided by a server
+ * (e.g. Xtra, Extended Ephemeris, etc...)
+ */
+ SERVER_PREDICTED,
+ /*
+ * Predicted ephemeris in use, generated locally on the device (e.g. from prior
+ * ephemeris)
+ */
+ LOCALLY_PREDICTED
+ };
+
+ /*
+ * Provides the current best known position from any
+ * source (GNSS or injected assistance).
+ */
+ struct PositionDebug {
+ /*
+ * Validity of the data in this struct. False only if no
+ * latitude/longitude information is known.
+ */
+ bool valid;
+ /* Latitude expressed in degrees */
+ double latitudeDegrees;
+ /* Longitude expressed in degrees */
+ double longitudeDegrees;
+ /* Altitude above ellipsoid expressed in meters */
+ float altitudeMeters;
+ /* Represents speed in meters per second. */
+ float speedMetersPerSec;
+ /* Represents heading in degrees. */
+ float bearingDegrees;
+ /*
+ * estimated horizontal accuracy of position expressed in meters, radial,
+ * 68% confidence.
+ */
+ double horizontalAccuracyMeters;
+ /*
+ * estimated vertical accuracy of position expressed in meters, with
+ * 68% confidence.
+ */
+ double verticalAccuracyMeters;
+ /*
+ * estimated speed accuracy in meters per second with 68% confidence.
+ */
+ double speedAccuracyMetersPerSecond;
+ /*
+ * estimated bearing accuracy degrees with 68% confidence.
+ */
+ double bearingAccuracyDegrees;
+ /*
+ * Time duration before this report that this position information was
+ * valid.
+ */
+ float ageSeconds;
+ };
+
+ /*
+ * Provides the current best known UTC time estimate.
+ */
+ struct TimeDebug {
+ /*
+ * Validity of the data in the struct.
+ * False if current time is unknown.
+ */
+ bool valid;
+ /*
+ * UTC time estimate.
+ */
+ GnssUtcTime timeEstimate;
+ /* 68% error estimate in time. */
+ float timeUncertaintyNs;
+ };
+
+ /*
+ * Provides a single satellite info that has decoded navigation data.
+ */
+ struct SatelliteData {
+ /* Satellite vehicle ID number */
+ int16_t svid;
+ /* Defines the constellation type of the given SV. */
+ GnssConstellationType constellation;
+ /* Defines the ephemeris type of the satellite. */
+ SatelliteEphemerisType ephemerisType;
+ /*
+ * Time duration before this report, that the ephemeris source was last
+ * updated, e.g. latest demodulation, or latest server download.
+ * Set to 0 when ephemerisType is UNKNOWN.
+ */
+ float ephemerisAgeSeconds;
+ };
+
+ /*
+ * Provides a set of debug information that is filled by the GNSS chipset
+ * when the method getDebugData() is invoked.
+ */
+ struct DebugData {
+ /* Current best known position. */
+ PositionDebug position;
+ /* Current best know time estimate */
+ TimeDebug time;
+ /*
+ * Provides a list of the decoded satellite ephemeris.
+ * Must provide a complete list for all constellations device can track,
+ * including GnssConstellationType UNKNOWN.
+ */
+ vec<SatelliteData> satelliteDataArray;
+
+ };
+
+ /*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return ret debugData information from GNSS Hal that contains the current best
+ * known position, best known time estimate and a complete list of
+ * constellations that the device can track.
+ */
+ getDebugData() generates (DebugData debugData);
+};
diff --git a/gnss/1.0/IGnssGeofenceCallback.hal b/gnss/1.0/IGnssGeofenceCallback.hal
new file mode 100644
index 0000000..722317e
--- /dev/null
+++ b/gnss/1.0/IGnssGeofenceCallback.hal
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/*
+ * GNSS Geofence.
+ * There are 3 states associated with a Geofence: Inside, Outside, Unknown.
+ * There are 3 transitions: ENTERED, EXITED, UNCERTAIN.
+ *
+ * An example state diagram with confidence level: 95% and Unknown time limit
+ * set as 30 secs is shown below. (confidence level and Unknown time limit are
+ * explained latter).
+ * ____________________________
+ * | Unknown (30 secs) |
+ * """"""""""""""""""""""""""""
+ * ^ | | ^
+ * UNCERTAIN| |ENTERED EXITED| |UNCERTAIN
+ * | v v |
+ * ________ EXITED _________
+ * | Inside | -----------> | Outside |
+ * | | <----------- | |
+ * """""""" ENTERED """""""""
+ *
+ * Inside state: We are 95% confident that the user is inside the geofence.
+ * Outside state: We are 95% confident that the user is outside the geofence
+ * Unknown state: Rest of the time.
+ *
+ * The Unknown state is better explained with an example:
+ *
+ * __________
+ * | c|
+ * | ___ | _______
+ * | |a| | | b |
+ * | """ | """""""
+ * | |
+ * """"""""""
+ * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy
+ * circle reported by the GNSS subsystem. Now with regard to "b", the system is
+ * confident that the user is outside. But with regard to "a" is not confident
+ * whether it is inside or outside the geofence. If the accuracy remains the
+ * same for a sufficient period of time, the UNCERTAIN transition must be
+ * triggered with the state set to Unknown. If the accuracy improves later, an
+ * appropriate transition must be triggered. This "sufficient period of time"
+ * is defined by the parameter in the addGeofenceArea API.
+ * In other words, Unknown state can be interpreted as a state in which the
+ * GNSS subsystem isn't confident enough that the user is either inside or
+ * outside the Geofence. It moves to Unknown state only after the expiry of the
+ * timeout.
+ *
+ * The geofence callback needs to be triggered for the ENTERED and EXITED
+ * transitions, when the GNSS system is confident that the user has entered
+ * (Inside state) or exited (Outside state) the Geofence. An implementation
+ * which uses a value of 95% as the confidence is recommended. The callback
+ * must be triggered only for the transitions requested by the
+ * addGeofenceArea method.
+ *
+ * Even though the diagram and explanation talks about states and transitions,
+ * the callee is only interested in the transitions. The states are mentioned
+ * here for illustrative purposes.
+ *
+ * Startup Scenario: When the device boots up, if an application adds geofences,
+ * and then we get an accurate GNSS location fix, it needs to trigger the
+ * appropriate (ENTERED or EXITED) transition for every Geofence it knows about.
+ * By default, all the Geofences will be in the Unknown state.
+ *
+ * When the GNSS system is unavailable, gnssGeofenceStatusCb must be
+ * called to inform the upper layers of the same. Similarly, when it becomes
+ * available the callback must be called. This is a global state while the
+ * UNKNOWN transition described above is per geofence.
+ *
+ * An important aspect to note is that users of this API (framework), will use
+ * other subsystems like wifi, sensors, cell to handle Unknown case and
+ * hopefully provide a definitive state transition to the third party
+ * application. GNSS Geofence will just be a signal indicating what the GNSS
+ * subsystem knows about the Geofence.
+ *
+ */
+
+interface IGnssGeofenceCallback {
+ @export(name="", value_prefix="GPS_GEOFENCE_")
+ enum GeofenceTransition : int32_t {
+ ENTERED = (1 << 0L),
+ EXITED = (1 << 1L),
+ UNCERTAIN = (1 << 2L),
+ };
+
+ @export(name="", value_prefix="GPS_GEOFENCE_")
+ enum GeofenceAvailability : int32_t {
+ UNAVAILABLE = (1 << 0L),
+ AVAILABLE = (1 << 1L),
+ };
+
+ @export(name="", value_prefix="GPS_GEOFENCE_")
+ enum GeofenceStatus : int32_t {
+ OPERATION_SUCCESS = 0,
+ ERROR_TOO_MANY_GEOFENCES = -100,
+ ERROR_ID_EXISTS = -101,
+ ERROR_ID_UNKNOWN = -102,
+ ERROR_INVALID_TRANSITION = -103,
+ ERROR_GENERIC = -149
+ };
+
+ /*
+ * The callback associated with the geofence transition.
+ * The callback must only be called when the caller is interested in that
+ * particular transition. For instance, if the caller is interested only in
+ * ENTERED transition, then the callback must not be called with the EXITED
+ * transition.
+ *
+ * IMPORTANT: If a transition is triggered resulting in this callback, the
+ * GNSS subsystem will wake up the application processor, if its in suspend
+ * state.
+ *
+ * @param geofenceId The id associated with the addGeofenceArea.
+ * @param location The current GNSS location.
+ * @param transition Can be one of ENTERED, EXITED or UNCERTAIN.
+ * @param timestamp Timestamp when the transition was detected.
+ *
+ */
+ gnssGeofenceTransitionCb(int32_t geofenceId, GnssLocation location,
+ GeofenceTransition transition, GnssUtcTime timestamp);
+
+ /*
+ * The callback associated with the availability of the GNSS system for
+ * geofencing monitoring. If the GNSS system determines that it cannot monitor
+ * geofences because of lack of reliability or unavailability of the GNSS
+ * signals, it will call this callback with UNAVAILABLE parameter.
+ *
+ * @param status - UNAVAILABLE or AVAILABLE.
+ * @param lastLocation - Last known location.
+ */
+ gnssGeofenceStatusCb(GeofenceAvailability status, GnssLocation lastLocation);
+
+ /*
+ * The callback associated with the addGeofence call.
+ *
+ * @param geofenceId Id of the geofence.
+ * @param status Will be OPERATION_SUCCESS if the geofence
+ * add was successful. Will be ERROR_TOO_MANY_GEOFENCES if the
+ * geofence limit has been reached.
+ * Will be ERROR_ID_EXISTS if geofence with id already exists.
+ * Will be ERROR_INVALID_TRANSITION if the monitorTransition contains an
+ * invalid transition.
+ * Will be ERROR_GENERIC for other errors.
+ */
+ gnssGeofenceAddCb(int32_t geofenceId, GeofenceStatus status);
+
+ /*
+ * The callback associated with the removeGeofence call.
+ *
+ * @param geofenceId Id of the geofence.
+ * @param status Will return OPERATION_SUCCESS if successful.
+ * Will be ERROR_ID_UNKNOWN for invalid id and
+ * ERROR_GENERIC for others.
+ */
+ gnssGeofenceRemoveCb(int32_t geofenceId, GeofenceStatus status);
+
+ /*
+ * The callback associated with the pauseGeofence call.
+ *
+ * @param geofenceId Id of the geofence.
+ * @param status Will be OPERATION_SUCCESS if success.
+ * Will be ERROR_ID_UNKNOWN for invalid id. Will be
+ * ERROR_INVALID_TRANSITION when monitorTransitions is invalid.
+ * Will be ERROR_GENERIC for other err errors.
+ */
+ gnssGeofencePauseCb(int32_t geofenceId, GeofenceStatus status);
+
+ /*
+ * The callback associated with the resumeGeofence call.
+ *
+ * @param geofenceId - Id of the geofence.
+ * @param status Will be OPERATION_SUCCESS if successful.
+ * Will be ERROR_ID_UNKNOWN for invalid id and ERROR_GENERIC for others.
+ */
+ gnssGeofenceResumeCb(int32_t geofenceId, GeofenceStatus status);
+};
diff --git a/gnss/1.0/IGnssGeofencing.hal b/gnss/1.0/IGnssGeofencing.hal
new file mode 100644
index 0000000..b8348b3
--- /dev/null
+++ b/gnss/1.0/IGnssGeofencing.hal
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IGnssGeofenceCallback;
+
+/* Extended interface for GNSS Geofencing support */
+interface IGnssGeofencing {
+ /*
+ * Opens the geofence interface and provides the callback routines
+ * to the HAL.
+ *
+ * @param callback Handle to the IGnssGeofenceCallback interface.
+ */
+ setCallback(IGnssGeofenceCallback callback);
+
+ /*
+ * Add a geofence area. This api currently supports circular geofences.
+ *
+ * @param geofenceId The id for the geofence. If a geofence with this id
+ * already exists, an error value (ERROR_ID_EXISTS) must be returned.
+ * @param latitudeDegrees The latitude(in degrees) for the geofence lastTransition.
+ * @param longtitudeDegrees The longitude(in degrees) for the geofence lastTransition.
+ * @param radiusMeters The radius(in meters) for the geofence lastTransition.
+ * @param lastTransition The current state of the geofence. For example, if
+ * the system already knows that the user is inside the geofence, this will
+ * be set to ENTERED. In most cases, it will be UNCERTAIN.
+ * @param monitorTransitions - Which transitions to monitor. Bitwise OR of
+ * ENTERED, EXITED and UNCERTAIN.
+ * @param notificationResponsivenessMs - Defines the best-effort description
+ * of how soon must the callback be called when the transition associated
+ * with the Geofence is triggered. For instance, if set to 1000 millseconds
+ * with ENTERED, the callback must be called 1000 milliseconds within entering
+ * the geofence. This parameter is defined in milliseconds.
+ * NOTE: This is not to be confused with the rate that the GNSS is polled at.
+ * It is acceptable to dynamically vary the rate of sampling the GNSS for
+ * power-saving reasons; thus the rate of sampling may be faster or slower
+ * than this.
+ * @param unknownTimerMs - The time limit after which the UNCERTAIN transition
+ * must be triggered. This parameter is defined in milliseconds.
+ */
+ addGeofence(int32_t geofenceId, double latitudeDegrees, double longitudeDegrees,
+ double radiusMeters, GeofenceTransition lastTransition,
+ bitfield<IGnssGeofenceCallback.GeofenceTransition> monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs);
+
+ /*
+ * Pause monitoring a particular geofence.
+ *
+ * @param geofenceId The id for the geofence.
+ */
+ pauseGeofence(int32_t geofenceId);
+
+ /*
+ * Resume monitoring a particular geofence.
+ *
+ * @param geofenceId - The id for the geofence.
+ * @param monitorTransitions Specifies which transitions to monitor.
+ * It can be a bitwise OR of ENTERED, EXITED and
+ * UNCERTAIN. This supersedes the value associated
+ * provided in the addGeofenceArea call.
+ */
+ resumeGeofence(int32_t geofenceId,
+ bitfield<IGnssGeofenceCallback.GeofenceTransition> monitorTransitions);
+
+ /*
+ * Remove a geofence area. After the function returns, no notifications
+ * must be sent.
+ *
+ * @param geofenceId The id of the geofence.
+ */
+ removeGeofence(int32_t geofenceId);
+};
diff --git a/gnss/1.0/IGnssMeasurement.hal b/gnss/1.0/IGnssMeasurement.hal
new file mode 100644
index 0000000..8329442
--- /dev/null
+++ b/gnss/1.0/IGnssMeasurement.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IGnssMeasurementCallback;
+
+/*
+ * Extended interface for GNSS Measurements support.
+ */
+interface IGnssMeasurement {
+ @export(name="", value_prefix="GPS_MEASUREMENT_")
+ enum GnssMeasurementStatus : int32_t {
+ SUCCESS = 0,
+ ERROR_ALREADY_INIT = -100,
+ ERROR_GENERIC = -101
+ };
+
+ /*
+ * Initializes the interface and registers the callback routines with the HAL.
+ * After a successful call to 'setCallback' the HAL must begin to provide updates at
+ * an average output rate of 1Hz (occasional
+ * intra-measurement time offsets in the range from 0-2000msec can be
+ * tolerated.)
+ *
+ * @param callback Handle to GnssMeasurement callback interface.
+ *
+ * @return initRet Returns SUCCESS if successful.
+ * Returns ERROR_ALREADY_INIT if a callback has already been
+ * registered without a corresponding call to 'close'.
+ * Returns ERROR_GENERIC for any other error. The HAL must
+ * not generate any other updates upon returning this error code.
+ */
+ setCallback(IGnssMeasurementCallback callback) generates (GnssMeasurementStatus initRet);
+
+ /*
+ * Stops updates from the HAL, and unregisters the callback routines.
+ * After a call to close(), the previously registered callbacks must be
+ * considered invalid by the HAL.
+ * If close() is invoked without a previous setCallback, this function must perform
+ * no work.
+ */
+ close();
+
+};
diff --git a/gnss/1.0/IGnssMeasurementCallback.hal b/gnss/1.0/IGnssMeasurementCallback.hal
new file mode 100644
index 0000000..5789621
--- /dev/null
+++ b/gnss/1.0/IGnssMeasurementCallback.hal
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/* The callback interface to report measurements from the HAL. */
+interface IGnssMeasurementCallback {
+ /*
+ * Flags to indicate what fields in GnssClock are valid.
+ */
+ @export(name="", value_prefix="GNSS_CLOCK_")
+ enum GnssClockFlags : uint16_t {
+ /** A valid 'leap second' is stored in the data structure. */
+ HAS_LEAP_SECOND = 1 << 0,
+ /** A valid 'time uncertainty' is stored in the data structure. */
+ HAS_TIME_UNCERTAINTY = 1 << 1,
+ /** A valid 'full bias' is stored in the data structure. */
+ HAS_FULL_BIAS = 1 << 2,
+ /** A valid 'bias' is stored in the data structure. */
+ HAS_BIAS = 1 << 3,
+ /** A valid 'bias uncertainty' is stored in the data structure. */
+ HAS_BIAS_UNCERTAINTY = 1 << 4,
+ /** A valid 'drift' is stored in the data structure. */
+ HAS_DRIFT = 1 << 5,
+ /** A valid 'drift uncertainty' is stored in the data structure. */
+ HAS_DRIFT_UNCERTAINTY = 1 << 6
+ };
+
+ /*
+ * Flags to indicate what fields in GnssMeasurement are valid.
+ */
+ @export(name="", value_prefix="GNSS_MEASUREMENT_")
+ enum GnssMeasurementFlags : uint32_t {
+ /** A valid 'snr' is stored in the data structure. */
+ HAS_SNR = 1 << 0,
+ /** A valid 'carrier frequency' is stored in the data structure. */
+ HAS_CARRIER_FREQUENCY = 1 << 9,
+ /** A valid 'carrier cycles' is stored in the data structure. */
+ HAS_CARRIER_CYCLES = 1 << 10,
+ /** A valid 'carrier phase' is stored in the data structure. */
+ HAS_CARRIER_PHASE = 1 << 11,
+ /** A valid 'carrier phase uncertainty' is stored in the data structure. */
+ HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12,
+ /** A valid automatic gain control is stored in the data structure. */
+ HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13
+ };
+
+ /*
+ * Enumeration of available values for the GNSS Measurement's multipath
+ * indicator.
+ */
+ @export(name="", value_prefix="GNSS_MULTIPATH_")
+ enum GnssMultipathIndicator : uint8_t {
+ /** The indicator is not available or unknown. */
+ INDICATOR_UNKNOWN = 0,
+ /** The measurement is indicated to be affected by multipath. */
+ INDICATOR_PRESENT = 1,
+ /** The measurement is indicated to be not affected by multipath. */
+ INDICATIOR_NOT_PRESENT = 2
+ };
+
+ /*
+ * Flags indicating the GNSS measurement state.
+ *
+ * The expected behavior here is for GNSS HAL to set all the flags that applies.
+ * For example, if the state for a satellite is only C/A code locked and bit
+ * synchronized, and there is still millisecond ambiguity, the state must be
+ * set as:
+ *
+ * STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_MSEC_AMBIGUOUS
+ *
+ * If GNSS is still searching for a satellite, the corresponding state must be
+ * set to STATE_UNKNOWN(0).
+ */
+ @export(name="", value_prefix="GNSS_MEASUREMENT_")
+ enum GnssMeasurementState : uint32_t {
+ STATE_UNKNOWN = 0,
+ STATE_CODE_LOCK = 1 << 0,
+ STATE_BIT_SYNC = 1 << 1,
+ STATE_SUBFRAME_SYNC = 1 << 2,
+ STATE_TOW_DECODED = 1 << 3,
+ STATE_MSEC_AMBIGUOUS = 1 << 4,
+ STATE_SYMBOL_SYNC = 1 << 5,
+ STATE_GLO_STRING_SYNC = 1 << 6,
+ STATE_GLO_TOD_DECODED = 1 << 7,
+ STATE_BDS_D2_BIT_SYNC = 1 << 8,
+ STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9,
+ STATE_GAL_E1BC_CODE_LOCK = 1 << 10,
+ STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11,
+ STATE_GAL_E1B_PAGE_SYNC = 1 << 12,
+ STATE_SBAS_SYNC = 1 << 13,
+ STATE_TOW_KNOWN = 1 << 14,
+ STATE_GLO_TOD_KNOWN = 1 << 15,
+ };
+
+ /*
+ * Flags indicating the Accumulated Delta Range's states.
+ */
+ @export(name="", value_prefix="GNSS_")
+ enum GnssAccumulatedDeltaRangeState : uint16_t {
+ ADR_STATE_UNKNOWN = 0,
+ ADR_STATE_VALID = 1 << 0,
+ ADR_STATE_RESET = 1 << 1,
+ ADR_STATE_CYCLE_SLIP = 1 << 2,
+ };
+
+ /*
+ * Represents an estimate of the GNSS clock time.
+ */
+ struct GnssClock {
+ /*
+ * A set of flags indicating the validity of the fields in this data
+ * structure.
+ */
+ bitfield<GnssClockFlags> gnssClockFlags;
+
+ /*
+ * Leap second data.
+ * The sign of the value is defined by the following equation:
+ * utcTimeNs = timeNs - (fullBiasNs + biasNs) - leapSecond *
+ * 1,000,000,000
+ *
+ * If this data is available, gnssClockFlags must contain
+ * HAS_LEAP_SECOND.
+ */
+ int16_t leapSecond;
+
+ /*
+ * The GNSS receiver internal clock value. This is the local hardware clock
+ * value.
+ *
+ * For local hardware clock, this value is expected to be monotonically
+ * increasing while the hardware clock remains powered on. (For the case of a
+ * HW clock that is not continuously on, see the
+ * hwClockDiscontinuityCount field). The receiver's estimate of GNSS time
+ * can be derived by subtracting the sum of fullBiasNs and biasNs (when
+ * available) from this value.
+ *
+ * This GNSS time must be the best estimate of current GNSS time
+ * that GNSS receiver can achieve.
+ *
+ * Sub-nanosecond accuracy can be provided by means of the 'biasNs' field.
+ * The value contains the timeUncertaintyNs in it.
+ *
+ * This field is mandatory.
+ */
+ int64_t timeNs;
+
+ /*
+ * 1-Sigma uncertainty associated with the clock's time in nanoseconds.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_TIME_UNCERTAINTY. Ths value is ideally zero, as the time
+ * 'latched' by timeNs is defined as the reference clock vs. which all
+ * other times (and corresponding uncertainties) are measured.
+ */
+ double timeUncertaintyNs;
+
+ /*
+ * The difference between hardware clock ('time' field) inside GNSS receiver
+ * and the true GNSS time since 0000Z, January 6, 1980, in nanoseconds.
+ *
+ * The sign of the value is defined by the following equation:
+ * local estimate of GNSS time = timeNs - (fullBiasNs + biasNs)
+ *
+ * This value is mandatory if the receiver has estimated GNSS time. If the
+ * computed time is for a non-GNSS constellation, the time offset of that
+ * constellation to GNSS has to be applied to fill this value. The error
+ * estimate for the sum of this and the biasNs is the biasUncertaintyNs,
+ * and the caller is responsible for using this uncertainty (it can be very
+ * large before the GNSS time has been solved for.) If the data is available
+ * gnssClockFlags must contain HAS_FULL_BIAS.
+ */
+ int64_t fullBiasNs;
+
+ /*
+ * Sub-nanosecond bias.
+ * The error estimate for the sum of this and the fullBiasNs is the
+ * biasUncertaintyNs.
+ *
+ * If the data is available gnssClockFlags must contain HAS_BIAS. If GNSS
+ * has computed a position fix. This value is mandatory if the receiver has
+ * estimated GNSS time.
+ */
+ double biasNs;
+
+ /*
+ * 1-Sigma uncertainty associated with the local estimate of GNSS time (clock
+ * bias) in nanoseconds. The uncertainty is represented as an absolute
+ * (single sided) value.
+ *
+ * If the data is available gnssClockFlags must contain
+ * HAS_BIAS_UNCERTAINTY. This value is mandatory if the receiver
+ * has estimated GNSS time.
+ */
+ double biasUncertaintyNs;
+
+ /*
+ * The clock's drift in nanoseconds (per second).
+ *
+ * A positive value means that the frequency is higher than the nominal
+ * frequency, and that the (fullBiasNs + biasNs) is growing more positive
+ * over time.
+ *
+ * The value contains the 'drift uncertainty' in it.
+ * If the data is available gnssClockFlags must contain HAS_DRIFT.
+ *
+ * This value is mandatory if the receiver has estimated GNSS time.
+ */
+ double driftNsps;
+
+ /*
+ * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per
+ * second).
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available gnssClockFlags must contain
+ * HAS_DRIFT_UNCERTAINTY. If GNSS has computed a position fix this
+ * field is mandatory and must be populated.
+ */
+ double driftUncertaintyNsps;
+
+ /*
+ * When there are any discontinuities in the HW clock, this field is
+ * mandatory.
+ *
+ * A "discontinuity" is meant to cover the case of a switch from one source
+ * of clock to another. A single free-running crystal oscillator (XO)
+ * will generally not have any discontinuities, and this can be set and
+ * left at 0.
+ *
+ * If, however, the timeNs value (HW clock) is derived from a composite of
+ * sources, that is not as smooth as a typical XO, or is otherwise stopped &
+ * restarted, then this value shall be incremented each time a discontinuity
+ * occurs. (E.g. this value can start at zero at device boot-up and
+ * increment each time there is a change in clock continuity. In the
+ * unlikely event that this value reaches full scale, rollover (not
+ * clamping) is required, such that this value continues to change, during
+ * subsequent discontinuity events.)
+ *
+ * While this number stays the same, between GnssClock reports, it can be
+ * safely assumed that the timeNs value has been running continuously, e.g.
+ * derived from a single, high quality clock (XO like, or better, that is
+ * typically used during continuous GNSS signal sampling.)
+ *
+ * It is expected, esp. during periods where there are few GNSS signals
+ * available, that the HW clock be discontinuity-free as long as possible,
+ * as this avoids the need to use (waste) a GNSS measurement to fully
+ * re-solve for the GNSS clock bias and drift, when using the accompanying
+ * measurements, from consecutive GnssData reports.
+ */
+ uint32_t hwClockDiscontinuityCount;
+
+ };
+
+ /*
+ * Represents a GNSS Measurement, it contains raw and computed information.
+ *
+ * All signal measurement information (e.g. svTime,
+ * pseudorangeRate, multipathIndicator) reported in this struct must be
+ * based on GNSS signal measurements only. You must not synthesize measurements
+ * by calculating or reporting expected measurements based on known or estimated
+ * position, velocity, or time.
+ */
+ struct GnssMeasurement{
+ /*
+ * A set of flags indicating the validity of the fields in this data
+ * structure.
+ */
+ bitfield<GnssMeasurementFlags> flags;
+
+ /*
+ * Satellite vehicle ID number, as defined in GnssSvInfo::svid
+ * This is a mandatory value.
+ */
+ int16_t svid;
+
+ /*
+ * Defines the constellation of the given SV.
+ */
+ GnssConstellationType constellation;
+
+ /*
+ * Time offset at which the measurement was taken in nanoseconds.
+ * The reference receiver's time is specified by GnssData::clock::timeNs.
+ *
+ * The sign of timeOffsetNs is given by the following equation:
+ * measurement time = GnssClock::timeNs + timeOffsetNs
+ *
+ * It provides an individual time-stamp for the measurement, and allows
+ * sub-nanosecond accuracy.
+ * This is a mandatory value.
+ */
+ double timeOffsetNs;
+
+ /*
+ * Per satellite sync state. It represents the current sync state for the
+ * associated satellite.
+ * Based on the sync state, the 'received GNSS tow' field must be interpreted
+ * accordingly.
+ *
+ * This is a mandatory value.
+ */
+ bitfield<GnssMeasurementState> state;
+
+ /*
+ * The received GNSS Time-of-Week at the measurement time, in nanoseconds.
+ * For GNSS & QZSS, this is the received GNSS Time-of-Week at the
+ * measurement time, in nanoseconds. The value is relative to the
+ * beginning of the current GNSS week.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set
+ * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC set
+ * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED set
+ * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * Note: If there is any ambiguity in integer millisecond,
+ * GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS must be set accordingly, in the
+ * 'state' field.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ *
+ * For Glonass, this is the received Glonass time of day, at the
+ * measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN set
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set
+ * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set
+ * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC set
+ * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED set
+ * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set
+ *
+ * Note: Time of day known refers to the case where it is possibly not
+ * decoded over the air but has been determined from other sources. If
+ * Time of day decoded is set then Time of day known must also be set.
+ *
+ * For Beidou, this is the received Beidou time of week,
+ * at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN set.
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set.
+ * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC set.
+ * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC set.
+ * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC set.
+ * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC set.
+ * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED set.
+ * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * For Galileo, this is the received Galileo time of week,
+ * at the measurement time in nanoseconds.
+ *
+ * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK set.
+ * E1C 2nd code lock : [ 0 100ms] : STATE_GAL_E1C_2ND_CODE_LOCK set.
+ * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC set.
+ * Time of week decoded : [ 0 1week] : STATE_TOW_DECODED is set.
+ * Time of week known : [ 0 1week] : STATE_TOW_KNOWN set
+ *
+ * Note: TOW Known refers to the case where TOW is possibly not decoded
+ * over the air but has been determined from other sources. If TOW
+ * decoded is set then TOW Known must also be set.
+ *
+ * For SBAS, this is received SBAS time, at the measurement time in
+ * nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock: [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
+ * Message : [ 0 1s ] : STATE_SBAS_SYNC is set
+ */
+ int64_t receivedSvTimeInNs;
+
+ /*
+ * 1-Sigma uncertainty of the Received GNSS Time-of-Week in nanoseconds.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ */
+ int64_t receivedSvTimeUncertaintyInNs;
+
+ /*
+ * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+ * It contains the measured C/N0 value for the signal at the antenna port.
+ *
+ * This is a mandatory value.
+ */
+ double cN0DbHz;
+
+ /*
+ * Pseudorange rate at the timestamp in m/s. The correction of a given
+ * Pseudorange Rate value includes corrections for receiver and satellite
+ * clock frequency errors. Ensure that this field is independent (see
+ * comment at top of GnssMeasurement struct.)
+ *
+ * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and
+ * provide GnssClock's 'drift' field as well. When providing the
+ * uncorrected pseudorange rate, do not apply the corrections described above.)
+ *
+ * The value includes the 'pseudorange rate uncertainty' in it.
+ * A positive 'uncorrected' value indicates that the SV is moving away from
+ * the receiver.
+ *
+ * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the
+ * sign of 'doppler shift' is given by the equation:
+ * pseudorange rate = -k * doppler shift (where k is a constant)
+ *
+ * This must be the most accurate pseudorange rate available, based on
+ * fresh signal measurements from this channel.
+ *
+ * It is mandatory that this value be provided at typical carrier phase PRR
+ * quality (few cm/sec per second of uncertainty, or better) - when signals
+ * are sufficiently strong & stable, e.g. signals from a GNSS simulator at >=
+ * 35 dB-Hz.
+ */
+ double pseudorangeRateMps;
+
+ /*
+ * 1-Sigma uncertainty of the pseudorangeRateMps.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * This is a mandatory value.
+ */
+ double pseudorangeRateUncertaintyMps;
+
+ /*
+ * Accumulated delta range's state. It indicates whether ADR is reset or
+ * there is a cycle slip(indicating loss of lock).
+ *
+ * This is a mandatory value.
+ */
+ bitfield<GnssAccumulatedDeltaRangeState> accumulatedDeltaRangeState;
+
+ /*
+ * Accumulated delta range since the last channel reset in meters.
+ * A positive value indicates that the SV is moving away from the receiver.
+ *
+ * The sign of the 'accumulated delta range' and its relation to the sign of
+ * 'carrier phase' is given by the equation:
+ * accumulated delta range = -k * carrier phase (where k is a constant)
+ *
+ * This value must be populated if 'accumulated delta range state' !=
+ * ADR_STATE_UNKNOWN.
+ * However, it is expected that the data is only accurate when:
+ * 'accumulated delta range state' == ADR_STATE_VALID.
+ */
+ double accumulatedDeltaRangeM;
+
+ /*
+ * 1-Sigma uncertainty of the accumulated delta range in meters.
+ * This value must be populated if 'accumulated delta range state' !=
+ * ADR_STATE_UNKNOWN.
+ */
+ double accumulatedDeltaRangeUncertaintyM;
+
+ /*
+ * Carrier frequency of the signal tracked, for example it can be the
+ * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 =
+ * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it
+ * is the primary common use central frequency, e.g. L1 = 1575.45 MHz
+ * for GPS.
+ *
+ * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same
+ * time, two raw measurement structs must be reported for this same
+ * satellite, in one of the measurement structs, all the values related
+ * to L1 must be filled, and in the other all of the values related to
+ * L5 must be filled.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_CARRIER_FREQUENCY.
+ */
+ float carrierFrequencyHz;
+
+ /*
+ * The number of full carrier cycles between the satellite and the
+ * receiver. The reference frequency is given by the field
+ * 'carrierFrequencyHz'. Indications of possible cycle slips and
+ * resets in the accumulation of this value can be inferred from the
+ * accumulatedDeltaRangeState flags.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_CARRIER_CYCLES.
+ */
+ int64_t carrierCycles;
+
+ /*
+ * The RF phase detected by the receiver, in the range [0.0, 1.0].
+ * This is usually the fractional part of the complete carrier phase
+ * measurement.
+ *
+ * The reference frequency is given by the field 'carrierFrequencyHz'.
+ * The value contains the 'carrier-phase uncertainty' in it.
+ *
+ * If the data is available, gnssClockFlags must contain
+ * HAS_CARRIER_PHASE.
+ */
+ double carrierPhase;
+
+ /*
+ * 1-Sigma uncertainty of the carrier-phase.
+ * If the data is available, gnssClockFlags must contain
+ * HAS_CARRIER_PHASE_UNCERTAINTY.
+ */
+ double carrierPhaseUncertainty;
+
+ /*
+ * An enumeration that indicates the 'multipath' state of the event.
+ *
+ * The multipath Indicator is intended to report the presence of overlapping
+ * signals that manifest as distorted correlation peaks.
+ *
+ * - if there is a distorted correlation peak shape, report that multipath
+ * is MULTIPATH_INDICATOR_PRESENT.
+ * - if there is no distorted correlation peak shape, report
+ * MULTIPATH_INDICATOR_NOT_PRESENT
+ * - if signals are too weak to discern this information, report
+ * MULTIPATH_INDICATOR_UNKNOWN
+ *
+ * Example: when doing the standardized overlapping Multipath Performance
+ * test (3GPP TS 34.171) the Multipath indicator must report
+ * MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and
+ * contain multipath, and MULTIPATH_INDICATOR_NOT_PRESENT for those
+ * signals that are tracked and do not contain multipath.
+ */
+ GnssMultipathIndicator multipathIndicator;
+
+ /*
+ * Signal-to-noise ratio at correlator output in dB.
+ * If the data is available, gnssClockFlags must contain MEASUREMENT_HAS_SNR.
+ * This is the power ratio of the "correlation peak height above the
+ * observed noise floor" to "the noise RMS".
+ */
+ double snrDb;
+
+ /*
+ * Automatic gain control (AGC) level. AGC acts as a variable gain
+ * amplifier adjusting the power of the incoming signal. The AGC level
+ * may be used to indicate potential interference. When AGC is at a
+ * nominal level, this value must be set as 0. Higher gain (and/or lower
+ * input power) must be output as a positive number. Hence in cases of
+ * strong jamming, in the band of this signal, this value must go more
+ * negative.
+ *
+ * Note: Different hardware designs (e.g. antenna, pre-amplification, or
+ * other RF HW components) may also affect the typical output of of this
+ * value on any given hardware design in an open sky test - the
+ * important aspect of this output is that changes in this value are
+ * indicative of changes on input signal power in the frequency band for
+ * this measurement.
+ */
+ double agcLevelDb;
+ };
+
+ /*
+ * Represents a reading of GNSS measurements. For devices where GnssSystemInfo's
+ * yearOfHw is set to 2016+, it is mandatory that these be provided, on
+ * request, when the GNSS receiver is searching/tracking signals.
+ *
+ * - Reporting of GNSS constellation measurements is mandatory.
+ * - Reporting of all tracked constellations are encouraged.
+ */
+ struct GnssData {
+ /* Number of GnssMeasurement elements. */
+ uint32_t measurementCount;
+
+ /* The array of measurements. */
+ GnssMeasurement[GnssMax:SVS_COUNT] measurements;
+
+ /** The GNSS clock time reading. */
+ GnssClock clock;
+ };
+
+ /*
+ * Callback for the hal to pass a GnssData structure back to the client.
+ *
+ * @param data Contains a reading of GNSS measurements.
+ */
+ GnssMeasurementCb(GnssData data);
+};
diff --git a/gnss/1.0/IGnssNavigationMessage.hal b/gnss/1.0/IGnssNavigationMessage.hal
new file mode 100644
index 0000000..ddd9169
--- /dev/null
+++ b/gnss/1.0/IGnssNavigationMessage.hal
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+import IGnssNavigationMessageCallback;
+
+/*
+ * Extended interface for GNSS navigation message reporting support.
+ */
+interface IGnssNavigationMessage {
+ @export(name="", value_prefix="GPS_NAVIGATION_MESSAGE_")
+ enum GnssNavigationMessageStatus : int32_t {
+ SUCCESS = 0,
+ ERROR_ALREADY_INIT = -100,
+ ERROR_GENERIC = -101
+ };
+
+ /*
+ * Initializes the interface and registers the callback routines with the HAL.
+ * After a successful call to 'setCallback' the HAL must begin to provide updates as
+ * they become available.
+ * @param callback handle to IGnssNavigationMessageCallack interface.
+ *
+ * @return initRet Returns SUCCESS if the operation
+ * is successful.
+ * Returns ERROR_ALREADY_INIT if a callback has
+ * already been registered without a corresponding call to close().
+ * Returns ERROR_GENERIC if any other error occurred. It is
+ * expected that the HAL will not generate any updates upon returning
+ * this error code.
+ */
+ setCallback(IGnssNavigationMessageCallback callback) generates (GnssNavigationMessageStatus initRet);
+
+ /*
+ * Stops updates from the HAL, and unregisters the callback routines.
+ * After a call to close(), the previously registered callbacks must be
+ * considered invalid by the HAL.
+ * If close() is invoked without a previous setCallback, this function must perform
+ * no work.
+ */
+ close();
+};
diff --git a/gnss/1.0/IGnssNavigationMessageCallback.hal b/gnss/1.0/IGnssNavigationMessageCallback.hal
new file mode 100644
index 0000000..2e6b853
--- /dev/null
+++ b/gnss/1.0/IGnssNavigationMessageCallback.hal
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/** Represents a GNSS navigation message (or a fragment of it). */
+interface IGnssNavigationMessageCallback {
+ /*
+ * Enumeration of available values to indicate the GNSS Navigation message
+ * types.
+ *
+ * For convenience, first byte is the GnssConstellationType on which that signal
+ * is typically transmitted.
+ */
+ @export(name="", value_prefix="GNSS_NAVIGATION_MESSAGE_TYPE_")
+ enum GnssNavigationMessageType : int16_t {
+ UNKNOWN = 0,
+ /** GNSS L1 C/A message contained in the structure. */
+ GNSS_L1CA = 0x0101,
+ /** GNSS L2-CNAV message contained in the structure. */
+ GNSS_L2CNAV = 0x0102,
+ /** GNSS L5-CNAV message contained in the structure. */
+ GNSS_L5CNAV = 0x0103,
+ /** GNSS CNAV-2 message contained in the structure. */
+ GNSS_CNAV2 = 0x0104,
+ /** Glonass L1 CA message contained in the structure. */
+ GLO_L1CA = 0x0301,
+ /** Beidou D1 message contained in the structure. */
+ BDS_D1 = 0x0501,
+ /** Beidou D2 message contained in the structure. */
+ BDS_D2 = 0x0502,
+ /** Galileo I/NAV message contained in the structure. */
+ GAL_I = 0x0601,
+ /** Galileo F/NAV message contained in the structure. */
+ GAL_F = 0x0602
+ };
+
+ /*
+ * Status of Navigation Message
+ * When a message is received properly without any parity error in its
+ * navigation words, the status must be set to PARITY_PASSED. But if a message is
+ * received with words that failed parity check, but GNSS is able to correct
+ * those words, the status must be set to PARITY_REBUILT.
+ * No need to send any navigation message that contains words with parity error
+ * and cannot be corrected.
+ */
+ @export(name="navigation_message_status", value_prefix="NAV_MESSAGE_STATUS_")
+ enum NavigationMessageStatus : uint16_t {
+ PARITY_PASSED = (1 << 0),
+ PARITY_REBUILT = (1 << 1),
+ UNKNOWN = 0
+ };
+
+ struct GnssNavigationMessage {
+ /*
+ * Satellite vehicle ID number, as defined in GnssSvInfo::svid
+ * This is a mandatory value.
+ */
+ int16_t svid;
+
+ /*
+ * The type of message contained in the structure.
+ * This is a mandatory value.
+ */
+ GnssNavigationMessageType type;
+
+ /*
+ * The status of the received navigation message.
+ * No need to send any navigation message that contains words with parity
+ * error and cannot be corrected.
+ */
+ bitfield<NavigationMessageStatus> status;
+
+ /*
+ * Message identifier. It provides an index so the complete Navigation
+ * Message can be assembled.
+ *
+ * - For GNSS L1 C/A subframe 4 and 5, this value corresponds to the 'frame
+ * id' of the navigation message, in the range of 1-25 (Subframe 1, 2, 3
+ * does not contain a 'frame id' and this value can be set to -1.)
+ *
+ * - For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.
+ *
+ * - For BeiDou D1, this refers to the frame number in the range of 1-24
+ *
+ * - For Beidou D2, this refers to the frame number, in the range of 1-120
+ *
+ * - For Galileo F/NAV nominal frame structure, this refers to the subframe
+ * number, in the range of 1-12
+ *
+ * - For Galileo I/NAV nominal frame structure, this refers to the subframe
+ * number in the range of 1-24
+ */
+ int16_t messageId;
+
+ /*
+ * Sub-message identifier. If required by the message 'type', this value
+ * contains a sub-index within the current message (or frame) that is being
+ * transmitted.
+ *
+ * - For GNSS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to
+ * the subframe number of the navigation message, in the range of 1-5.
+ *
+ * - For Glonass L1 C/A, this refers to the String number, in the range from
+ * 1-15
+ *
+ * - For Galileo F/NAV, this refers to the page type in the range 1-6
+ *
+ * - For Galileo I/NAV, this refers to the word type in the range 1-10+
+ */
+ int16_t submessageId;
+
+ /*
+ * The data of the reported GNSS message. The bytes (or words) are specified
+ * using big endian format (MSB first). The data is stored and decoded
+ * in a server for research purposes.
+ *
+ * - For GNSS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit
+ * words. Each word (30 bits) must fit into the last 30 bits in a
+ * 4-byte word (skip B31 and B32), with MSB first, for a total of 40
+ * bytes, covering a time period of 6, 6, and 0.6 seconds, respectively.
+ * The standard followed is 1995 SPS Signal specification.
+ *
+ * - For Glonass L1 C/A, each string contains 85 data bits, including the
+ * checksum. These bits must fit into 11 bytes, with MSB first (skip
+ * B86-B88), covering a time period of 2 seconds.
+ * The standard followed is Glonass Interface Control Document Edition 5.1.
+ *
+ * - For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols
+ * excluded). Each word must fit into 30-bytes, with MSB first (skip
+ * B239, B240), covering a time period of 10 seconds. The standard
+ * followed is European GNSS(Galileo) Signal in Space Interface
+ * Control Document Issue 1.2.
+ *
+ * - For Galileo I/NAV, each page contains 2 page parts, even and odd, with
+ * a total of 2x114 = 228 bits, (sync & tail excluded) that must fit
+ * into 29 bytes, with MSB first (skip B229-B232). The standard followed
+ * is same as above.
+ *
+ * TODO(b/32022567): Describe this relationship with data to the VTS
+ * via custom annotations and plug in a VTS test to verify that the data
+ * correctly follows the standard.
+ *
+ */
+ vec<uint8_t> data;
+ };
+
+ /*
+ * The callback to report an available fragment of a GNSS navigation messages
+ * from the HAL.
+ *
+ * @param message - The GNSS navigation submessage/subframe representation.
+ */
+ gnssNavigationMessageCb(GnssNavigationMessage message);
+};
diff --git a/gnss/1.0/IGnssNi.hal b/gnss/1.0/IGnssNi.hal
new file mode 100644
index 0000000..c823bf0
--- /dev/null
+++ b/gnss/1.0/IGnssNi.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+import IGnssNiCallback;
+
+/*
+ * Extended interface for Network-initiated (NI) support. This interface is used
+ * to respond to NI notifications originating from the HAL.
+ */
+interface IGnssNi {
+ /*
+ * Registers the callbacks for HAL to use.
+ *
+ * @param callback handle to IGnssNiCallback interface.
+ */
+ setCallback(IGnssNiCallback callback);
+
+ /*
+ * Sends a response to HAL.
+ *
+ * @param notifId An ID generated by HAL to associate NI notifications and
+ * framework responses.
+ * @param userResponse A GNSS Ni response indicating if the notification was
+ * accepted, denied or not responded to.
+ */
+ respond(int32_t notifId, GnssUserResponseType userResponse);
+};
diff --git a/gnss/1.0/IGnssNiCallback.hal b/gnss/1.0/IGnssNiCallback.hal
new file mode 100644
index 0000000..c5fb223
--- /dev/null
+++ b/gnss/1.0/IGnssNiCallback.hal
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+/* GNSS Network Initiated callback interface. */
+interface IGnssNiCallback {
+ /*
+ * GnssNiType constants
+ */
+ @export(name="", value_prefix="GPS_NI_TYPE_")
+ enum GnssNiType : uint8_t {
+ VOICE = 1,
+ UMTS_SUPL = 2,
+ UMTS_CTRL_PLANE = 3
+ };
+
+ /*
+ * GnssNiNotifyFlags constants
+ */
+ @export(name="", value_prefix="GPS_NI_")
+ enum GnssNiNotifyFlags : uint32_t {
+ /** NI requires notification */
+ NEED_NOTIFY = 0x0001,
+ /** NI requires verification */
+ NEED_VERIFY = 0x0002,
+ /** NI requires privacy override, no notification/minimal trace */
+ PRIVACY_OVERRIDE = 0x0004,
+ };
+
+ /*
+ * GNSS NI responses, used to define the response in
+ * NI structures
+ */
+ @export(name="", value_prefix="GPS_NI_")
+ enum GnssUserResponseType : uint8_t {
+ RESPONSE_ACCEPT = 1,
+ RESPONSE_DENY = 2,
+ RESPONSE_NORESP = 3,
+ };
+
+ /*
+ * NI data encoding scheme
+ */
+ @export(name="", value_prefix="GPS_")
+ enum GnssNiEncodingType : int32_t {
+ ENC_NONE = 0,
+ ENC_SUPL_GSM_DEFAULT = 1,
+ ENC_SUPL_UTF8 = 2,
+ ENC_SUPL_UCS2 = 3,
+ ENC_UNKNOWN = -1,
+ };
+
+ /** Represents an NI request */
+ struct GnssNiNotification{
+ /*
+ * An ID generated by HAL to associate NI notifications and UI
+ * responses.
+ */
+ int32_t notificationId;
+
+ /*
+ * A type used to distinguish different categories of NI
+ * events, such as VOICE, UMTS_SUPL etc.
+ */
+ GnssNiType niType;
+
+ /*
+ * Notification/verification options, combinations of GnssNiNotifyFlags
+ * constants.
+ */
+ bitfield<GnssNiNotifyFlags> notifyFlags;
+
+ /*
+ * Timeout period to wait for user response.
+ * Set to 0 for no timeout limit. Specified in seconds.
+ */
+ uint32_t timeoutSec;
+
+ /*
+ * Default response when timeout.
+ */
+ GnssUserResponseType defaultResponse;
+
+ /*
+ * String representing the requester of the network inititated location
+ * request.
+ */
+ string requestorId;
+
+ /*
+ * Notification message. String representing the service(for eg. SUPL-service)
+ * who sent the network initiated location request.
+ */
+ string notificationMessage;
+
+ /*
+ * requestorId decoding scheme.
+ */
+ GnssNiEncodingType requestorIdEncoding;
+
+ /*
+ * notificationId decoding scheme
+ */
+ GnssNiEncodingType notificationIdEncoding;
+ };
+
+ /*
+ * Callback with a network initiated request.
+ *
+ * @param notification network initiated request.
+ */
+ niNotifyCb(GnssNiNotification notification);
+};
diff --git a/gnss/1.0/IGnssXtra.hal b/gnss/1.0/IGnssXtra.hal
new file mode 100644
index 0000000..5222fde
--- /dev/null
+++ b/gnss/1.0/IGnssXtra.hal
@@ -0,0 +1,27 @@
+package android.hardware.gnss@1.0;
+import IGnssXtraCallback;
+
+/*
+ * This interface is used by the GNSS HAL to request the framework
+ * to download XTRA data.
+ */
+interface IGnssXtra {
+ /*
+ * Opens the XTRA interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Handle to the IGnssXtraCallback interface.
+ *
+ * @return success True if the operation is successful.
+ */
+ setCallback(IGnssXtraCallback callback) generates (bool success);
+
+ /*
+ * Inject the downloaded XTRA data into the GNSS receiver.
+ *
+ * @param xtraData GNSS XTRA data.
+ *
+ * @return success True if the operation is successful.
+ */
+ injectXtraData(string xtraData) generates (bool success);
+};
diff --git a/gnss/1.0/IGnssXtraCallback.hal b/gnss/1.0/IGnssXtraCallback.hal
new file mode 100644
index 0000000..42df082
--- /dev/null
+++ b/gnss/1.0/IGnssXtraCallback.hal
@@ -0,0 +1,12 @@
+package android.hardware.gnss@1.0;
+
+/*
+ * This interface is used by the GNSS HAL to request download of XTRA data.
+ */
+interface IGnssXtraCallback {
+ /*
+ * Callback to request the client to download XTRA data. The client should
+ * download XTRA data and inject it by calling injectXtraData().
+ */
+ downloadRequestCb();
+};
diff --git a/gnss/1.0/default/AGnss.cpp b/gnss/1.0/default/AGnss.cpp
new file mode 100644
index 0000000..29c6ddd
--- /dev/null
+++ b/gnss/1.0/default/AGnss.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_AGnssInterface"
+
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> AGnss::sThreadFuncArgsList;
+sp<IAGnssCallback> AGnss::sAGnssCbIface = nullptr;
+bool AGnss::sInterfaceExists = false;
+
+AGpsCallbacks AGnss::sAGnssCb = {
+ .status_cb = statusCb,
+ .create_thread_cb = createThreadCb
+};
+
+AGnss::AGnss(const AGpsInterface* aGpsIface) : mAGnssIface(aGpsIface) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+}
+
+AGnss::~AGnss() {
+ sThreadFuncArgsList.clear();
+ sInterfaceExists = false;
+}
+
+void AGnss::statusCb(AGpsStatus* status) {
+ if (sAGnssCbIface == nullptr) {
+ ALOGE("%s: AGNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (status == nullptr) {
+ ALOGE("AGNSS status is invalid");
+ return;
+ }
+
+ /*
+ * Logic based on AGnssStatus processing by GnssLocationProvider. Size of
+ * AGpsStatus is checked for backward compatibility since some devices may
+ * be sending out an older version of AGpsStatus that only supports IPv4.
+ */
+ size_t statusSize = status->size;
+ if (status->size == sizeof(AGpsStatus)) {
+ switch (status->addr.ss_family)
+ {
+ case AF_INET:
+ {
+ /*
+ * ss_family indicates IPv4.
+ */
+ struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(&(status->addr));
+ IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = {
+ .type = static_cast<IAGnssCallback::AGnssType>(status->type),
+ .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status),
+ .ipV4Addr = in->sin_addr.s_addr,
+ };
+
+ /*
+ * Callback to client with agnssStatusIpV4Cb.
+ */
+ auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ break;
+ }
+ case AF_INET6:
+ {
+ /*
+ * ss_family indicates IPv6. Callback to client with agnssStatusIpV6Cb.
+ */
+ IAGnssCallback::AGnssStatusIpV6 aGnssStatusIpV6;
+
+ aGnssStatusIpV6.type = static_cast<IAGnssCallback::AGnssType>(status->type);
+ aGnssStatusIpV6.status = static_cast<IAGnssCallback::AGnssStatusValue>(
+ status->status);
+
+ struct sockaddr_in6* in6 = reinterpret_cast<struct sockaddr_in6 *>(
+ &(status->addr));
+ memcpy(&(aGnssStatusIpV6.ipV6Addr[0]), in6->sin6_addr.s6_addr,
+ aGnssStatusIpV6.ipV6Addr.size());
+ auto ret = sAGnssCbIface->agnssStatusIpV6Cb(aGnssStatusIpV6);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ break;
+ }
+ default:
+ ALOGE("Invalid ss_family found: %d", status->addr.ss_family);
+ }
+ } else if (statusSize >= sizeof(AGpsStatus_v2)) {
+ AGpsStatus_v2* statusV2 = reinterpret_cast<AGpsStatus_v2*>(status);
+ uint32_t ipV4Addr = statusV2->ipaddr;
+ IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = {
+ .type = static_cast<IAGnssCallback::AGnssType>(AF_INET),
+ .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status),
+ /*
+ * For older versions of AGpsStatus, change IP addr to net order. This
+ * was earlier being done in GnssLocationProvider.
+ */
+ .ipV4Addr = htonl(ipV4Addr)
+ };
+ /*
+ * Callback to client with agnssStatusIpV4Cb.
+ */
+ auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ } else {
+ ALOGE("%s: Invalid size for AGPS Status", __func__);
+ }
+}
+
+pthread_t AGnss::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+/*
+ * Implementation of methods from ::android::hardware::gnss::V1_0::IAGnss follow.
+ */
+Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) {
+ if (mAGnssIface == nullptr) {
+ ALOGE("%s: AGnss interface is unavailable", __func__);
+ return Void();
+ }
+
+ sAGnssCbIface = callback;
+
+ mAGnssIface->init(&sAGnssCb);
+ return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+ if (mAGnssIface == nullptr) {
+ ALOGE("%s: AGnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mAGnssIface->data_conn_closed() == 0);
+}
+
+Return<bool> AGnss::dataConnFailed() {
+ if (mAGnssIface == nullptr) {
+ ALOGE("%s: AGnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mAGnssIface->data_conn_failed() == 0);
+}
+
+Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) {
+ if (mAGnssIface == nullptr) {
+ ALOGE("%s: AGnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mAGnssIface->set_server(static_cast<AGpsType>(type), hostname.c_str(), port) == 0);
+}
+
+Return<bool> AGnss::dataConnOpen(const hidl_string& apn, IAGnss::ApnIpType apnIpType) {
+ if (mAGnssIface == nullptr) {
+ ALOGE("%s: AGnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mAGnssIface->data_conn_open_with_apn_ip_type(apn.c_str(),
+ static_cast<uint16_t>(apnIpType)) == 0);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/AGnss.h b/gnss/1.0/default/AGnss.h
new file mode 100644
index 0000000..2a8eed0
--- /dev/null
+++ b/gnss/1.0/default/AGnss.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_AGnss_H_
+#define android_hardware_gnss_V1_0_AGnss_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <hardware/gps_internal.h>
+#include <hidl/Status.h>
+#include <netinet/in.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnss;
+using ::android::hardware::gnss::V1_0::IAGnssCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Extended interface for AGNSS support. Also contains wrapper methods to allow
+ * methods from IAGnssCallback interface to be passed into the conventional
+ * implementation of the GNSS HAL.
+ */
+struct AGnss : public IAGnss {
+ AGnss(const AGpsInterface* agpsIface);
+ ~AGnss();
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow.
+ * These declarations were generated from IAGnss.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssCallback>& callback) override;
+ Return<bool> dataConnClosed() override;
+ Return<bool> dataConnFailed() override;
+ Return<bool> setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname, int32_t port) override;
+ Return<bool> dataConnOpen(const hidl_string& apn,
+ IAGnss::ApnIpType apnIpType) override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default
+ * implementation. These methods are not part of the IAGnss base class.
+ */
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+ static void statusCb(AGpsStatus* status);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static AGpsCallbacks sAGnssCb;
+
+ private:
+ const AGpsInterface* mAGnssIface = nullptr;
+ static sp<IAGnssCallback> sAGnssCbIface;
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static bool sInterfaceExists;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_AGnss_H_
diff --git a/gnss/1.0/default/AGnssRil.cpp b/gnss/1.0/default/AGnssRil.cpp
new file mode 100644
index 0000000..1458327
--- /dev/null
+++ b/gnss/1.0/default/AGnssRil.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_AGnssRilInterface"
+
+#include "AGnssRil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> AGnssRil::sThreadFuncArgsList;
+sp<IAGnssRilCallback> AGnssRil::sAGnssRilCbIface = nullptr;
+bool AGnssRil::sInterfaceExists = false;
+
+AGpsRilCallbacks AGnssRil::sAGnssRilCb = {
+ .request_setid = AGnssRil::requestSetId,
+ .request_refloc = AGnssRil::requestRefLoc,
+ .create_thread_cb = AGnssRil::createThreadCb
+};
+
+AGnssRil::AGnssRil(const AGpsRilInterface* aGpsRilIface) : mAGnssRilIface(aGpsRilIface) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+}
+
+AGnssRil::~AGnssRil() {
+ sThreadFuncArgsList.clear();
+ sInterfaceExists = false;
+}
+
+void AGnssRil::requestSetId(uint32_t flags) {
+ if (sAGnssRilCbIface == nullptr) {
+ ALOGE("%s: AGNSSRil Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = sAGnssRilCbIface->requestSetIdCb(flags);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void AGnssRil::requestRefLoc(uint32_t /*flags*/) {
+ if (sAGnssRilCbIface == nullptr) {
+ ALOGE("%s: AGNSSRil Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = sAGnssRilCbIface->requestRefLocCb();
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+pthread_t AGnssRil::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+Return<void> AGnssRil::setCallback(const sp<IAGnssRilCallback>& callback) {
+ if (mAGnssRilIface == nullptr) {
+ ALOGE("%s: AGnssRil interface is unavailable", __func__);
+ return Void();
+ }
+
+ sAGnssRilCbIface = callback;
+
+ mAGnssRilIface->init(&sAGnssRilCb);
+ return Void();
+}
+
+Return<void> AGnssRil::setRefLocation(const IAGnssRil::AGnssRefLocation& aGnssRefLocation) {
+ if (mAGnssRilIface == nullptr) {
+ ALOGE("%s: AGnssRil interface is unavailable", __func__);
+ return Void();
+ }
+
+ AGpsRefLocation aGnssRefloc;
+ aGnssRefloc.type = static_cast<uint16_t>(aGnssRefLocation.type);
+
+ auto& cellID = aGnssRefLocation.cellID;
+ aGnssRefloc.u.cellID = {
+ .type = static_cast<uint16_t>(cellID.type),
+ .mcc = cellID.mcc,
+ .mnc = cellID.mnc,
+ .lac = cellID.lac,
+ .cid = cellID.cid,
+ .tac = cellID.tac,
+ .pcid = cellID.pcid
+ };
+
+ mAGnssRilIface->set_ref_location(&aGnssRefloc, sizeof(aGnssRefloc));
+ return Void();
+}
+
+Return<bool> AGnssRil::setSetId(IAGnssRil::SetIDType type, const hidl_string& setid) {
+ if (mAGnssRilIface == nullptr) {
+ ALOGE("%s: AGnssRil interface is unavailable", __func__);
+ return false;
+ }
+
+ mAGnssRilIface->set_set_id(static_cast<uint16_t>(type), setid.c_str());
+ return true;
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected,
+ IAGnssRil::NetworkType type,
+ bool roaming) {
+ if (mAGnssRilIface == nullptr) {
+ ALOGE("%s: AGnssRil interface is unavailable", __func__);
+ return false;
+ }
+
+ mAGnssRilIface->update_network_state(connected,
+ static_cast<int>(type),
+ roaming,
+ nullptr /* extra_info */);
+ return true;
+}
+
+Return<bool> AGnssRil::updateNetworkAvailability(bool available, const hidl_string& apn) {
+ if (mAGnssRilIface == nullptr) {
+ ALOGE("%s: AGnssRil interface is unavailable", __func__);
+ return false;
+ }
+
+ mAGnssRilIface->update_network_availability(available, apn.c_str());
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/AGnssRil.h b/gnss/1.0/default/AGnssRil.h
new file mode 100644
index 0000000..6215a9e
--- /dev/null
+++ b/gnss/1.0/default/AGnssRil.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_AGnssRil_H_
+#define android_hardware_gnss_V1_0_AGnssRil_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IAGnssRil.h>
+#include <hardware/gps.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnssRil;
+using ::android::hardware::gnss::V1_0::IAGnssRilCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public IAGnssRil {
+ AGnssRil(const AGpsRilInterface* aGpsRilIface);
+ ~AGnssRil();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+ * These declarations were generated from IAGnssRil.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssRilCallback>& callback) override;
+ Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& agnssReflocation) override;
+ Return<bool> setSetId(IAGnssRil::SetIDType type, const hidl_string& setid) override;
+ Return<bool> updateNetworkState(bool connected,
+ IAGnssRil::NetworkType type,
+ bool roaming) override;
+ Return<bool> updateNetworkAvailability(bool available, const hidl_string& apn) override;
+ static void requestSetId(uint32_t flags);
+ static void requestRefLoc(uint32_t flags);
+
+ /*
+ * Callback method to be passed into the conventional GNSS HAL by the default
+ * implementation. This method is not part of the IAGnssRil base class.
+ */
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static AGpsRilCallbacks sAGnssRilCb;
+
+ private:
+ const AGpsRilInterface* mAGnssRilIface = nullptr;
+ static sp<IAGnssRilCallback> sAGnssRilCbIface;
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static bool sInterfaceExists;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_AGnssRil_H_
diff --git a/gnss/1.0/default/Android.mk b/gnss/1.0/default/Android.mk
new file mode 100644
index 0000000..5ad5e50
--- /dev/null
+++ b/gnss/1.0/default/Android.mk
@@ -0,0 +1,56 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ ThreadCreationWrapper.cpp \
+ AGnss.cpp \
+ AGnssRil.cpp \
+ Gnss.cpp \
+ GnssBatching.cpp \
+ GnssDebug.cpp \
+ GnssGeofencing.cpp \
+ GnssMeasurement.cpp \
+ GnssNavigationMessage.cpp \
+ GnssNi.cpp \
+ GnssXtra.cpp \
+ GnssConfiguration.cpp \
+ GnssUtils.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ android.hardware.gnss@1.0 \
+ libhardware
+
+LOCAL_CFLAGS += -Werror
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.gnss@1.0-service
+LOCAL_INIT_RC := android.hardware.gnss@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.gnss@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
new file mode 100644
index 0000000..afb659c
--- /dev/null
+++ b/gnss/1.0/default/Gnss.cpp
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssInterface"
+
+#include "Gnss.h"
+#include <GnssUtils.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> Gnss::sThreadFuncArgsList;
+sp<IGnssCallback> Gnss::sGnssCbIface = nullptr;
+bool Gnss::sInterfaceExists = false;
+bool Gnss::sWakelockHeldGnss = false;
+bool Gnss::sWakelockHeldFused = false;
+
+GpsCallbacks Gnss::sGnssCb = {
+ .size = sizeof(GpsCallbacks),
+ .location_cb = locationCb,
+ .status_cb = statusCb,
+ .sv_status_cb = gpsSvStatusCb,
+ .nmea_cb = nmeaCb,
+ .set_capabilities_cb = setCapabilitiesCb,
+ .acquire_wakelock_cb = acquireWakelockCb,
+ .release_wakelock_cb = releaseWakelockCb,
+ .create_thread_cb = createThreadCb,
+ .request_utc_time_cb = requestUtcTimeCb,
+ .set_system_info_cb = setSystemInfoCb,
+ .gnss_sv_status_cb = gnssSvStatusCb,
+};
+
+uint32_t Gnss::sCapabilitiesCached = 0;
+uint16_t Gnss::sYearOfHwCached = 0;
+
+Gnss::Gnss(gps_device_t* gnssDevice) :
+ mDeathRecipient(new GnssHidlDeathRecipient(this)) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+
+ if (gnssDevice == nullptr) {
+ ALOGE("%s: Invalid device_t handle", __func__);
+ return;
+ }
+
+ mGnssIface = gnssDevice->get_gps_interface(gnssDevice);
+}
+
+Gnss::~Gnss() {
+ sInterfaceExists = false;
+ sThreadFuncArgsList.clear();
+}
+
+void Gnss::locationCb(GpsLocation* location) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (location == nullptr) {
+ ALOGE("%s: Invalid location from GNSS HAL", __func__);
+ return;
+ }
+
+ android::hardware::gnss::V1_0::GnssLocation gnssLocation = convertToGnssLocation(location);
+ auto ret = sGnssCbIface->gnssLocationCb(gnssLocation);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void Gnss::statusCb(GpsStatus* gnssStatus) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (gnssStatus == nullptr) {
+ ALOGE("%s: Invalid GpsStatus from GNSS HAL", __func__);
+ return;
+ }
+
+ IGnssCallback::GnssStatusValue status =
+ static_cast<IGnssCallback::GnssStatusValue>(gnssStatus->status);
+
+ auto ret = sGnssCbIface->gnssStatusCb(status);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void Gnss::gnssSvStatusCb(GnssSvStatus* status) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (status == nullptr) {
+ ALOGE("Invalid status from GNSS HAL %s", __func__);
+ return;
+ }
+
+ IGnssCallback::GnssSvStatus svStatus;
+ svStatus.numSvs = status->num_svs;
+
+ if (svStatus.numSvs > static_cast<uint32_t>(GnssMax::SVS_COUNT)) {
+ ALOGW("Too many satellites %zd. Clamps to %d.", svStatus.numSvs, GnssMax::SVS_COUNT);
+ svStatus.numSvs = static_cast<uint32_t>(GnssMax::SVS_COUNT);
+ }
+
+ for (size_t i = 0; i < svStatus.numSvs; i++) {
+ auto svInfo = status->gnss_sv_list[i];
+ IGnssCallback::GnssSvInfo gnssSvInfo = {
+ .svid = svInfo.svid,
+ .constellation = static_cast<android::hardware::gnss::V1_0::GnssConstellationType>(
+ svInfo.constellation),
+ .cN0Dbhz = svInfo.c_n0_dbhz,
+ .elevationDegrees = svInfo.elevation,
+ .azimuthDegrees = svInfo.azimuth,
+ .svFlag = svInfo.flags,
+ // Older chipsets do not provide carrier frequency, hence HAS_CARRIER_FREQUENCY flag
+ // is not set and the carrierFrequencyHz field is set to zero
+ .carrierFrequencyHz = 0
+ };
+ svStatus.gnssSvList[i] = gnssSvInfo;
+ }
+
+ auto ret = sGnssCbIface->gnssSvStatusCb(svStatus);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+/*
+ * This enum is used by gpsSvStatusCb() method below to convert GpsSvStatus
+ * to GnssSvStatus for backward compatibility. It is only used by the default
+ * implementation and is not part of the GNSS interface.
+ */
+enum SvidValues : uint16_t {
+ GLONASS_SVID_OFFSET = 64,
+ GLONASS_SVID_COUNT = 24,
+ BEIDOU_SVID_OFFSET = 200,
+ BEIDOU_SVID_COUNT = 35,
+ SBAS_SVID_MIN = 33,
+ SBAS_SVID_MAX = 64,
+ SBAS_SVID_ADD = 87,
+ QZSS_SVID_MIN = 193,
+ QZSS_SVID_MAX = 200
+};
+
+/*
+ * The following code that converts GpsSvStatus to GnssSvStatus is moved here from
+ * GnssLocationProvider. GnssLocationProvider does not require it anymore since GpsSvStatus is
+ * being deprecated and is no longer part of the GNSS interface.
+ */
+void Gnss::gpsSvStatusCb(GpsSvStatus* svInfo) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (svInfo == nullptr) {
+ ALOGE("Invalid status from GNSS HAL %s", __func__);
+ return;
+ }
+
+ IGnssCallback::GnssSvStatus svStatus;
+ svStatus.numSvs = svInfo->num_svs;
+ /*
+ * Clamp the list size since GnssSvStatus can support a maximum of
+ * GnssMax::SVS_COUNT entries.
+ */
+ if (svStatus.numSvs > static_cast<uint32_t>(GnssMax::SVS_COUNT)) {
+ ALOGW("Too many satellites %zd. Clamps to %d.", svStatus.numSvs, GnssMax::SVS_COUNT);
+ svStatus.numSvs = static_cast<uint32_t>(GnssMax::SVS_COUNT);
+ }
+
+ uint32_t ephemerisMask = svInfo->ephemeris_mask;
+ uint32_t almanacMask = svInfo->almanac_mask;
+ uint32_t usedInFixMask = svInfo->used_in_fix_mask;
+ /*
+ * Conversion from GpsSvInfo to IGnssCallback::GnssSvInfo happens below.
+ */
+ for (size_t i = 0; i < svStatus.numSvs; i++) {
+ IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList[i];
+ info.svid = svInfo->sv_list[i].prn;
+ if (info.svid >= 1 && info.svid <= 32) {
+ info.constellation = GnssConstellationType::GPS;
+ } else if (info.svid > GLONASS_SVID_OFFSET &&
+ info.svid <= GLONASS_SVID_OFFSET + GLONASS_SVID_COUNT) {
+ info.constellation = GnssConstellationType::GLONASS;
+ info.svid -= GLONASS_SVID_OFFSET;
+ } else if (info.svid > BEIDOU_SVID_OFFSET &&
+ info.svid <= BEIDOU_SVID_OFFSET + BEIDOU_SVID_COUNT) {
+ info.constellation = GnssConstellationType::BEIDOU;
+ info.svid -= BEIDOU_SVID_OFFSET;
+ } else if (info.svid >= SBAS_SVID_MIN && info.svid <= SBAS_SVID_MAX) {
+ info.constellation = GnssConstellationType::SBAS;
+ info.svid += SBAS_SVID_ADD;
+ } else if (info.svid >= QZSS_SVID_MIN && info.svid <= QZSS_SVID_MAX) {
+ info.constellation = GnssConstellationType::QZSS;
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", info.svid);
+ info.constellation = GnssConstellationType::UNKNOWN;
+ }
+
+ info.cN0Dbhz = svInfo->sv_list[i].snr;
+ info.elevationDegrees = svInfo->sv_list[i].elevation;
+ info.azimuthDegrees = svInfo->sv_list[i].azimuth;
+ // TODO: b/31702236
+ info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+
+ /*
+ * Only GPS info is valid for these fields, as these masks are just 32
+ * bits, by GPS prn.
+ */
+ if (info.constellation == GnssConstellationType::GPS) {
+ int32_t svidMask = (1 << (info.svid - 1));
+ if ((ephemerisMask & svidMask) != 0) {
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+ }
+ if ((almanacMask & svidMask) != 0) {
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+ }
+ if ((usedInFixMask & svidMask) != 0) {
+ info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+ }
+ }
+ }
+
+ auto ret = sGnssCbIface->gnssSvStatusCb(svStatus);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void Gnss::nmeaCb(GpsUtcTime timestamp, const char* nmea, int length) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ android::hardware::hidl_string nmeaString;
+ nmeaString.setToExternal(nmea, length);
+ auto ret = sGnssCbIface->gnssNmeaCb(timestamp, nmeaString);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void Gnss::setCapabilitiesCb(uint32_t capabilities) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = sGnssCbIface->gnssSetCapabilitesCb(capabilities);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ // Save for reconnection when some legacy hal's don't resend this info
+ sCapabilitiesCached = capabilities;
+}
+
+void Gnss::acquireWakelockCb() {
+ acquireWakelockGnss();
+}
+
+void Gnss::releaseWakelockCb() {
+ releaseWakelockGnss();
+}
+
+
+void Gnss::acquireWakelockGnss() {
+ sWakelockHeldGnss = true;
+ updateWakelock();
+}
+
+void Gnss::releaseWakelockGnss() {
+ sWakelockHeldGnss = false;
+ updateWakelock();
+}
+
+void Gnss::acquireWakelockFused() {
+ sWakelockHeldFused = true;
+ updateWakelock();
+}
+
+void Gnss::releaseWakelockFused() {
+ sWakelockHeldFused = false;
+ updateWakelock();
+}
+
+void Gnss::updateWakelock() {
+ // Track the state of the last request - in case the wake lock in the layer above is reference
+ // counted.
+ static bool sWakelockHeld = false;
+
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (sWakelockHeldGnss || sWakelockHeldFused) {
+ if (!sWakelockHeld) {
+ ALOGI("%s: GNSS HAL Wakelock acquired due to gps: %d, fused: %d", __func__,
+ sWakelockHeldGnss, sWakelockHeldFused);
+ sWakelockHeld = true;
+ auto ret = sGnssCbIface->gnssAcquireWakelockCb();
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ }
+ } else {
+ if (sWakelockHeld) {
+ ALOGI("%s: GNSS HAL Wakelock released", __func__);
+ } else {
+ // To avoid burning power, always release, even if logic got here with sWakelock false
+ // which it shouldn't, unless underlying *.h implementation makes duplicate requests.
+ ALOGW("%s: GNSS HAL Wakelock released, duplicate request", __func__);
+ }
+ sWakelockHeld = false;
+ auto ret = sGnssCbIface->gnssReleaseWakelockCb();
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+ }
+}
+
+void Gnss::requestUtcTimeCb() {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = sGnssCbIface->gnssRequestTimeCb();
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+pthread_t Gnss::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+void Gnss::setSystemInfoCb(const LegacyGnssSystemInfo* info) {
+ if (sGnssCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (info == nullptr) {
+ ALOGE("Invalid GnssSystemInfo from GNSS HAL %s", __func__);
+ return;
+ }
+
+ IGnssCallback::GnssSystemInfo gnssInfo = {
+ .yearOfHw = info->year_of_hw
+ };
+
+ auto ret = sGnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+
+ // Save for reconnection when some legacy hal's don't resend this info
+ sYearOfHwCached = info->year_of_hw;
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+Return<bool> Gnss::setCallback(const sp<IGnssCallback>& callback) {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ if (callback == nullptr) {
+ ALOGE("%s: Null callback ignored", __func__);
+ return false;
+ }
+
+ if (sGnssCbIface != NULL) {
+ ALOGW("%s called more than once. Unexpected unless test.", __func__);
+ sGnssCbIface->unlinkToDeath(mDeathRecipient);
+ }
+
+ sGnssCbIface = callback;
+ callback->linkToDeath(mDeathRecipient, 0 /*cookie*/);
+
+ // If this was received in the past, send it up again to refresh caller.
+ // mGnssIface will override after init() is called below, if needed
+ // (though it's unlikely the gps.h capabilities or system info will change.)
+ if (sCapabilitiesCached != 0) {
+ setCapabilitiesCb(sCapabilitiesCached);
+ }
+ if (sYearOfHwCached != 0) {
+ LegacyGnssSystemInfo info;
+ info.year_of_hw = sYearOfHwCached;
+ setSystemInfoCb(&info);
+ }
+
+ return (mGnssIface->init(&sGnssCb) == 0);
+}
+
+Return<bool> Gnss::start() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mGnssIface->start() == 0);
+}
+
+Return<bool> Gnss::stop() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mGnssIface->stop() == 0);
+}
+
+Return<void> Gnss::cleanup() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ } else {
+ mGnssIface->cleanup();
+ }
+ return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mGnssIface->inject_location(latitudeDegrees, longitudeDegrees, accuracyMeters) == 0);
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mGnssIface->inject_time(timeMs, timeReferenceMs, uncertaintyMs) == 0);
+}
+
+Return<void> Gnss::deleteAidingData(IGnss::GnssAidingData aidingDataFlags) {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ } else {
+ mGnssIface->delete_aiding_data(static_cast<GpsAidingData>(aidingDataFlags));
+ }
+ return Void();
+}
+
+Return<bool> Gnss::setPositionMode(IGnss::GnssPositionMode mode,
+ IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mGnssIface->set_position_mode(static_cast<GpsPositionMode>(mode),
+ static_cast<GpsPositionRecurrence>(recurrence),
+ minIntervalMs,
+ preferredAccuracyMeters,
+ preferredTimeMs) == 0);
+}
+
+Return<sp<IAGnssRil>> Gnss::getExtensionAGnssRil() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssRil == nullptr) {
+ const AGpsRilInterface* agpsRilIface = static_cast<const AGpsRilInterface*>(
+ mGnssIface->get_extension(AGPS_RIL_INTERFACE));
+ if (agpsRilIface == nullptr) {
+ ALOGE("%s GnssRil interface not implemented by GNSS HAL", __func__);
+ } else {
+ mGnssRil = new AGnssRil(agpsRilIface);
+ }
+ }
+ return mGnssRil;
+}
+
+Return<sp<IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssConfig == nullptr) {
+ const GnssConfigurationInterface* gnssConfigIface =
+ static_cast<const GnssConfigurationInterface*>(
+ mGnssIface->get_extension(GNSS_CONFIGURATION_INTERFACE));
+
+ if (gnssConfigIface == nullptr) {
+ ALOGE("%s GnssConfiguration interface not implemented by GNSS HAL", __func__);
+ } else {
+ mGnssConfig = new GnssConfiguration(gnssConfigIface);
+ }
+ }
+ return mGnssConfig;
+}
+
+Return<sp<IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssGeofencingIface == nullptr) {
+ const GpsGeofencingInterface* gpsGeofencingIface =
+ static_cast<const GpsGeofencingInterface*>(
+ mGnssIface->get_extension(GPS_GEOFENCING_INTERFACE));
+
+ if (gpsGeofencingIface == nullptr) {
+ ALOGE("%s GnssGeofencing interface not implemented by GNSS HAL", __func__);
+ } else {
+ mGnssGeofencingIface = new GnssGeofencing(gpsGeofencingIface);
+ }
+ }
+
+ return mGnssGeofencingIface;
+}
+
+Return<sp<IAGnss>> Gnss::getExtensionAGnss() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mAGnssIface == nullptr) {
+ const AGpsInterface* agpsIface = static_cast<const AGpsInterface*>(
+ mGnssIface->get_extension(AGPS_INTERFACE));
+ if (agpsIface == nullptr) {
+ ALOGE("%s AGnss interface not implemented by GNSS HAL", __func__);
+ } else {
+ mAGnssIface = new AGnss(agpsIface);
+ }
+ }
+ return mAGnssIface;
+}
+
+Return<sp<IGnssNi>> Gnss::getExtensionGnssNi() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssNi == nullptr) {
+ const GpsNiInterface* gpsNiIface = static_cast<const GpsNiInterface*>(
+ mGnssIface->get_extension(GPS_NI_INTERFACE));
+ if (gpsNiIface == nullptr) {
+ ALOGE("%s GnssNi interface not implemented by GNSS HAL", __func__);
+ } else {
+ mGnssNi = new GnssNi(gpsNiIface);
+ }
+ }
+ return mGnssNi;
+}
+
+Return<sp<IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssMeasurement == nullptr) {
+ const GpsMeasurementInterface* gpsMeasurementIface =
+ static_cast<const GpsMeasurementInterface*>(
+ mGnssIface->get_extension(GPS_MEASUREMENT_INTERFACE));
+
+ if (gpsMeasurementIface == nullptr) {
+ ALOGE("%s GnssMeasurement interface not implemented by GNSS HAL", __func__);
+ } else {
+ mGnssMeasurement = new GnssMeasurement(gpsMeasurementIface);
+ }
+ }
+ return mGnssMeasurement;
+}
+
+Return<sp<IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssNavigationMessage == nullptr) {
+ const GpsNavigationMessageInterface* gpsNavigationMessageIface =
+ static_cast<const GpsNavigationMessageInterface*>(
+ mGnssIface->get_extension(GPS_NAVIGATION_MESSAGE_INTERFACE));
+
+ if (gpsNavigationMessageIface == nullptr) {
+ ALOGE("%s GnssNavigationMessage interface not implemented by GNSS HAL",
+ __func__);
+ } else {
+ mGnssNavigationMessage = new GnssNavigationMessage(gpsNavigationMessageIface);
+ }
+ }
+
+ return mGnssNavigationMessage;
+}
+
+Return<sp<IGnssXtra>> Gnss::getExtensionXtra() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssXtraIface == nullptr) {
+ const GpsXtraInterface* gpsXtraIface = static_cast<const GpsXtraInterface*>(
+ mGnssIface->get_extension(GPS_XTRA_INTERFACE));
+
+ if (gpsXtraIface == nullptr) {
+ ALOGE("%s GnssXtra interface not implemented by HAL", __func__);
+ } else {
+ mGnssXtraIface = new GnssXtra(gpsXtraIface);
+ }
+ }
+
+ return mGnssXtraIface;
+}
+
+Return<sp<IGnssDebug>> Gnss::getExtensionGnssDebug() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssDebug == nullptr) {
+ const GpsDebugInterface* gpsDebugIface = static_cast<const GpsDebugInterface*>(
+ mGnssIface->get_extension(GPS_DEBUG_INTERFACE));
+
+ if (gpsDebugIface == nullptr) {
+ ALOGE("%s: GnssDebug interface is not implemented by HAL", __func__);
+ } else {
+ mGnssDebug = new GnssDebug(gpsDebugIface);
+ }
+ }
+
+ return mGnssDebug;
+}
+
+Return<sp<IGnssBatching>> Gnss::getExtensionGnssBatching() {
+ if (mGnssIface == nullptr) {
+ ALOGE("%s: Gnss interface is unavailable", __func__);
+ return nullptr;
+ }
+
+ if (mGnssBatching == nullptr) {
+ hw_module_t* module;
+ const FlpLocationInterface* flpLocationIface = nullptr;
+ int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+
+ if (err != 0) {
+ ALOGE("gnss flp hw_get_module failed: %d", err);
+ } else if (module == nullptr) {
+ ALOGE("Fused Location hw_get_module returned null module");
+ } else if (module->methods == nullptr) {
+ ALOGE("Fused Location hw_get_module returned null methods");
+ } else {
+ hw_device_t* device;
+ err = module->methods->open(module, FUSED_LOCATION_HARDWARE_MODULE_ID, &device);
+ if (err != 0) {
+ ALOGE("flpDevice open failed: %d", err);
+ } else {
+ flp_device_t * flpDevice = reinterpret_cast<flp_device_t*>(device);
+ flpLocationIface = flpDevice->get_flp_interface(flpDevice);
+ }
+ }
+
+ if (flpLocationIface == nullptr) {
+ ALOGE("%s: GnssBatching interface is not implemented by HAL", __func__);
+ } else {
+ mGnssBatching = new GnssBatching(flpLocationIface);
+ }
+ }
+ return mGnssBatching;
+}
+
+void Gnss::handleHidlDeath() {
+ ALOGW("GNSS service noticed HIDL death. Stopping all GNSS operations.");
+
+ // commands down to the HAL implementation
+ stop(); // stop ongoing GPS tracking
+ if (mGnssMeasurement != nullptr) {
+ mGnssMeasurement->close();
+ }
+ if (mGnssNavigationMessage != nullptr) {
+ mGnssNavigationMessage->close();
+ }
+ if (mGnssBatching != nullptr) {
+ mGnssBatching->stop();
+ mGnssBatching->cleanup();
+ }
+ cleanup();
+
+ /*
+ * This has died, so close it off in case (race condition) callbacks happen
+ * before HAL processes above messages.
+ */
+ sGnssCbIface = nullptr;
+}
+
+IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
+ hw_module_t* module;
+ IGnss* iface = nullptr;
+ int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+
+ if (err == 0) {
+ hw_device_t* device;
+ err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ iface = new Gnss(reinterpret_cast<gps_device_t*>(device));
+ } else {
+ ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
+ }
+ } else {
+ ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
+ }
+ return iface;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/Gnss.h b/gnss/1.0/default/Gnss.h
new file mode 100644
index 0000000..faf903c
--- /dev/null
+++ b/gnss/1.0/default/Gnss.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_Gnss_H_
+#define android_hardware_gnss_V1_0_Gnss_H_
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssBatching.h>
+#include <GnssConfiguration.h>
+#include <GnssDebug.h>
+#include <GnssGeofencing.h>
+#include <GnssMeasurement.h>
+#include <GnssNavigationMessage.h>
+#include <GnssNi.h>
+#include <GnssXtra.h>
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <hardware/fused_location.h>
+#include <hardware/gps.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+using LegacyGnssSystemInfo = ::GnssSystemInfo;
+
+/*
+ * Represents the standard GNSS interface. Also contains wrapper methods to allow methods from
+ * IGnssCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+class Gnss : public IGnss {
+ public:
+ Gnss(gps_device_t* gnss_device);
+ ~Gnss();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+ * These declarations were generated from Gnss.hal.
+ */
+ Return<bool> setCallback(const sp<IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<bool> injectTime(int64_t timeMs,
+ int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<void> deleteAidingData(IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(IGnss::GnssPositionMode mode,
+ IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<IAGnssRil>> getExtensionAGnssRil() override;
+ Return<sp<IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<IAGnss>> getExtensionAGnss() override;
+ Return<sp<IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+ Return<sp<IGnssXtra>> getExtensionXtra() override;
+ Return<sp<IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<IGnssDebug>> getExtensionGnssDebug() override;
+ Return<sp<IGnssBatching>> getExtensionGnssBatching() override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default
+ * implementation. These methods are not part of the IGnss base class.
+ */
+ static void locationCb(GpsLocation* location);
+ static void statusCb(GpsStatus* gnss_status);
+ static void nmeaCb(GpsUtcTime timestamp, const char* nmea, int length);
+ static void setCapabilitiesCb(uint32_t capabilities);
+ static void acquireWakelockCb();
+ static void releaseWakelockCb();
+ static void requestUtcTimeCb();
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+ static void gnssSvStatusCb(GnssSvStatus* status);
+ /*
+ * Deprecated callback added for backward compatibility to devices that do
+ * not support GnssSvStatus.
+ */
+ static void gpsSvStatusCb(GpsSvStatus* status);
+ static void setSystemInfoCb(const LegacyGnssSystemInfo* info);
+
+ /*
+ * Wakelock consolidation, only needed for dual use of a gps.h & fused_location.h HAL
+ *
+ * Ensures that if the last call from either legacy .h was to acquire a wakelock, that a
+ * wakelock is held. Otherwise releases it.
+ */
+ static void acquireWakelockFused();
+ static void releaseWakelockFused();
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsCallbacks sGnssCb;
+
+ private:
+ /*
+ * For handling system-server death while GNSS service lives on.
+ */
+ class GnssHidlDeathRecipient : public hidl_death_recipient {
+ public:
+ GnssHidlDeathRecipient(const sp<Gnss> gnss) : mGnss(gnss) {
+ }
+
+ virtual void serviceDied(uint64_t /*cookie*/,
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ mGnss->handleHidlDeath();
+ }
+ private:
+ sp<Gnss> mGnss;
+ };
+
+ // for wakelock consolidation, see above
+ static void acquireWakelockGnss();
+ static void releaseWakelockGnss();
+ static void updateWakelock();
+ static bool sWakelockHeldGnss;
+ static bool sWakelockHeldFused;
+
+ /*
+ * Cleanup for death notification
+ */
+ void handleHidlDeath();
+
+ sp<GnssXtra> mGnssXtraIface = nullptr;
+ sp<AGnssRil> mGnssRil = nullptr;
+ sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+ sp<AGnss> mAGnssIface = nullptr;
+ sp<GnssNi> mGnssNi = nullptr;
+ sp<GnssMeasurement> mGnssMeasurement = nullptr;
+ sp<GnssNavigationMessage> mGnssNavigationMessage = nullptr;
+ sp<GnssDebug> mGnssDebug = nullptr;
+ sp<GnssConfiguration> mGnssConfig = nullptr;
+ sp<GnssBatching> mGnssBatching = nullptr;
+
+ sp<GnssHidlDeathRecipient> mDeathRecipient;
+
+ const GpsInterface* mGnssIface = nullptr;
+ static sp<IGnssCallback> sGnssCbIface;
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static bool sInterfaceExists;
+
+ // Values saved for resend
+ static uint32_t sCapabilitiesCached;
+ static uint16_t sYearOfHwCached;
+};
+
+extern "C" IGnss* HIDL_FETCH_IGnss(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_Gnss_H_
diff --git a/gnss/1.0/default/GnssBatching.cpp b/gnss/1.0/default/GnssBatching.cpp
new file mode 100644
index 0000000..02b38cb
--- /dev/null
+++ b/gnss/1.0/default/GnssBatching.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssBatchingInterface"
+
+#include "GnssBatching.h"
+#include <Gnss.h> // for wakelock consolidation
+#include <GnssUtils.h>
+
+#include <cutils/log.h> // for ALOGE
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+sp<IGnssBatchingCallback> GnssBatching::sGnssBatchingCbIface = nullptr;
+bool GnssBatching::sFlpSupportsBatching = false;
+
+FlpCallbacks GnssBatching::sFlpCb = {
+ .size = sizeof(FlpCallbacks),
+ .location_cb = locationCb,
+ .acquire_wakelock_cb = acquireWakelockCb,
+ .release_wakelock_cb = releaseWakelockCb,
+ .set_thread_event_cb = setThreadEventCb,
+ .flp_capabilities_cb = flpCapabilitiesCb,
+ .flp_status_cb = flpStatusCb,
+};
+
+GnssBatching::GnssBatching(const FlpLocationInterface* flpLocationIface) :
+ mFlpLocationIface(flpLocationIface) {
+}
+
+/*
+ * This enum is used locally by various methods below. It is only used by the default
+ * implementation and is not part of the GNSS interface.
+ */
+enum BatchingValues : uint16_t {
+ // Numbers 0-3 were used in earlier implementations - using 4 to be distinct to the HAL
+ FLP_GNSS_BATCHING_CLIENT_ID = 4,
+ // Tech. mask of GNSS, and sensor aiding, for legacy HAL to fit with GnssBatching API
+ FLP_TECH_MASK_GNSS_AND_SENSORS = FLP_TECH_MASK_GNSS | FLP_TECH_MASK_SENSORS,
+ // Putting a cap to avoid possible memory issues. Unlikely values this high are supported.
+ MAX_LOCATIONS_PER_BATCH = 1000
+};
+
+void GnssBatching::locationCb(int32_t locationsCount, FlpLocation** locations) {
+ if (sGnssBatchingCbIface == nullptr) {
+ ALOGE("%s: GNSS Batching Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (locations == nullptr) {
+ ALOGE("%s: Invalid locations from GNSS HAL", __func__);
+ return;
+ }
+
+ if (locationsCount < 0) {
+ ALOGE("%s: Negative location count: %d set to 0", __func__, locationsCount);
+ locationsCount = 0;
+ } else if (locationsCount > MAX_LOCATIONS_PER_BATCH) {
+ ALOGW("%s: Unexpected high location count: %d set to %d", __func__, locationsCount,
+ MAX_LOCATIONS_PER_BATCH);
+ locationsCount = MAX_LOCATIONS_PER_BATCH;
+ }
+
+ /**
+ * Note:
+ * Some existing implementations may drop duplicate locations. These could be expanded here
+ * but as there's ambiguity between no-GPS-fix vs. dropped duplicates in that implementation,
+ * and that's not specified by the fused_location.h, that isn't safe to do here.
+ * Fortunately, this shouldn't be a major issue in cases where GNSS batching is typically
+ * used (e.g. when user is likely in vehicle/bicycle.)
+ */
+ std::vector<android::hardware::gnss::V1_0::GnssLocation> gnssLocations;
+ for (int iLocation = 0; iLocation < locationsCount; iLocation++) {
+ if (locations[iLocation] == nullptr) {
+ ALOGE("%s: Null location at slot: %d of %d, skipping", __func__, iLocation,
+ locationsCount);
+ continue;
+ }
+ if ((locations[iLocation]->sources_used & ~FLP_TECH_MASK_GNSS_AND_SENSORS) != 0)
+ {
+ ALOGE("%s: Unrequested location type %d at slot: %d of %d, skipping", __func__,
+ locations[iLocation]->sources_used, iLocation, locationsCount);
+ continue;
+ }
+ gnssLocations.push_back(convertToGnssLocation(locations[iLocation]));
+ }
+
+ auto ret = sGnssBatchingCbIface->gnssLocationBatchCb(gnssLocations);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssBatching::acquireWakelockCb() {
+ Gnss::acquireWakelockFused();
+}
+
+void GnssBatching::releaseWakelockCb() {
+ Gnss::releaseWakelockFused();
+}
+
+// this can just return success, because threads are now set up on demand in the jni layer
+int32_t GnssBatching::setThreadEventCb(ThreadEvent /*event*/) {
+ return FLP_RESULT_SUCCESS;
+}
+
+void GnssBatching::flpCapabilitiesCb(int32_t capabilities) {
+ ALOGD("%s capabilities %d", __func__, capabilities);
+
+ if (capabilities & CAPABILITY_GNSS) {
+ // once callback is received and capabilities high enough, we know version is
+ // high enough for flush()
+ sFlpSupportsBatching = true;
+ }
+}
+
+void GnssBatching::flpStatusCb(int32_t status) {
+ ALOGD("%s (default implementation) not forwarding status: %d", __func__, status);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching is unavailable", __func__);
+ return false;
+ }
+
+ sGnssBatchingCbIface = callback;
+
+ return (mFlpLocationIface->init(&sFlpCb) == 0);
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching interface is unavailable", __func__);
+ return 0;
+ }
+
+ return mFlpLocationIface->get_batch_size();
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching interface is unavailable", __func__);
+ return false;
+ }
+
+ if (!sFlpSupportsBatching) {
+ ALOGE("%s: Flp batching interface not supported, no capabilities callback received",
+ __func__);
+ return false;
+ }
+
+ FlpBatchOptions optionsHw;
+ // Legacy code used 9999 mW for High accuracy, and 21 mW for balanced.
+ // New GNSS API just expects reasonable GNSS chipset behavior - do something efficient
+ // given the interval. This 100 mW limit should be quite sufficient (esp. given legacy code
+ // implementations may not even use this value.)
+ optionsHw.max_power_allocation_mW = 100;
+ optionsHw.sources_to_use = FLP_TECH_MASK_GNSS_AND_SENSORS;
+ optionsHw.flags = 0;
+ if (options.flags & Flag::WAKEUP_ON_FIFO_FULL) {
+ optionsHw.flags |= FLP_BATCH_WAKEUP_ON_FIFO_FULL;
+ }
+ optionsHw.period_ns = options.periodNanos;
+ optionsHw.smallest_displacement_meters = 0; // Zero offset - just use time interval
+
+ return (mFlpLocationIface->start_batching(FLP_GNSS_BATCHING_CLIENT_ID, &optionsHw)
+ == FLP_RESULT_SUCCESS);
+}
+
+Return<void> GnssBatching::flush() {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching interface is unavailable", __func__);
+ return Void();
+ }
+
+ mFlpLocationIface->flush_batched_locations();
+
+ return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching interface is unavailable", __func__);
+ return false;
+ }
+
+ return (mFlpLocationIface->stop_batching(FLP_GNSS_BATCHING_CLIENT_ID) == FLP_RESULT_SUCCESS);
+}
+
+Return<void> GnssBatching::cleanup() {
+ if (mFlpLocationIface == nullptr) {
+ ALOGE("%s: Flp batching interface is unavailable", __func__);
+ return Void();
+ }
+
+ mFlpLocationIface->cleanup();
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssBatching.h b/gnss/1.0/default/GnssBatching.h
new file mode 100644
index 0000000..001c27d
--- /dev/null
+++ b/gnss/1.0/default/GnssBatching.h
@@ -0,0 +1,67 @@
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <hardware/fused_location.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct GnssBatching : public IGnssBatching {
+ GnssBatching(const FlpLocationInterface* flpLocationIface);
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+ Return<bool> init(const sp<IGnssBatchingCallback>& callback) override;
+ Return<uint16_t> getBatchSize() override;
+ Return<bool> start(const IGnssBatching::Options& options ) override;
+ Return<void> flush() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+
+ /*
+ * Callback methods to be passed into the conventional FLP HAL by the default
+ * implementation. These methods are not part of the IGnssBatching base class.
+ */
+ static void locationCb(int32_t locationsCount, FlpLocation** locations);
+ static void acquireWakelockCb();
+ static void releaseWakelockCb();
+ static int32_t setThreadEventCb(ThreadEvent event);
+ static void flpCapabilitiesCb(int32_t capabilities);
+ static void flpStatusCb(int32_t status);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static FlpCallbacks sFlpCb;
+
+ private:
+ const FlpLocationInterface* mFlpLocationIface = nullptr;
+ static sp<IGnssBatchingCallback> sGnssBatchingCbIface;
+ static bool sFlpSupportsBatching;
+};
+
+extern "C" IGnssBatching* HIDL_FETCH_IGnssBatching(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
diff --git a/gnss/1.0/default/GnssConfiguration.cpp b/gnss/1.0/default/GnssConfiguration.cpp
new file mode 100644
index 0000000..0c1aa86
--- /dev/null
+++ b/gnss/1.0/default/GnssConfiguration.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssConfigurationInterface"
+
+#include <log/log.h>
+
+#include "GnssConfiguration.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+GnssConfiguration::GnssConfiguration(const GnssConfigurationInterface* gnssConfigInfc)
+ : mGnssConfigIface(gnssConfigInfc) {}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "SUPL_ES=" + std::to_string(enabled ? 1 : 0) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "SUPL_VER=" + std::to_string(version) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+
+ return true;
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "SUPL_MODE=" + std::to_string(mode) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfile) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "LPP_PROFILE=" + std::to_string(lppProfile) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "A_GLONASS_POS_PROTOCOL_SELECT=" +
+ std::to_string(protocol) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "GPS_LOCK=" + std::to_string(lock) + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+ if (mGnssConfigIface == nullptr) {
+ ALOGE("%s: GNSS Configuration interface is not available.", __func__);
+ return false;
+ }
+
+ std::string config = "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=" + std::to_string(enabled ? 1 : 0)
+ + "\n";
+ mGnssConfigIface->configuration_update(config.c_str(), config.size());
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssConfiguration.h b/gnss/1.0/default/GnssConfiguration.h
new file mode 100644
index 0000000..a6eca88
--- /dev/null
+++ b/gnss/1.0/default/GnssConfiguration.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+
+#ifndef android_hardware_gnss_V1_0_GnssConfiguration_H_
+#define android_hardware_gnss_V1_0_GnssConfiguration_H_
+
+#include <android/hardware/gnss/1.0/IGnssConfiguration.h>
+#include <hardware/gps.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssConfiguration;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct GnssConfiguration : public IGnssConfiguration {
+ GnssConfiguration(const GnssConfigurationInterface* gnssConfigIface);
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ * These declarations were generated from IGnssConfiguration.hal.
+ */
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(uint8_t mode) override;
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setLppProfile(uint8_t lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+ Return<bool> setGpsLock(uint8_t lock) override;
+
+ private:
+ const GnssConfigurationInterface* mGnssConfigIface = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssConfiguration_H_
diff --git a/gnss/1.0/default/GnssDebug.cpp b/gnss/1.0/default/GnssDebug.cpp
new file mode 100644
index 0000000..cfc38ca
--- /dev/null
+++ b/gnss/1.0/default/GnssDebug.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssDebugInterface"
+
+#include <log/log.h>
+
+#include "GnssDebug.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+GnssDebug::GnssDebug(const GpsDebugInterface* gpsDebugIface) : mGnssDebugIface(gpsDebugIface) {}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb) {
+ /*
+ * This is a new interface and hence there is no way to retrieve the
+ * debug data from the HAL.
+ */
+ DebugData data = {};
+
+ _hidl_cb(data);
+
+ /*
+ * Log the debug data sent from the conventional Gnss HAL. This code is
+ * moved here from GnssLocationProvider.
+ */
+ if (mGnssDebugIface) {
+ char buffer[kMaxDebugStrLen + 1];
+ size_t length = mGnssDebugIface->get_internal_state(buffer, kMaxDebugStrLen);
+ length = std::max(length, kMaxDebugStrLen);
+ buffer[length] = '\0';
+ ALOGD("Gnss Debug Data: %s", buffer);
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssDebug.h b/gnss/1.0/default/GnssDebug.h
new file mode 100644
index 0000000..9a17dde
--- /dev/null
+++ b/gnss/1.0/default/GnssDebug.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssDebug_H_
+#define android_hardware_gnss_V1_0_GnssDebug_H_
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+#include <hardware/gps.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct GnssDebug : public IGnssDebug {
+ GnssDebug(const GpsDebugInterface* gpsDebugIface);
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+ * These declarations were generated from IGnssDebug.hal.
+ */
+ Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+ private:
+ /*
+ * Constant added for backward compatibility to conventional GPS Hals which
+ * returned a debug string.
+ */
+ const size_t kMaxDebugStrLen = 2047;
+ const GpsDebugInterface* mGnssDebugIface = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssDebug_H_
diff --git a/gnss/1.0/default/GnssGeofencing.cpp b/gnss/1.0/default/GnssGeofencing.cpp
new file mode 100644
index 0000000..54c4aaa
--- /dev/null
+++ b/gnss/1.0/default/GnssGeofencing.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHal_GnssGeofencing"
+
+#include "GnssGeofencing.h"
+#include <GnssUtils.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> GnssGeofencing::sThreadFuncArgsList;
+sp<IGnssGeofenceCallback> GnssGeofencing::mGnssGeofencingCbIface = nullptr;
+bool GnssGeofencing::sInterfaceExists = false;
+
+GpsGeofenceCallbacks GnssGeofencing::sGnssGfCb = {
+ .geofence_transition_callback = gnssGfTransitionCb,
+ .geofence_status_callback = gnssGfStatusCb,
+ .geofence_add_callback = gnssGfAddCb,
+ .geofence_remove_callback = gnssGfRemoveCb,
+ .geofence_pause_callback = gnssGfPauseCb,
+ .geofence_resume_callback = gnssGfResumeCb,
+ .create_thread_cb = createThreadCb
+};
+
+GnssGeofencing::GnssGeofencing(const GpsGeofencingInterface* gpsGeofencingIface)
+ : mGnssGeofencingIface(gpsGeofencingIface) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+}
+
+GnssGeofencing::~GnssGeofencing() {
+ sThreadFuncArgsList.clear();
+ sInterfaceExists = false;
+}
+void GnssGeofencing::gnssGfTransitionCb(int32_t geofenceId,
+ GpsLocation* location,
+ int32_t transition,
+ GpsUtcTime timestamp) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (location == nullptr) {
+ ALOGE("%s : Invalid location from GNSS HAL", __func__);
+ return;
+ }
+
+ GnssLocation gnssLocation = convertToGnssLocation(location);
+ auto ret = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+ geofenceId,
+ gnssLocation,
+ static_cast<IGnssGeofenceCallback::GeofenceTransition>(transition),
+ timestamp);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssGeofencing::gnssGfStatusCb(int32_t status, GpsLocation* location) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ GnssLocation gnssLocation;
+
+ if (location != nullptr) {
+ gnssLocation = convertToGnssLocation(location);
+ } else {
+ gnssLocation = {};
+ }
+
+ auto ret = mGnssGeofencingCbIface->gnssGeofenceStatusCb(
+ static_cast<IGnssGeofenceCallback::GeofenceAvailability>(status), gnssLocation);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssGeofencing::gnssGfAddCb(int32_t geofenceId, int32_t status) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = mGnssGeofencingCbIface->gnssGeofenceAddCb(
+ geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status));
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssGeofencing::gnssGfRemoveCb(int32_t geofenceId, int32_t status) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(
+ geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status));
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssGeofencing::gnssGfPauseCb(int32_t geofenceId, int32_t status) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = mGnssGeofencingCbIface->gnssGeofencePauseCb(
+ geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status));
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+void GnssGeofencing::gnssGfResumeCb(int32_t geofenceId, int32_t status) {
+ if (mGnssGeofencingCbIface == nullptr) {
+ ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = mGnssGeofencingCbIface->gnssGeofenceResumeCb(
+ geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status));
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+pthread_t GnssGeofencing::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback) {
+ mGnssGeofencingCbIface = callback;
+
+ if (mGnssGeofencingIface == nullptr) {
+ ALOGE("%s: GnssGeofencing interface is not available", __func__);
+ } else {
+ mGnssGeofencingIface->init(&sGnssGfCb);
+ }
+
+ return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+ int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) {
+ if (mGnssGeofencingIface == nullptr) {
+ ALOGE("%s: GnssGeofencing interface is not available", __func__);
+ return Void();
+ } else {
+ mGnssGeofencingIface->add_geofence_area(
+ geofenceId,
+ latitudeDegrees,
+ longitudeDegrees,
+ radiusMeters,
+ static_cast<int32_t>(lastTransition),
+ monitorTransitions,
+ notificationResponsivenessMs,
+ unknownTimerMs);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId) {
+ if (mGnssGeofencingIface == nullptr) {
+ ALOGE("%s: GnssGeofencing interface is not available", __func__);
+ } else {
+ mGnssGeofencingIface->pause_geofence(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) {
+ if (mGnssGeofencingIface == nullptr) {
+ ALOGE("%s: GnssGeofencing interface is not available", __func__);
+ } else {
+ mGnssGeofencingIface->resume_geofence(geofenceId, monitorTransitions);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId) {
+ if (mGnssGeofencingIface == nullptr) {
+ ALOGE("%s: GnssGeofencing interface is not available", __func__);
+ } else {
+ mGnssGeofencingIface->remove_geofence_area(geofenceId);
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssGeofencing.h b/gnss/1.0/default/GnssGeofencing.h
new file mode 100644
index 0000000..124b893
--- /dev/null
+++ b/gnss/1.0/default/GnssGeofencing.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssGeofencing_H_
+#define android_hardware_gnss_V1_0_GnssGeofencing_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+#include <hardware/gps.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for GNSS Geofencing support. It also contains wrapper methods to allow
+ * methods from IGnssGeofenceCallback interface to be passed into the
+ * conventional implementation of the GNSS HAL.
+ */
+struct GnssGeofencing : public IGnssGeofencing {
+ GnssGeofencing(const GpsGeofencingInterface* gpsGeofencingIface);
+ ~GnssGeofencing();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+ * These declarations were generated from IGnssGeofencing.hal.
+ */
+ Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback) override;
+ Return<void> addGeofence(int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) override;
+
+ Return<void> pauseGeofence(int32_t geofenceId) override;
+ Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) override;
+ Return<void> removeGeofence(int32_t geofenceId) override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default
+ * implementation. These methods are not part of the IGnssGeofencing base class.
+ */
+ static void gnssGfTransitionCb(int32_t geofence_id, GpsLocation* location,
+ int32_t transition, GpsUtcTime timestamp);
+ static void gnssGfStatusCb(int32_t status, GpsLocation* last_location);
+ static void gnssGfAddCb(int32_t geofence_id, int32_t status);
+ static void gnssGfRemoveCb(int32_t geofence_id, int32_t status);
+ static void gnssGfPauseCb(int32_t geofence_id, int32_t status);
+ static void gnssGfResumeCb(int32_t geofence_id, int32_t status);
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsGeofenceCallbacks sGnssGfCb;
+
+ private:
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static sp<IGnssGeofenceCallback> mGnssGeofencingCbIface;
+ const GpsGeofencingInterface* mGnssGeofencingIface = nullptr;
+ static bool sInterfaceExists;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssGeofencing_H_
diff --git a/gnss/1.0/default/GnssMeasurement.cpp b/gnss/1.0/default/GnssMeasurement.cpp
new file mode 100644
index 0000000..6c9b838
--- /dev/null
+++ b/gnss/1.0/default/GnssMeasurement.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssMeasurementInterface"
+
+#include "GnssMeasurement.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+sp<IGnssMeasurementCallback> GnssMeasurement::sGnssMeasureCbIface = nullptr;
+GpsMeasurementCallbacks GnssMeasurement::sGnssMeasurementCbs = {
+ .size = sizeof(GpsMeasurementCallbacks),
+ .measurement_callback = gpsMeasurementCb,
+ .gnss_measurement_callback = gnssMeasurementCb
+};
+
+GnssMeasurement::GnssMeasurement(const GpsMeasurementInterface* gpsMeasurementIface)
+ : mGnssMeasureIface(gpsMeasurementIface) {}
+
+void GnssMeasurement::gnssMeasurementCb(LegacyGnssData* legacyGnssData) {
+ if (sGnssMeasureCbIface == nullptr) {
+ ALOGE("%s: GNSSMeasurement Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (legacyGnssData == nullptr) {
+ ALOGE("%s: Invalid GnssData from GNSS HAL", __func__);
+ return;
+ }
+
+ IGnssMeasurementCallback::GnssData gnssData;
+ gnssData.measurementCount = std::min(legacyGnssData->measurement_count,
+ static_cast<size_t>(GnssMax::SVS_COUNT));
+
+ for (size_t i = 0; i < gnssData.measurementCount; i++) {
+ auto entry = legacyGnssData->measurements[i];
+ auto state = static_cast<GnssMeasurementState>(entry.state);
+ if (state & IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED) {
+ state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_KNOWN;
+ }
+ if (state & IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED) {
+ state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_KNOWN;
+ }
+ gnssData.measurements[i] = {
+ .flags = entry.flags,
+ .svid = entry.svid,
+ .constellation = static_cast<GnssConstellationType>(entry.constellation),
+ .timeOffsetNs = entry.time_offset_ns,
+ .state = state,
+ .receivedSvTimeInNs = entry.received_sv_time_in_ns,
+ .receivedSvTimeUncertaintyInNs = entry.received_sv_time_uncertainty_in_ns,
+ .cN0DbHz = entry.c_n0_dbhz,
+ .pseudorangeRateMps = entry.pseudorange_rate_mps,
+ .pseudorangeRateUncertaintyMps = entry.pseudorange_rate_uncertainty_mps,
+ .accumulatedDeltaRangeState = entry.accumulated_delta_range_state,
+ .accumulatedDeltaRangeM = entry.accumulated_delta_range_m,
+ .accumulatedDeltaRangeUncertaintyM = entry.accumulated_delta_range_uncertainty_m,
+ .carrierFrequencyHz = entry.carrier_frequency_hz,
+ .carrierCycles = entry.carrier_cycles,
+ .carrierPhase = entry.carrier_phase,
+ .carrierPhaseUncertainty = entry.carrier_phase_uncertainty,
+ .multipathIndicator = static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(
+ entry.multipath_indicator),
+ .snrDb = entry.snr_db
+ };
+ }
+
+ auto clockVal = legacyGnssData->clock;
+ gnssData.clock = {
+ .gnssClockFlags = clockVal.flags,
+ .leapSecond = clockVal.leap_second,
+ .timeNs = clockVal.time_ns,
+ .timeUncertaintyNs = clockVal.time_uncertainty_ns,
+ .fullBiasNs = clockVal.full_bias_ns,
+ .biasNs = clockVal.bias_ns,
+ .biasUncertaintyNs = clockVal.bias_uncertainty_ns,
+ .driftNsps = clockVal.drift_nsps,
+ .driftUncertaintyNsps = clockVal.drift_uncertainty_nsps,
+ .hwClockDiscontinuityCount = clockVal.hw_clock_discontinuity_count
+ };
+
+ auto ret = sGnssMeasureCbIface->GnssMeasurementCb(gnssData);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+/*
+ * The code in the following method has been moved here from GnssLocationProvider.
+ * It converts GpsData to GnssData. This code is no longer required in
+ * GnssLocationProvider since GpsData is deprecated and no longer part of the
+ * GNSS interface.
+ */
+void GnssMeasurement::gpsMeasurementCb(GpsData* gpsData) {
+ if (sGnssMeasureCbIface == nullptr) {
+ ALOGE("%s: GNSSMeasurement Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (gpsData == nullptr) {
+ ALOGE("%s: Invalid GpsData from GNSS HAL", __func__);
+ return;
+ }
+
+ IGnssMeasurementCallback::GnssData gnssData;
+ gnssData.measurementCount = std::min(gpsData->measurement_count,
+ static_cast<size_t>(GnssMax::SVS_COUNT));
+
+
+ for (size_t i = 0; i < gnssData.measurementCount; i++) {
+ auto entry = gpsData->measurements[i];
+ gnssData.measurements[i].flags = entry.flags;
+ gnssData.measurements[i].svid = static_cast<int32_t>(entry.prn);
+ if (entry.prn >= 1 && entry.prn <= 32) {
+ gnssData.measurements[i].constellation = GnssConstellationType::GPS;
+ } else {
+ gnssData.measurements[i].constellation =
+ GnssConstellationType::UNKNOWN;
+ }
+
+ gnssData.measurements[i].timeOffsetNs = entry.time_offset_ns;
+ gnssData.measurements[i].state = entry.state;
+ gnssData.measurements[i].receivedSvTimeInNs = entry.received_gps_tow_ns;
+ gnssData.measurements[i].receivedSvTimeUncertaintyInNs =
+ entry.received_gps_tow_uncertainty_ns;
+ gnssData.measurements[i].cN0DbHz = entry.c_n0_dbhz;
+ gnssData.measurements[i].pseudorangeRateMps = entry.pseudorange_rate_mps;
+ gnssData.measurements[i].pseudorangeRateUncertaintyMps =
+ entry.pseudorange_rate_uncertainty_mps;
+ gnssData.measurements[i].accumulatedDeltaRangeState =
+ entry.accumulated_delta_range_state;
+ gnssData.measurements[i].accumulatedDeltaRangeM =
+ entry.accumulated_delta_range_m;
+ gnssData.measurements[i].accumulatedDeltaRangeUncertaintyM =
+ entry.accumulated_delta_range_uncertainty_m;
+
+ if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
+ gnssData.measurements[i].carrierFrequencyHz = entry.carrier_frequency_hz;
+ } else {
+ gnssData.measurements[i].carrierFrequencyHz = 0;
+ }
+
+ if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_PHASE) {
+ gnssData.measurements[i].carrierPhase = entry.carrier_phase;
+ } else {
+ gnssData.measurements[i].carrierPhase = 0;
+ }
+
+ if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
+ gnssData.measurements[i].carrierPhaseUncertainty = entry.carrier_phase_uncertainty;
+ } else {
+ gnssData.measurements[i].carrierPhaseUncertainty = 0;
+ }
+
+ gnssData.measurements[i].multipathIndicator =
+ static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(
+ entry.multipath_indicator);
+
+ if (entry.flags & GNSS_MEASUREMENT_HAS_SNR) {
+ gnssData.measurements[i].snrDb = entry.snr_db;
+ } else {
+ gnssData.measurements[i].snrDb = 0;
+ }
+ }
+
+ auto clockVal = gpsData->clock;
+ static uint32_t discontinuity_count_to_handle_old_clock_type = 0;
+ auto flags = clockVal.flags;
+
+ gnssData.clock.leapSecond = clockVal.leap_second;
+ /*
+ * GnssClock only supports the more effective HW_CLOCK type, so type
+ * handling and documentation complexity has been removed. To convert the
+ * old GPS_CLOCK types (active only in a limited number of older devices),
+ * the GPS time information is handled as an always discontinuous HW clock,
+ * with the GPS time information put into the full_bias_ns instead - so that
+ * time_ns - full_bias_ns = local estimate of GPS time. Additionally, the
+ * sign of full_bias_ns and bias_ns has flipped between GpsClock &
+ * GnssClock, so that is also handled below.
+ */
+ switch (clockVal.type) {
+ case GPS_CLOCK_TYPE_UNKNOWN:
+ // Clock type unsupported.
+ ALOGE("Unknown clock type provided.");
+ break;
+ case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
+ // Already local hardware time. No need to do anything.
+ break;
+ case GPS_CLOCK_TYPE_GPS_TIME:
+ // GPS time, need to convert.
+ flags |= GPS_CLOCK_HAS_FULL_BIAS;
+ clockVal.full_bias_ns = clockVal.time_ns;
+ clockVal.time_ns = 0;
+ gnssData.clock.hwClockDiscontinuityCount =
+ discontinuity_count_to_handle_old_clock_type++;
+ break;
+ }
+
+ gnssData.clock.timeNs = clockVal.time_ns;
+ gnssData.clock.timeUncertaintyNs = clockVal.time_uncertainty_ns;
+ /*
+ * Definition of sign for full_bias_ns & bias_ns has been changed since N,
+ * so flip signs here.
+ */
+ gnssData.clock.fullBiasNs = -(clockVal.full_bias_ns);
+ gnssData.clock.biasNs = -(clockVal.bias_ns);
+ gnssData.clock.biasUncertaintyNs = clockVal.bias_uncertainty_ns;
+ gnssData.clock.driftNsps = clockVal.drift_nsps;
+ gnssData.clock.driftUncertaintyNsps = clockVal.drift_uncertainty_nsps;
+ gnssData.clock.gnssClockFlags = clockVal.flags;
+
+ auto ret = sGnssMeasureCbIface->GnssMeasurementCb(gnssData);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+ const sp<IGnssMeasurementCallback>& callback) {
+ if (mGnssMeasureIface == nullptr) {
+ ALOGE("%s: GnssMeasure interface is unavailable", __func__);
+ return GnssMeasurementStatus::ERROR_GENERIC;
+ }
+ sGnssMeasureCbIface = callback;
+
+ return static_cast<GnssMeasurement::GnssMeasurementStatus>(
+ mGnssMeasureIface->init(&sGnssMeasurementCbs));
+}
+
+Return<void> GnssMeasurement::close() {
+ if (mGnssMeasureIface == nullptr) {
+ ALOGE("%s: GnssMeasure interface is unavailable", __func__);
+ } else {
+ mGnssMeasureIface->close();
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssMeasurement.h b/gnss/1.0/default/GnssMeasurement.h
new file mode 100644
index 0000000..9ff1435
--- /dev/null
+++ b/gnss/1.0/default/GnssMeasurement.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssMeasurement_H_
+#define android_hardware_gnss_V1_0_GnssMeasurement_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <hidl/Status.h>
+#include <hardware/gps.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+using LegacyGnssData = ::GnssData;
+
+/*
+ * Extended interface for GNSS Measurements support. Also contains wrapper methods to allow methods
+ * from IGnssMeasurementCallback interface to be passed into the conventional implementation of the
+ * GNSS HAL.
+ */
+struct GnssMeasurement : public IGnssMeasurement {
+ GnssMeasurement(const GpsMeasurementInterface* gpsMeasurementIface);
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+ * These declarations were generated from IGnssMeasurement.hal.
+ */
+ Return<GnssMeasurementStatus> setCallback(
+ const sp<IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default
+ * implementation. These methods are not part of the IGnssMeasurement base class.
+ */
+ static void gnssMeasurementCb(LegacyGnssData* data);
+ /*
+ * Deprecated callback added for backward compatibity for devices that do
+ * not support GnssData measurements.
+ */
+ static void gpsMeasurementCb(GpsData* data);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsMeasurementCallbacks sGnssMeasurementCbs;
+
+ private:
+ const GpsMeasurementInterface* mGnssMeasureIface = nullptr;
+ static sp<IGnssMeasurementCallback> sGnssMeasureCbIface;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssMeasurement_H_
diff --git a/gnss/1.0/default/GnssNavigationMessage.cpp b/gnss/1.0/default/GnssNavigationMessage.cpp
new file mode 100644
index 0000000..6f509d0
--- /dev/null
+++ b/gnss/1.0/default/GnssNavigationMessage.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssNavigationMessageInterface"
+
+#include <log/log.h>
+
+#include "GnssNavigationMessage.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+sp<IGnssNavigationMessageCallback> GnssNavigationMessage::sGnssNavigationMsgCbIface = nullptr;
+
+GpsNavigationMessageCallbacks GnssNavigationMessage::sGnssNavigationMessageCb = {
+ .size = sizeof(GpsNavigationMessageCallbacks),
+ .navigation_message_callback = nullptr,
+ .gnss_navigation_message_callback = gnssNavigationMessageCb
+};
+
+GnssNavigationMessage::GnssNavigationMessage(
+ const GpsNavigationMessageInterface* gpsNavigationMessageIface) :
+ mGnssNavigationMessageIface(gpsNavigationMessageIface) {}
+
+void GnssNavigationMessage::gnssNavigationMessageCb(LegacyGnssNavigationMessage* message) {
+ if (sGnssNavigationMsgCbIface == nullptr) {
+ ALOGE("%s: GnssNavigation Message Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (message == nullptr) {
+ ALOGE("%s, received invalid GnssNavigationMessage from GNSS HAL", __func__);
+ return;
+ }
+
+ IGnssNavigationMessageCallback::GnssNavigationMessage navigationMsg;
+
+ navigationMsg.svid = message->svid;
+ navigationMsg.type =
+ static_cast<IGnssNavigationMessageCallback::GnssNavigationMessageType>(message->type);
+ navigationMsg.status = message->status;
+ navigationMsg.messageId = message->message_id;
+ navigationMsg.submessageId = message->submessage_id;
+ navigationMsg.data.setToExternal(message->data, message->data_length);
+
+ auto ret = sGnssNavigationMsgCbIface->gnssNavigationMessageCb(navigationMsg);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNavigationMessage follow.
+Return<GnssNavigationMessage::GnssNavigationMessageStatus> GnssNavigationMessage::setCallback(
+ const sp<IGnssNavigationMessageCallback>& callback) {
+ if (mGnssNavigationMessageIface == nullptr) {
+ ALOGE("%s: GnssNavigationMessage not available", __func__);
+ return GnssNavigationMessageStatus::ERROR_GENERIC;
+ }
+
+ sGnssNavigationMsgCbIface = callback;
+
+ return static_cast<GnssNavigationMessage::GnssNavigationMessageStatus>(
+ mGnssNavigationMessageIface->init(&sGnssNavigationMessageCb));
+}
+
+Return<void> GnssNavigationMessage::close() {
+ if (mGnssNavigationMessageIface == nullptr) {
+ ALOGE("%s: GnssNavigationMessage not available", __func__);
+ } else {
+ mGnssNavigationMessageIface->close();
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssNavigationMessage.h b/gnss/1.0/default/GnssNavigationMessage.h
new file mode 100644
index 0000000..882854b
--- /dev/null
+++ b/gnss/1.0/default/GnssNavigationMessage.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssNavigationMessage_H_
+#define android_hardware_gnss_V1_0_GnssNavigationMessage_H_
+
+#include <android/hardware/gnss/1.0/IGnssNavigationMessage.h>
+#include <hidl/Status.h>
+#include <hardware/gps.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNavigationMessage;
+using ::android::hardware::gnss::V1_0::IGnssNavigationMessageCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+using LegacyGnssNavigationMessage = ::GnssNavigationMessage;
+
+/*
+ * Extended interface for GNSS navigation message reporting support. Also contains wrapper methods
+ * to allow methods from IGnssNavigationMessageCallback interface to be passed into the conventional
+ * implementation of the GNSS HAL.
+ */
+struct GnssNavigationMessage : public IGnssNavigationMessage {
+ GnssNavigationMessage(const GpsNavigationMessageInterface* gpsNavigationMessageIface);
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssNavigationMessage follow.
+ * These declarations were generated from IGnssNavigationMessage.hal.
+ */
+ Return<GnssNavigationMessageStatus> setCallback(
+ const sp<IGnssNavigationMessageCallback>& callback) override;
+ Return<void> close() override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default implementation.
+ * These methods are not part of the IGnssNavigationMessage base class.
+ */
+ static void gnssNavigationMessageCb(LegacyGnssNavigationMessage* message);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsNavigationMessageCallbacks sGnssNavigationMessageCb;
+ private:
+ const GpsNavigationMessageInterface* mGnssNavigationMessageIface = nullptr;
+ static sp<IGnssNavigationMessageCallback> sGnssNavigationMsgCbIface;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssNavigationMessage_H_
diff --git a/gnss/1.0/default/GnssNi.cpp b/gnss/1.0/default/GnssNi.cpp
new file mode 100644
index 0000000..d17891d
--- /dev/null
+++ b/gnss/1.0/default/GnssNi.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssNiInterface"
+
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> GnssNi::sThreadFuncArgsList;
+sp<IGnssNiCallback> GnssNi::sGnssNiCbIface = nullptr;
+bool GnssNi::sInterfaceExists = false;
+
+GpsNiCallbacks GnssNi::sGnssNiCb = {
+ .notify_cb = niNotifyCb,
+ .create_thread_cb = createThreadCb
+};
+
+GnssNi::GnssNi(const GpsNiInterface* gpsNiIface) : mGnssNiIface(gpsNiIface) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+}
+
+GnssNi::~GnssNi() {
+ sThreadFuncArgsList.clear();
+ sInterfaceExists = false;
+}
+
+pthread_t GnssNi::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+void GnssNi::niNotifyCb(GpsNiNotification* notification) {
+ if (sGnssNiCbIface == nullptr) {
+ ALOGE("%s: GNSS NI Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ if (notification == nullptr) {
+ ALOGE("%s: Invalid GpsNotification callback from GNSS HAL", __func__);
+ return;
+ }
+
+ IGnssNiCallback::GnssNiNotification notificationGnss = {
+ .notificationId = notification->notification_id,
+ .niType = static_cast<IGnssNiCallback::GnssNiType>(notification->ni_type),
+ .notifyFlags = notification->notify_flags,
+ .timeoutSec = static_cast<uint32_t>(notification->timeout),
+ .defaultResponse =
+ static_cast<IGnssNiCallback::GnssUserResponseType>(notification->default_response),
+ .requestorId = notification->requestor_id,
+ .notificationMessage = notification->text,
+ .requestorIdEncoding =
+ static_cast<IGnssNiCallback::GnssNiEncodingType>(notification->requestor_id_encoding),
+ .notificationIdEncoding =
+ static_cast<IGnssNiCallback::GnssNiEncodingType>(notification->text_encoding)
+ };
+
+ auto ret = sGnssNiCbIface->niNotifyCb(notificationGnss);
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback) {
+ if (mGnssNiIface == nullptr) {
+ ALOGE("%s: GnssNi interface is unavailable", __func__);
+ return Void();
+ }
+
+ sGnssNiCbIface = callback;
+
+ mGnssNiIface->init(&sGnssNiCb);
+ return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse) {
+ if (mGnssNiIface == nullptr) {
+ ALOGE("%s: GnssNi interface is unavailable", __func__);
+ } else {
+ mGnssNiIface->respond(notifId, static_cast<GpsUserResponseType>(userResponse));
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssNi.h b/gnss/1.0/default/GnssNi.h
new file mode 100644
index 0000000..fe850b1
--- /dev/null
+++ b/gnss/1.0/default/GnssNi.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssNi_H_
+#define android_hardware_gnss_V1_0_GnssNi_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+#include <hardware/gps.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Extended interface for Network-initiated (NI) support. This interface is used to respond to
+ * NI notifications originating from the HAL. Also contains wrapper methods to allow methods from
+ * IGnssNiCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct GnssNi : public IGnssNi {
+ GnssNi(const GpsNiInterface* gpsNiIface);
+ ~GnssNi();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+ * These declarations were generated from IGnssNi.hal.
+ */
+ Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+ Return<void> respond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default
+ * implementation. These methods are not part of the IGnssNi base class.
+ */
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+ static void niNotifyCb(GpsNiNotification* notification);
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsNiCallbacks sGnssNiCb;
+
+ private:
+ const GpsNiInterface* mGnssNiIface = nullptr;
+ static sp<IGnssNiCallback> sGnssNiCbIface;
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static bool sInterfaceExists;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssNi_H_
diff --git a/gnss/1.0/default/GnssUtils.cpp b/gnss/1.0/default/GnssUtils.cpp
new file mode 100644
index 0000000..d9956d6
--- /dev/null
+++ b/gnss/1.0/default/GnssUtils.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "GnssUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using android::hardware::gnss::V1_0::GnssLocation;
+
+GnssLocation convertToGnssLocation(GpsLocation* location) {
+ GnssLocation gnssLocation = {};
+ if (location != nullptr) {
+ gnssLocation = {
+ // Bit operation AND with 1f below is needed to clear vertical accuracy,
+ // speed accuracy and bearing accuracy flags as some vendors are found
+ // to be setting these bits in pre-Android-O devices
+ .gnssLocationFlags = static_cast<uint16_t>(location->flags & 0x1f),
+ .latitudeDegrees = location->latitude,
+ .longitudeDegrees = location->longitude,
+ .altitudeMeters = location->altitude,
+ .speedMetersPerSec = location->speed,
+ .bearingDegrees = location->bearing,
+ .horizontalAccuracyMeters = location->accuracy,
+ // Older chipsets do not provide the following 3 fields, hence the flags
+ // HAS_VERTICAL_ACCURACY, HAS_SPEED_ACCURACY and HAS_BEARING_ACCURACY are
+ // not set and the field are set to zeros.
+ .verticalAccuracyMeters = 0,
+ .speedAccuracyMetersPerSecond = 0,
+ .bearingAccuracyDegrees = 0,
+ .timestamp = location->timestamp
+ };
+ }
+
+ return gnssLocation;
+}
+
+GnssLocation convertToGnssLocation(FlpLocation* location) {
+ GnssLocation gnssLocation = {};
+ if (location != nullptr) {
+ gnssLocation = {
+ // Bit mask applied (and 0's below) for same reason as above with GpsLocation
+ .gnssLocationFlags = static_cast<uint16_t>(location->flags & 0x1f),
+ .latitudeDegrees = location->latitude,
+ .longitudeDegrees = location->longitude,
+ .altitudeMeters = location->altitude,
+ .speedMetersPerSec = location->speed,
+ .bearingDegrees = location->bearing,
+ .horizontalAccuracyMeters = location->accuracy,
+ .verticalAccuracyMeters = 0,
+ .speedAccuracyMetersPerSecond = 0,
+ .bearingAccuracyDegrees = 0,
+ .timestamp = location->timestamp
+ };
+ }
+
+ return gnssLocation;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssUtils.h b/gnss/1.0/default/GnssUtils.h
new file mode 100644
index 0000000..38d4b2d
--- /dev/null
+++ b/gnss/1.0/default/GnssUtils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef android_hardware_gnss_V1_0_GnssUtil_H_
+#define android_hardware_gnss_V1_0_GnssUtil_H_
+
+#include <hardware/fused_location.h>
+#include <hardware/gps.h>
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+/*
+ * This method converts a GpsLocation struct to a GnssLocation
+ * struct.
+ */
+GnssLocation convertToGnssLocation(GpsLocation* location);
+
+/*
+ * This method converts an FlpLocation struct to a GnssLocation
+ * struct.
+ */
+GnssLocation convertToGnssLocation(FlpLocation* location);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/gnss/1.0/default/GnssXtra.cpp b/gnss/1.0/default/GnssXtra.cpp
new file mode 100644
index 0000000..d124ce1
--- /dev/null
+++ b/gnss/1.0/default/GnssXtra.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "GnssHAL_GnssXtraInterface"
+
+#include "GnssXtra.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+std::vector<std::unique_ptr<ThreadFuncArgs>> GnssXtra::sThreadFuncArgsList;
+sp<IGnssXtraCallback> GnssXtra::sGnssXtraCbIface = nullptr;
+bool GnssXtra::sInterfaceExists = false;
+
+GpsXtraCallbacks GnssXtra::sGnssXtraCb = {
+ .download_request_cb = gnssXtraDownloadRequestCb,
+ .create_thread_cb = createThreadCb,
+};
+
+GnssXtra::~GnssXtra() {
+ sThreadFuncArgsList.clear();
+ sInterfaceExists = false;
+}
+
+pthread_t GnssXtra::createThreadCb(const char* name, void (*start)(void*), void* arg) {
+ return createPthread(name, start, arg, &sThreadFuncArgsList);
+}
+
+GnssXtra::GnssXtra(const GpsXtraInterface* xtraIface) : mGnssXtraIface(xtraIface) {
+ /* Error out if an instance of the interface already exists. */
+ LOG_ALWAYS_FATAL_IF(sInterfaceExists);
+ sInterfaceExists = true;
+}
+
+void GnssXtra::gnssXtraDownloadRequestCb() {
+ if (sGnssXtraCbIface == nullptr) {
+ ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
+ return;
+ }
+
+ auto ret = sGnssXtraCbIface->downloadRequestCb();
+ if (!ret.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssXtra follow.
+Return<bool> GnssXtra::setCallback(const sp<IGnssXtraCallback>& callback) {
+ if (mGnssXtraIface == nullptr) {
+ ALOGE("%s: Gnss Xtra interface is unavailable", __func__);
+ return false;
+ }
+
+ sGnssXtraCbIface = callback;
+
+ return (mGnssXtraIface->init(&sGnssXtraCb) == 0);
+}
+
+Return<bool> GnssXtra::injectXtraData(const hidl_string& xtraData) {
+ if (mGnssXtraIface == nullptr) {
+ ALOGE("%s: Gnss Xtra interface is unavailable", __func__);
+ return false;
+ }
+
+ char* buf = new char[xtraData.size()];
+ const char* data = xtraData.c_str();
+
+ memcpy(buf, data, xtraData.size());
+
+ int ret = mGnssXtraIface->inject_xtra_data(buf, xtraData.size());
+ delete[] buf;
+ return (ret == 0);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/gnss/1.0/default/GnssXtra.h b/gnss/1.0/default/GnssXtra.h
new file mode 100644
index 0000000..7a0733a
--- /dev/null
+++ b/gnss/1.0/default/GnssXtra.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef android_hardware_gnss_V1_0_GnssXtra_H_
+#define android_hardware_gnss_V1_0_GnssXtra_H_
+
+#include <ThreadCreationWrapper.h>
+#include <android/hardware/gnss/1.0/IGnssXtra.h>
+#include <hardware/gps.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssXtra;
+using ::android::hardware::gnss::V1_0::IGnssXtraCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * This interface is used by the GNSS HAL to request the framework to download XTRA data.
+ * Also contains wrapper methods to allow methods from IGnssXtraCallback interface to be passed
+ * into the conventional implementation of the GNSS HAL.
+ */
+struct GnssXtra : public IGnssXtra {
+ GnssXtra(const GpsXtraInterface* xtraIface);
+ ~GnssXtra();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssXtra follow.
+ * These declarations were generated from IGnssXtra.hal.
+ */
+ Return<bool> setCallback(const sp<IGnssXtraCallback>& callback) override;
+ Return<bool> injectXtraData(const hidl_string& xtraData) override;
+
+ /*
+ * Callback methods to be passed into the conventional GNSS HAL by the default implementation.
+ * These methods are not part of the IGnssXtra base class.
+ */
+ static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg);
+ static void gnssXtraDownloadRequestCb();
+
+ /*
+ * Holds function pointers to the callback methods.
+ */
+ static GpsXtraCallbacks sGnssXtraCb;
+
+ private:
+ const GpsXtraInterface* mGnssXtraIface = nullptr;
+ static sp<IGnssXtraCallback> sGnssXtraCbIface;
+ static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList;
+ static bool sInterfaceExists;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_gnss_V1_0_GnssXtra_H_
diff --git a/gnss/1.0/default/ThreadCreationWrapper.cpp b/gnss/1.0/default/ThreadCreationWrapper.cpp
new file mode 100644
index 0000000..2a5638f
--- /dev/null
+++ b/gnss/1.0/default/ThreadCreationWrapper.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <ThreadCreationWrapper.h>
+
+void* threadFunc(void* arg) {
+ ThreadFuncArgs* threadArgs = reinterpret_cast<ThreadFuncArgs*>(arg);
+ threadArgs->fptr(threadArgs->args);
+ return nullptr;
+}
+
+pthread_t createPthread(const char* name,
+ void (*start)(void*),
+ void* arg, std::vector<std::unique_ptr<ThreadFuncArgs>> * listArgs) {
+ pthread_t threadId;
+ auto threadArgs = new ThreadFuncArgs(start, arg);
+ auto argPtr = std::unique_ptr<ThreadFuncArgs>(threadArgs);
+
+ listArgs->push_back(std::move(argPtr));
+
+ int ret = pthread_create(&threadId, nullptr, threadFunc, reinterpret_cast<void*>(
+ threadArgs));
+ if (ret != 0) {
+ ALOGE("pthread creation unsuccessful");
+ } else {
+ pthread_setname_np(threadId, name);
+ }
+ return threadId;
+}
diff --git a/gnss/1.0/default/ThreadCreationWrapper.h b/gnss/1.0/default/ThreadCreationWrapper.h
new file mode 100644
index 0000000..df0a9e4
--- /dev/null
+++ b/gnss/1.0/default/ThreadCreationWrapper.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H
+#define ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H
+
+#include <pthread.h>
+#include <vector>
+#include <cutils/log.h>
+
+typedef void (*threadEntryFunc)(void* ret);
+
+/*
+ * This class facilitates createThreadCb methods in various GNSS interfaces to wrap
+ * pthread_create() from libc since its function signature differs from what is required by the
+ * conventional GNSS HAL. The arguments passed to pthread_create() need to be on heap and not on
+ * the stack of createThreadCb.
+ */
+struct ThreadFuncArgs {
+ ThreadFuncArgs(void (*start)(void*), void* arg) : fptr(start), args(arg) {}
+
+ /* pointer to the function of type void()(void*) that needs to be wrapped */
+ threadEntryFunc fptr;
+ /* argument for fptr to be called with */
+ void* args;
+};
+
+/*
+ * This method is simply a wrapper. It is required since pthread_create() requires an entry
+ * function pointer of type void*()(void*) and the GNSS hal requires as input a function pointer of
+ * type void()(void*).
+ */
+void* threadFunc(void* arg);
+
+/*
+ * This method is called by createThreadCb with a pointer to the vector that
+ * holds the pointers to the thread arguments. The arg and start parameters are
+ * first used to create a ThreadFuncArgs object which is then saved in the
+ * listArgs parameters. The created ThreadFuncArgs object is then used to invoke
+ * threadFunc() method which in-turn invokes pthread_create.
+ */
+pthread_t createPthread(const char* name, void (*start)(void*), void* arg,
+ std::vector<std::unique_ptr<ThreadFuncArgs>> * listArgs);
+
+#endif
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
new file mode 100644
index 0000000..f1116f4
--- /dev/null
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -0,0 +1,7 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
+ class main
+ user system
+#
+# TODO:(b/35757613) - STOPSHIP - HAL cannot have direct inet access
+#
+ group system inet
diff --git a/gnss/1.0/default/service.cpp b/gnss/1.0/default/service.cpp
new file mode 100644
index 0000000..5a8acc1
--- /dev/null
+++ b/gnss/1.0/default/service.cpp
@@ -0,0 +1,12 @@
+#define LOG_TAG "android.hardware.gnss@1.0-service"
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IGnss>();
+}
diff --git a/gnss/1.0/types.hal b/gnss/1.0/types.hal
new file mode 100644
index 0000000..d5e0e9b
--- /dev/null
+++ b/gnss/1.0/types.hal
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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.gnss@1.0;
+
+@export(name="", value_prefix="GNSS_MAX_")
+enum GnssMax : uint32_t {
+/** Maximum number of SVs for gnssSvStatusCb(). */
+ SVS_COUNT = 64,
+};
+
+/* Milliseconds since January 1, 1970 */
+typedef int64_t GnssUtcTime;
+
+/*
+ * Constellation type of GnssSvInfo
+ */
+
+@export(name="", value_prefix="GNSS_CONSTELLATION_")
+enum GnssConstellationType : uint8_t {
+ UNKNOWN = 0,
+ GPS = 1,
+ SBAS = 2,
+ GLONASS = 3,
+ QZSS = 4,
+ BEIDOU = 5,
+ GALILEO = 6,
+};
+
+/** Bit mask to indicate which values are valid in a GnssLocation object. */
+@export(name="", value_prefix="GPS_LOCATION_")
+enum GnssLocationFlags : uint16_t {
+ /** GnssLocation has valid latitude and longitude. */
+ HAS_LAT_LONG = 0x0001,
+ /** GnssLocation has valid altitude. */
+ HAS_ALTITUDE = 0x0002,
+ /** GnssLocation has valid speed. */
+ HAS_SPEED = 0x0004,
+ /** GnssLocation has valid bearing. */
+ HAS_BEARING = 0x0008,
+ /** GpsLocation has valid horizontal accuracy. */
+ HAS_HORIZONTAL_ACCURACY = 0x0010,
+ /** GpsLocation has valid vertical accuracy. */
+ HAS_VERTICAL_ACCURACY = 0x0020,
+ /** GpsLocation has valid speed accuracy. */
+ HAS_SPEED_ACCURACY = 0x0040,
+ /** GpsLocation has valid bearing accuracy. */
+ HAS_BEARING_ACCURACY = 0x0080
+};
+
+/* Represents a location. */
+struct GnssLocation {
+ /* Contains GnssLocationFlags bits. */
+ bitfield<GnssLocationFlags> gnssLocationFlags;
+
+ /* Represents latitude in degrees. */
+ double latitudeDegrees;
+
+ /* Represents longitude in degrees. */
+ double longitudeDegrees;
+
+ /*
+ * Represents altitude in meters above the WGS 84 reference ellipsoid.
+ */
+ double altitudeMeters;
+
+ /* Represents speed in meters per second. */
+ float speedMetersPerSec;
+
+ /* Represents heading in degrees. */
+ float bearingDegrees;
+
+ /*
+ * Represents expected horizontal position accuracy, radial, in meters
+ * (68% confidence).
+ */
+ float horizontalAccuracyMeters;
+
+ /*
+ * Represents expected vertical position accuracy in meters
+ * (68% confidence).
+ */
+ float verticalAccuracyMeters;
+
+ /*
+ * Represents expected speed accuracy in meter per seconds
+ * (68% confidence).
+ */
+ float speedAccuracyMetersPerSecond;
+
+ /*
+ * Represents expected bearing accuracy in degrees
+ * (68% confidence).
+ */
+ float bearingAccuracyDegrees;
+
+ /* Timestamp for the location fix. */
+ GnssUtcTime timestamp;
+};
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..6d96059
--- /dev/null
+++ b/gnss/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalGnssV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGnssV1_0TargetTest.cpp"],
+ shared_libs: [
+ "android.hardware.gnss@1.0",
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libnativehelper",
+ "libutils",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
\ No newline at end of file
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
new file mode 100644
index 0000000..21b7136
--- /dev/null
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "VtsHalGnssV1_0TargetTest"
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/log.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V1_0::IGnss;
+using android::hardware::gnss::V1_0::IGnssCallback;
+using android::sp;
+
+#define TIMEOUT_SEC 3 // for basic commands/responses
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ // Clean between tests
+ capabilities_called_count_ = 0;
+ location_called_count_ = 0;
+ info_called_count_ = 0;
+
+ gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
+ ASSERT_NE(gnss_hal_, nullptr);
+
+ gnss_cb_ = new GnssCallback(*this);
+ ASSERT_NE(gnss_cb_, nullptr);
+
+ auto result = gnss_hal_->setCallback(gnss_cb_);
+ if (!result.isOk()) {
+ ALOGE("result of failed setCallback %s", result.description().c_str());
+ }
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ /*
+ * At least one callback should trigger - it may be capabilites, or
+ * system info first, so wait again if capabilities not received.
+ */
+ EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ if (capabilities_called_count_ == 0) {
+ EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ }
+
+ /*
+ * Generally should be 1 capabilites callback -
+ * or possibly 2 in some recovery cases (default cached & refreshed)
+ */
+ EXPECT_GE(capabilities_called_count_, 1);
+ EXPECT_LE(capabilities_called_count_, 2);
+
+ /*
+ * Clear notify/waiting counter, allowing up till the timeout after
+ * the last reply for final startup messages to arrive (esp. system
+ * info.)
+ */
+ while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+ }
+ }
+
+ virtual void TearDown() override {
+ if (gnss_hal_ != nullptr) {
+ gnss_hal_->cleanup();
+ }
+ }
+
+ /* Used as a mechanism to inform the test that a callback has occurred */
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ count++;
+ cv_.notify_one();
+ }
+
+ /* Test code calls this function to wait for a callback */
+ inline std::cv_status wait(int timeoutSeconds) {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count == 0) {
+ status = cv_.wait_until(lock, now + std::chrono::seconds(timeoutSeconds));
+ if (status == std::cv_status::timeout) return status;
+ }
+ count--;
+ return status;
+ }
+
+ /* Callback class for data & Event. */
+ class GnssCallback : public IGnssCallback {
+ public:
+ GnssHalTest& parent_;
+
+ GnssCallback(GnssHalTest& parent) : parent_(parent){};
+
+ virtual ~GnssCallback() = default;
+
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(
+ const IGnssCallback::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssSvStatusCb(
+ const IGnssCallback::GnssSvStatus& /* svStatus */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(
+ int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+
+ // Actual (test) callback handlers
+ Return<void> gnssLocationCb(const GnssLocation& location) override {
+ ALOGI("Location received");
+ parent_.location_called_count_++;
+ parent_.last_location_ = location;
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override {
+ ALOGI("Capabilities received %d", capabilities);
+ parent_.capabilities_called_count_++;
+ parent_.last_capabilities_ = capabilities;
+ parent_.notify();
+ return Void();
+ }
+
+ Return<void> gnssSetSystemInfoCb(
+ const IGnssCallback::GnssSystemInfo& info) override {
+ ALOGI("Info received, year %d", info.yearOfHw);
+ parent_.info_called_count_++;
+ parent_.last_info_ = info;
+ parent_.notify();
+ return Void();
+ }
+ };
+
+ sp<IGnss> gnss_hal_; // GNSS HAL to call into
+ sp<IGnssCallback> gnss_cb_; // Primary callback interface
+
+ /* Count of calls to set the following items, and the latest item (used by
+ * test.)
+ */
+ int capabilities_called_count_;
+ uint32_t last_capabilities_;
+
+ int location_called_count_;
+ GnssLocation last_location_;
+
+ int info_called_count_;
+ IGnssCallback::GnssSystemInfo last_info_;
+
+ private:
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count;
+};
+
+/*
+ * SetCallbackCapabilitiesCleanup:
+ * Sets up the callback, awaits the capabilities, and calls cleanup
+ *
+ * Since this is just the basic operation of SetUp() and TearDown(),
+ * the function definition is intentionally empty
+ */
+TEST_F(GnssHalTest, SetCallbackCapabilitiesCleanup) {}
+
+/*
+ * CheckLocation:
+ * Helper function to vet Location fields
+ */
+
+void CheckLocation(GnssLocation& location, bool checkAccuracies) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
+ EXPECT_TRUE(location.gnssLocationFlags &
+ GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+ // New uncertainties available in O must be provided,
+ // at least when paired with modern hardware (2017+)
+ if (checkAccuracies) {
+ EXPECT_TRUE(location.gnssLocationFlags &
+ GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+ EXPECT_TRUE(location.gnssLocationFlags &
+ GnssLocationFlags::HAS_SPEED_ACCURACY);
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ EXPECT_TRUE(location.gnssLocationFlags &
+ GnssLocationFlags::HAS_BEARING_ACCURACY);
+ }
+ }
+ EXPECT_GE(location.latitudeDegrees, -90.0);
+ EXPECT_LE(location.latitudeDegrees, 90.0);
+ EXPECT_GE(location.longitudeDegrees, -180.0);
+ EXPECT_LE(location.longitudeDegrees, 180.0);
+ EXPECT_GE(location.altitudeMeters, -1000.0);
+ EXPECT_LE(location.altitudeMeters, 30000.0);
+ EXPECT_GE(location.speedMetersPerSec, 0.0);
+ EXPECT_LE(location.speedMetersPerSec, 5.0); // VTS tests are stationary.
+
+ // Non-zero speeds must be reported with an associated bearing
+ if (location.speedMetersPerSec > 0.0) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
+ }
+
+ /*
+ * Tolerating some especially high values for accuracy estimate, in case of
+ * first fix with especially poor geometry (happens occasionally)
+ */
+ EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+ EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+ /*
+ * Some devices may define bearing as -180 to +180, others as 0 to 360.
+ * Both are okay & understandable.
+ */
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ EXPECT_GE(location.bearingDegrees, -180.0);
+ EXPECT_LE(location.bearingDegrees, 360.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+ EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+ EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+ EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+ }
+
+ // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+ EXPECT_GT(location.timestamp, 1.48e12);
+}
+
+/*
+ * GetLocation:
+ * Turns on location, waits 45 second for at least 5 locations,
+ * and checks them for reasonable validity.
+ */
+TEST_F(GnssHalTest, GetLocation) {
+#define MIN_INTERVAL_MSEC 500
+#define PREFERRED_ACCURACY 0 // Ideally perfect (matches GnssLocationProvider)
+#define PREFERRED_TIME_MSEC 0 // Ideally immediate
+
+#define LOCATION_TIMEOUT_FIRST_SEC 45
+#define LOCATION_TIMEOUT_SUBSEQUENT_SEC 3
+#define LOCATIONS_TO_CHECK 5
+
+ bool checkMoreAccuracies =
+ (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+
+ auto result = gnss_hal_->setPositionMode(
+ IGnss::GnssPositionMode::MS_BASED,
+ IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, MIN_INTERVAL_MSEC,
+ PREFERRED_ACCURACY, PREFERRED_TIME_MSEC);
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ result = gnss_hal_->start();
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ // GPS signals initially optional for this test, so don't expect no timeout
+ // yet
+ wait(LOCATION_TIMEOUT_FIRST_SEC);
+ if (location_called_count_ > 0) {
+ CheckLocation(last_location_, checkMoreAccuracies);
+ }
+
+ for (int i = 1; i < LOCATIONS_TO_CHECK; i++) {
+ wait(LOCATION_TIMEOUT_SUBSEQUENT_SEC);
+ if (location_called_count_ > 0) {
+ CheckLocation(last_location_, checkMoreAccuracies);
+ }
+ }
+
+ result = gnss_hal_->stop();
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
\ No newline at end of file
diff --git a/gnss/Android.bp b/gnss/Android.bp
new file mode 100644
index 0000000..33f70eb
--- /dev/null
+++ b/gnss/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/vts/functional",
+]
diff --git a/graphics/Android.bp b/graphics/Android.bp
new file mode 100644
index 0000000..f4f7db4
--- /dev/null
+++ b/graphics/Android.bp
@@ -0,0 +1,14 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "allocator/2.0",
+ "allocator/2.0/default",
+ "allocator/2.0/vts/functional",
+ "bufferqueue/1.0",
+ "common/1.0",
+ "composer/2.1",
+ "composer/2.1/default",
+ "composer/2.1/vts/functional",
+ "mapper/2.0",
+ "mapper/2.0/default",
+ "mapper/2.0/vts/functional",
+]
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp
new file mode 100644
index 0000000..69ddd9b
--- /dev/null
+++ b/graphics/allocator/2.0/Android.bp
@@ -0,0 +1,71 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.allocator@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IAllocator.hal",
+ "IAllocatorClient.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.allocator@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.allocator@2.0",
+ srcs: [
+ ":android.hardware.graphics.allocator@2.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/allocator/2.0/types.cpp",
+ "android/hardware/graphics/allocator/2.0/AllocatorAll.cpp",
+ "android/hardware/graphics/allocator/2.0/AllocatorClientAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.allocator@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.allocator@2.0",
+ srcs: [
+ ":android.hardware.graphics.allocator@2.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/allocator/2.0/types.h",
+ "android/hardware/graphics/allocator/2.0/IAllocator.h",
+ "android/hardware/graphics/allocator/2.0/IHwAllocator.h",
+ "android/hardware/graphics/allocator/2.0/BnHwAllocator.h",
+ "android/hardware/graphics/allocator/2.0/BpHwAllocator.h",
+ "android/hardware/graphics/allocator/2.0/BsAllocator.h",
+ "android/hardware/graphics/allocator/2.0/IAllocatorClient.h",
+ "android/hardware/graphics/allocator/2.0/IHwAllocatorClient.h",
+ "android/hardware/graphics/allocator/2.0/BnHwAllocatorClient.h",
+ "android/hardware/graphics/allocator/2.0/BpHwAllocatorClient.h",
+ "android/hardware/graphics/allocator/2.0/BsAllocatorClient.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.allocator@2.0",
+ generated_sources: ["android.hardware.graphics.allocator@2.0_genc++"],
+ generated_headers: ["android.hardware.graphics.allocator@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.allocator@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/graphics/allocator/2.0/Android.mk b/graphics/allocator/2.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/allocator/2.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/allocator/2.0/IAllocator.hal b/graphics/allocator/2.0/IAllocator.hal
new file mode 100644
index 0000000..00d07d5
--- /dev/null
+++ b/graphics/allocator/2.0/IAllocator.hal
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.graphics.allocator@2.0;
+
+import IAllocatorClient;
+
+interface IAllocator {
+ enum Capability : int32_t {
+ /* reserved */
+ INVALID = 0,
+
+ /*
+ * IAllocatorClient::testAllocate must always return UNDEFINED unless
+ * this capability is supported.
+ */
+ TEST_ALLOCATE = 1,
+
+ /*
+ * IAllocatorClient::BufferDescriptorInfo::layerCount must be 1 unless
+ * this capability is supported.
+ */
+ LAYERED_BUFFERS = 2,
+ };
+
+ /*
+ * Provides a list of supported capabilities (as described in the
+ * definition of Capability above). This list must not change after
+ * initialization.
+ *
+ * @return capabilities is a list of supported capabilities.
+ */
+ @entry
+ @exit
+ @callflow(next="*")
+ getCapabilities() generates (vec<Capability> capabilities);
+
+ /*
+ * Retrieves implementation-defined debug information, which will be
+ * displayed during, for example, `dumpsys SurfaceFlinger`.
+ *
+ * @return debugInfo is a string of debug information.
+ */
+ @entry
+ @exit
+ @callflow(next="*")
+ dumpDebugInfo() generates (string debugInfo);
+
+ /*
+ * Creates a client of the allocator. All resources created by the client
+ * are owned by the client and are only visible to the client, unless they
+ * are exported by exportHandle.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when no more client can currently be created.
+ * @return client is the newly created client.
+ */
+ @entry
+ @callflow(next="*")
+ createClient() generates (Error error, IAllocatorClient client);
+};
diff --git a/graphics/allocator/2.0/IAllocatorClient.hal b/graphics/allocator/2.0/IAllocatorClient.hal
new file mode 100644
index 0000000..080e3ea
--- /dev/null
+++ b/graphics/allocator/2.0/IAllocatorClient.hal
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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.graphics.allocator@2.0;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+
+interface IAllocatorClient {
+ struct BufferDescriptorInfo {
+ /*
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ uint32_t width;
+
+ /*
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ uint32_t height;
+
+ /*
+ * The number of image layers that must be in the allocated buffer.
+ */
+ uint32_t layerCount;
+
+ /* Buffer pixel format. */
+ PixelFormat format;
+
+ /*
+ * Buffer producer usage mask; valid flags can be found in the
+ * definition of ProducerUsage.
+ */
+ uint64_t producerUsageMask;
+
+ /*
+ * Buffer consumer usage mask; valid flags can be found in the
+ * definition of ConsumerUsage.
+ */
+ uint64_t consumerUsageMask;
+ };
+
+ /*
+ * Creates a new, opaque buffer descriptor.
+ *
+ * @param descriptorInfo specifies the attributes of the buffer
+ * descriptor.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_VALUE when any attribute in descriptorInfo is invalid.
+ * NO_RESOURCES when no more descriptors can currently be created.
+ * @return descriptor is the newly created buffer descriptor.
+ */
+ @entry
+ @callflow(next="*")
+ createDescriptor(BufferDescriptorInfo descriptorInfo)
+ generates (Error error,
+ BufferDescriptor descriptor);
+
+ /*
+ * Destroys an existing buffer descriptor.
+ *
+ * @param descriptor is the descriptor to destroy.
+ * @return error is either NONE or BAD_DESCRIPTOR.
+ */
+ @exit
+ @callflow(next="*")
+ destroyDescriptor(BufferDescriptor descriptor) generates (Error error);
+
+ /*
+ * Tests whether a buffer allocation can succeed, ignoring potential
+ * resource contention which might lead to a NO_RESOURCES error.
+ *
+ * @param descriptors is a list of buffer descriptors.
+ * @return error is NONE or NOT_SHARED upon success;
+ * NONE when buffers can be created and share a backing store.
+ * NOT_SHARED when buffers can be created but require more than a
+ * backing store.
+ * Otherwise,
+ * BAD_DESCRIPTOR when any of the descriptors is invalid.
+ * UNSUPPORTED when any of the descriptors can never be satisfied.
+ * UNDEFINED when TEST_ALLOCATE is not listed in getCapabilities.
+ */
+ @callflow(next="allocate")
+ testAllocate(vec<BufferDescriptor> descriptors) generates (Error error);
+
+ /*
+ * Attempts to allocate a list of buffers sharing a backing store.
+ *
+ * Each buffer must correspond to one of the descriptors passed into the
+ * function and must hold a reference to its backing store. If the device
+ * is unable to share the backing store between the buffers, it must
+ * attempt to allocate the buffers with different backing stores and
+ * return NOT_SHARED if it is successful.
+ *
+ * @param descriptors is the buffer descriptors to attempt to allocate.
+ * @return error is NONE or NOT_SHARED upon success;
+ * NONE when buffers can be created and share a backing store.
+ * NOT_SHARED when buffers can be created but require more than a
+ * backing store.
+ * Otherwise,
+ * BAD_DESCRIPTOR when any of the descriptors is invalid.
+ * UNSUPPORTED when any of the descriptors can never be satisfied.
+ * NO_RESOURCES when any of the buffers cannot be created at this
+ * time.
+ * @return buffers is the allocated buffers.
+ */
+ @callflow(next="exportHandle")
+ allocate(vec<BufferDescriptor> descriptors)
+ generates (Error error,
+ vec<Buffer> buffers);
+
+ /*
+ * Frees a buffer.
+ *
+ * @param buffer is the buffer to be freed.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer is invalid.
+ */
+ @exit
+ @callflow(next="*")
+ free(Buffer buffer) generates (Error error);
+
+ /*
+ * Exports a buffer for use in other client libraries or for cross-process
+ * sharing.
+ *
+ * The exported handle is a handle to the backing store of the buffer, not
+ * to the buffer itself. It however may not hold any reference to the
+ * backing store and may be considered invalid by client libraries. To use
+ * it and, in most cases, to save it for later use, a client must make a
+ * clone of the handle and have the cloned handle hold a reference to the
+ * backing store. Such a cloned handle will stay valid even after the
+ * original buffer is freed. Refer to native_handle_clone and IMapper for
+ * how a handle is cloned and how a reference is added.
+ *
+ * @param descriptor is the descriptor used to allocate the buffer.
+ * @param buffer is the buffer to be exported.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DESCRIPTOR when the descriptor is invalid.
+ * BAD_BUFFER when the buffer is invalid.
+ * BAD_VALUE when descriptor and buffer do not match.
+ * NO_RESOURCES when the buffer cannot be exported at this time.
+ * @return bufferHandle is the exported handle.
+ */
+ @callflow(next="free")
+ exportHandle(BufferDescriptor descriptor,
+ Buffer buffer)
+ generates (Error error,
+ handle bufferHandle);
+};
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp
new file mode 100644
index 0000000..b8d4fde
--- /dev/null
+++ b/graphics/allocator/2.0/default/Android.bp
@@ -0,0 +1,44 @@
+cc_library_shared {
+ name: "android.hardware.graphics.allocator@2.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Gralloc.cpp"],
+ cppflags: ["-Wall", "-Wextra"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.graphics.allocator@2.0-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.allocator@2.0-service.rc"],
+
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_library_static {
+ name: "libgralloc1-adapter",
+ defaults: ["hidl_defaults"],
+ srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"],
+ include_dirs: ["system/core/libsync/include"],
+ cflags: ["-Wall", "-Wextra", "-Wno-unused-parameter"],
+ export_include_dirs: ["."],
+}
diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp
new file mode 100644
index 0000000..0b9e863
--- /dev/null
+++ b/graphics/allocator/2.0/default/Gralloc.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "GrallocPassthrough"
+
+#include <mutex>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+#include <string.h>
+
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+
+#include "Gralloc.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace implementation {
+
+class GrallocHal : public IAllocator {
+public:
+ GrallocHal(const hw_module_t* module);
+ virtual ~GrallocHal();
+
+ // IAllocator interface
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+
+ Error createDescriptor(
+ const IAllocatorClient::BufferDescriptorInfo& descriptorInfo,
+ BufferDescriptor* outDescriptor);
+ Error destroyDescriptor(BufferDescriptor descriptor);
+
+ Error testAllocate(const hidl_vec<BufferDescriptor>& descriptors);
+ Error allocate(const hidl_vec<BufferDescriptor>& descriptors,
+ hidl_vec<Buffer>* outBuffers);
+ Error free(Buffer buffer);
+
+ Error exportHandle(Buffer buffer, const native_handle_t** outHandle);
+
+private:
+ void initCapabilities();
+
+ template<typename T>
+ void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
+ void initDispatch();
+
+ bool hasCapability(Capability capability) const;
+
+ gralloc1_device_t* mDevice;
+
+ std::unordered_set<Capability> mCapabilities;
+
+ struct {
+ GRALLOC1_PFN_DUMP dump;
+ GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
+ GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
+ GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
+ GRALLOC1_PFN_SET_FORMAT setFormat;
+ GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
+ GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
+ GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
+ GRALLOC1_PFN_ALLOCATE allocate;
+ GRALLOC1_PFN_RELEASE release;
+ } mDispatch;
+};
+
+class GrallocClient : public IAllocatorClient {
+public:
+ GrallocClient(GrallocHal& hal);
+ virtual ~GrallocClient();
+
+ // IAllocatorClient interface
+ Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
+ createDescriptor_cb hidl_cb) override;
+ Return<Error> destroyDescriptor(BufferDescriptor descriptor) override;
+
+ Return<Error> testAllocate(
+ const hidl_vec<BufferDescriptor>& descriptors) override;
+ Return<void> allocate(const hidl_vec<BufferDescriptor>& descriptors,
+ allocate_cb hidl_cb) override;
+ Return<Error> free(Buffer buffer) override;
+
+ Return<void> exportHandle(BufferDescriptor descriptor,
+ Buffer buffer, exportHandle_cb hidl_cb) override;
+
+private:
+ GrallocHal& mHal;
+
+ std::mutex mMutex;
+ std::unordered_set<BufferDescriptor> mDescriptors;
+ std::unordered_set<Buffer> mBuffers;
+};
+
+GrallocHal::GrallocHal(const hw_module_t* module)
+ : mDevice(nullptr), mDispatch()
+{
+ int status = gralloc1_open(module, &mDevice);
+ if (status) {
+ LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
+ strerror(-status));
+ }
+
+ initCapabilities();
+ initDispatch();
+}
+
+GrallocHal::~GrallocHal()
+{
+ gralloc1_close(mDevice);
+}
+
+void GrallocHal::initCapabilities()
+{
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<Capability> caps(count);
+ mDevice->getCapabilities(mDevice, &count, reinterpret_cast<
+ std::underlying_type<Capability>::type*>(caps.data()));
+ caps.resize(count);
+
+ mCapabilities.insert(caps.cbegin(), caps.cend());
+}
+
+template<typename T>
+void GrallocHal::initDispatch(gralloc1_function_descriptor_t desc, T* outPfn)
+{
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
+ }
+
+ *outPfn = reinterpret_cast<T>(pfn);
+}
+
+void GrallocHal::initDispatch()
+{
+ initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump);
+ initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR,
+ &mDispatch.createDescriptor);
+ initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR,
+ &mDispatch.destroyDescriptor);
+ initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions);
+ initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat);
+ if (hasCapability(Capability::LAYERED_BUFFERS)) {
+ initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT,
+ &mDispatch.setLayerCount);
+ }
+ initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE,
+ &mDispatch.setConsumerUsage);
+ initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE,
+ &mDispatch.setProducerUsage);
+ initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate);
+ initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
+}
+
+bool GrallocHal::hasCapability(Capability capability) const
+{
+ return (mCapabilities.count(capability) > 0);
+}
+
+Return<void> GrallocHal::getCapabilities(getCapabilities_cb hidl_cb)
+{
+ std::vector<Capability> caps(
+ mCapabilities.cbegin(), mCapabilities.cend());
+
+ hidl_vec<Capability> reply;
+ reply.setToExternal(caps.data(), caps.size());
+ hidl_cb(reply);
+
+ return Void();
+}
+
+Return<void> GrallocHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb)
+{
+ uint32_t len = 0;
+ mDispatch.dump(mDevice, &len, nullptr);
+
+ std::vector<char> buf(len + 1);
+ mDispatch.dump(mDevice, &len, buf.data());
+ buf.resize(len + 1);
+ buf[len] = '\0';
+
+ hidl_string reply;
+ reply.setToExternal(buf.data(), len);
+ hidl_cb(reply);
+
+ return Void();
+}
+
+Return<void> GrallocHal::createClient(createClient_cb hidl_cb)
+{
+ sp<IAllocatorClient> client = new GrallocClient(*this);
+ hidl_cb(Error::NONE, client);
+
+ return Void();
+}
+
+Error GrallocHal::createDescriptor(
+ const IAllocatorClient::BufferDescriptorInfo& descriptorInfo,
+ BufferDescriptor* outDescriptor)
+{
+ gralloc1_buffer_descriptor_t descriptor;
+ int32_t err = mDispatch.createDescriptor(mDevice, &descriptor);
+ if (err != GRALLOC1_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ err = mDispatch.setDimensions(mDevice, descriptor,
+ descriptorInfo.width, descriptorInfo.height);
+ if (err == GRALLOC1_ERROR_NONE) {
+ err = mDispatch.setFormat(mDevice, descriptor,
+ static_cast<int32_t>(descriptorInfo.format));
+ }
+ if (err == GRALLOC1_ERROR_NONE) {
+ if (hasCapability(Capability::LAYERED_BUFFERS)) {
+ err = mDispatch.setLayerCount(mDevice, descriptor,
+ descriptorInfo.layerCount);
+ } else if (descriptorInfo.layerCount != 1) {
+ err = GRALLOC1_ERROR_BAD_VALUE;
+ }
+ }
+ if (err == GRALLOC1_ERROR_NONE) {
+ uint64_t producerUsageMask = descriptorInfo.producerUsageMask;
+ if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN) {
+ producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
+ }
+ if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) {
+ producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+ }
+ err = mDispatch.setProducerUsage(mDevice, descriptor,
+ descriptorInfo.producerUsageMask);
+ }
+ if (err == GRALLOC1_ERROR_NONE) {
+ uint64_t consumerUsageMask = descriptorInfo.consumerUsageMask;
+ if (consumerUsageMask & GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) {
+ consumerUsageMask |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
+ }
+ err = mDispatch.setConsumerUsage(mDevice, descriptor,
+ consumerUsageMask);
+ }
+
+ if (err == GRALLOC1_ERROR_NONE) {
+ *outDescriptor = descriptor;
+ } else {
+ mDispatch.destroyDescriptor(mDevice, descriptor);
+ }
+
+ return static_cast<Error>(err);
+}
+
+Error GrallocHal::destroyDescriptor(BufferDescriptor descriptor)
+{
+ int32_t err = mDispatch.destroyDescriptor(mDevice, descriptor);
+ return static_cast<Error>(err);
+}
+
+Error GrallocHal::testAllocate(const hidl_vec<BufferDescriptor>& descriptors)
+{
+ if (!hasCapability(Capability::TEST_ALLOCATE)) {
+ return Error::UNDEFINED;
+ }
+
+ int32_t err = mDispatch.allocate(mDevice, descriptors.size(),
+ descriptors.data(), nullptr);
+ return static_cast<Error>(err);
+}
+
+Error GrallocHal::allocate(const hidl_vec<BufferDescriptor>& descriptors,
+ hidl_vec<Buffer>* outBuffers)
+{
+ std::vector<buffer_handle_t> buffers(descriptors.size());
+ int32_t err = mDispatch.allocate(mDevice, descriptors.size(),
+ descriptors.data(), buffers.data());
+ if (err == GRALLOC1_ERROR_NONE || err == GRALLOC1_ERROR_NOT_SHARED) {
+ outBuffers->resize(buffers.size());
+ for (size_t i = 0; i < outBuffers->size(); i++) {
+ (*outBuffers)[i] = static_cast<Buffer>(
+ reinterpret_cast<uintptr_t>(buffers[i]));
+ }
+ }
+
+ return static_cast<Error>(err);
+}
+
+Error GrallocHal::free(Buffer buffer)
+{
+ buffer_handle_t handle = reinterpret_cast<buffer_handle_t>(
+ static_cast<uintptr_t>(buffer));
+
+ int32_t err = mDispatch.release(mDevice, handle);
+ return static_cast<Error>(err);
+}
+
+Error GrallocHal::exportHandle(Buffer buffer,
+ const native_handle_t** outHandle)
+{
+ // we rely on the caller to validate buffer here
+ *outHandle = reinterpret_cast<buffer_handle_t>(
+ static_cast<uintptr_t>(buffer));
+ return Error::NONE;
+}
+
+GrallocClient::GrallocClient(GrallocHal& hal)
+ : mHal(hal)
+{
+}
+
+GrallocClient::~GrallocClient()
+{
+ if (!mBuffers.empty()) {
+ ALOGW("client destroyed with valid buffers");
+ for (auto buf : mBuffers) {
+ mHal.free(buf);
+ }
+ }
+
+ if (!mDescriptors.empty()) {
+ ALOGW("client destroyed with valid buffer descriptors");
+ for (auto desc : mDescriptors) {
+ mHal.destroyDescriptor(desc);
+ }
+ }
+}
+
+Return<void> GrallocClient::createDescriptor(
+ const BufferDescriptorInfo& descriptorInfo,
+ createDescriptor_cb hidl_cb)
+{
+ BufferDescriptor descriptor = 0;
+ Error err = mHal.createDescriptor(descriptorInfo, &descriptor);
+
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto result = mDescriptors.insert(descriptor);
+ if (!result.second) {
+ ALOGW("duplicated buffer descriptor id returned");
+ mHal.destroyDescriptor(descriptor);
+ err = Error::NO_RESOURCES;
+ }
+ }
+
+ hidl_cb(err, descriptor);
+ return Void();
+}
+
+Return<Error> GrallocClient::destroyDescriptor(BufferDescriptor descriptor)
+{
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mDescriptors.erase(descriptor)) {
+ return Error::BAD_DESCRIPTOR;
+ }
+ }
+
+ return mHal.destroyDescriptor(descriptor);
+}
+
+Return<Error> GrallocClient::testAllocate(
+ const hidl_vec<BufferDescriptor>& descriptors)
+{
+ return mHal.testAllocate(descriptors);
+}
+
+Return<void> GrallocClient::allocate(
+ const hidl_vec<BufferDescriptor>& descriptors,
+ allocate_cb hidl_cb) {
+ hidl_vec<Buffer> buffers;
+ Error err = mHal.allocate(descriptors, &buffers);
+
+ if (err == Error::NONE || err == Error::NOT_SHARED) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ for (size_t i = 0; i < buffers.size(); i++) {
+ auto result = mBuffers.insert(buffers[i]);
+ if (!result.second) {
+ ALOGW("duplicated buffer id returned");
+
+ for (size_t j = 0; j < buffers.size(); j++) {
+ if (j < i) {
+ mBuffers.erase(buffers[i]);
+ }
+ mHal.free(buffers[i]);
+ }
+
+ buffers = hidl_vec<Buffer>();
+ err = Error::NO_RESOURCES;
+ break;
+ }
+ }
+ }
+
+ hidl_cb(err, buffers);
+ return Void();
+}
+
+Return<Error> GrallocClient::free(Buffer buffer)
+{
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mBuffers.erase(buffer)) {
+ return Error::BAD_BUFFER;
+ }
+ }
+
+ return mHal.free(buffer);
+}
+
+Return<void> GrallocClient::exportHandle(BufferDescriptor /*descriptor*/,
+ Buffer buffer, exportHandle_cb hidl_cb)
+{
+ const native_handle_t* handle = nullptr;
+
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mBuffers.count(buffer) == 0) {
+ hidl_cb(Error::BAD_BUFFER, handle);
+ return Void();
+ }
+ }
+
+ Error err = mHal.exportHandle(buffer, &handle);
+
+ hidl_cb(err, handle);
+ return Void();
+}
+
+IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
+ const hw_module_t* module = nullptr;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return nullptr;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major != 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return nullptr;
+ }
+
+ return new GrallocHal(module);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc.h b/graphics/allocator/2.0/default/Gralloc.h
new file mode 100644
index 0000000..c79eeaa
--- /dev/null
+++ b/graphics/allocator/2.0/default/Gralloc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
+#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace implementation {
+
+extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp b/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
new file mode 100644
index 0000000..4b9c9e1
--- /dev/null
+++ b/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
@@ -0,0 +1,560 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Gralloc1On0Adapter"
+//#define LOG_NDEBUG 0
+
+#include "Gralloc1On0Adapter.h"
+#include "gralloc1-adapter.h"
+
+#include <hardware/gralloc.h>
+
+#include <utils/Log.h>
+#include <sync/sync.h>
+
+#include <inttypes.h>
+
+template <typename PFN, typename T>
+static gralloc1_function_pointer_t asFP(T function)
+{
+ static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+ return reinterpret_cast<gralloc1_function_pointer_t>(function);
+}
+
+namespace android {
+namespace hardware {
+
+Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module)
+ : gralloc1_device_t(),
+ mModule(reinterpret_cast<const gralloc_module_t*>(module)),
+ mDevice(nullptr)
+{
+ ALOGV("Constructing");
+
+ int minor = 0;
+ mModule->perform(mModule,
+ GRALLOC1_ADAPTER_PERFORM_GET_REAL_MODULE_API_VERSION_MINOR,
+ &minor);
+ mMinorVersion = minor;
+
+ common.tag = HARDWARE_DEVICE_TAG,
+ common.version = HARDWARE_DEVICE_API_VERSION(0, 0),
+ common.module = const_cast<struct hw_module_t*>(module),
+ common.close = closeHook,
+
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ int error = ::gralloc_open(&(mModule->common), &mDevice);
+ if (error) {
+ ALOGE("Failed to open gralloc0 module: %d", error);
+ }
+ ALOGV("Opened gralloc0 device %p", mDevice);
+}
+
+Gralloc1On0Adapter::~Gralloc1On0Adapter()
+{
+ ALOGV("Destructing");
+ if (mDevice) {
+ ALOGV("Closing gralloc0 device %p", mDevice);
+ ::gralloc_close(mDevice);
+ }
+}
+
+void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount,
+ int32_t* outCapabilities)
+{
+ *outCount = 0;
+}
+
+gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction(
+ int32_t intDescriptor)
+{
+ constexpr auto lastDescriptor =
+ static_cast<int32_t>(GRALLOC1_LAST_FUNCTION);
+ if (intDescriptor < 0 || intDescriptor > lastDescriptor) {
+ ALOGE("Invalid function descriptor");
+ return nullptr;
+ }
+
+ auto descriptor =
+ static_cast<gralloc1_function_descriptor_t>(intDescriptor);
+ switch (descriptor) {
+ case GRALLOC1_FUNCTION_DUMP:
+ return asFP<GRALLOC1_PFN_DUMP>(dumpHook);
+ case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR:
+ return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook);
+ case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR:
+ return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook);
+ case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE:
+ return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook);
+ case GRALLOC1_FUNCTION_SET_DIMENSIONS:
+ return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook);
+ case GRALLOC1_FUNCTION_SET_FORMAT:
+ return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook);
+ case GRALLOC1_FUNCTION_SET_LAYER_COUNT:
+ return asFP<GRALLOC1_PFN_SET_LAYER_COUNT>(setLayerCountHook);
+ case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE:
+ return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook);
+ case GRALLOC1_FUNCTION_GET_BACKING_STORE:
+ return asFP<GRALLOC1_PFN_GET_BACKING_STORE>(
+ bufferHook<decltype(&Buffer::getBackingStore),
+ &Buffer::getBackingStore, gralloc1_backing_store_t*>);
+ case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE:
+ return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook);
+ case GRALLOC1_FUNCTION_GET_DIMENSIONS:
+ return asFP<GRALLOC1_PFN_GET_DIMENSIONS>(
+ bufferHook<decltype(&Buffer::getDimensions),
+ &Buffer::getDimensions, uint32_t*, uint32_t*>);
+ case GRALLOC1_FUNCTION_GET_FORMAT:
+ return asFP<GRALLOC1_PFN_GET_FORMAT>(
+ bufferHook<decltype(&Buffer::getFormat),
+ &Buffer::getFormat, int32_t*>);
+ case GRALLOC1_FUNCTION_GET_LAYER_COUNT:
+ return asFP<GRALLOC1_PFN_GET_LAYER_COUNT>(
+ bufferHook<decltype(&Buffer::getLayerCount),
+ &Buffer::getLayerCount, uint32_t*>);
+ case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE:
+ return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook);
+ case GRALLOC1_FUNCTION_GET_STRIDE:
+ return asFP<GRALLOC1_PFN_GET_STRIDE>(
+ bufferHook<decltype(&Buffer::getStride),
+ &Buffer::getStride, uint32_t*>);
+ case GRALLOC1_FUNCTION_ALLOCATE:
+ if (mDevice != nullptr) {
+ return asFP<GRALLOC1_PFN_ALLOCATE>(allocateHook);
+ } else {
+ return nullptr;
+ }
+ case GRALLOC1_FUNCTION_RETAIN:
+ return asFP<GRALLOC1_PFN_RETAIN>(retainHook);
+ case GRALLOC1_FUNCTION_RELEASE:
+ return asFP<GRALLOC1_PFN_RELEASE>(releaseHook);
+ case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES:
+ return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>(
+ bufferHook<decltype(&Buffer::getNumFlexPlanes),
+ &Buffer::getNumFlexPlanes, uint32_t*>);
+ case GRALLOC1_FUNCTION_LOCK:
+ return asFP<GRALLOC1_PFN_LOCK>(
+ lockHook<void*, &Gralloc1On0Adapter::lock>);
+ case GRALLOC1_FUNCTION_LOCK_FLEX:
+ return asFP<GRALLOC1_PFN_LOCK_FLEX>(
+ lockHook<struct android_flex_layout,
+ &Gralloc1On0Adapter::lockFlex>);
+ case GRALLOC1_FUNCTION_UNLOCK:
+ return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook);
+ case GRALLOC1_FUNCTION_INVALID:
+ ALOGE("Invalid function descriptor");
+ return nullptr;
+ }
+
+ ALOGE("Unknown function descriptor: %d", intDescriptor);
+ return nullptr;
+}
+
+void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer)
+{
+ ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer);
+
+ if (!mDevice->dump) {
+ // dump is optional on gralloc0 implementations
+ *outSize = 0;
+ return;
+ }
+
+ if (!outBuffer) {
+ constexpr int32_t BUFFER_LENGTH = 4096;
+ char buffer[BUFFER_LENGTH] = {};
+ mDevice->dump(mDevice, buffer, BUFFER_LENGTH);
+ buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated
+ size_t actualLength = std::strlen(buffer);
+ mCachedDump.resize(actualLength);
+ std::copy_n(buffer, actualLength, mCachedDump.begin());
+ *outSize = static_cast<uint32_t>(actualLength);
+ } else {
+ *outSize = std::min(*outSize,
+ static_cast<uint32_t>(mCachedDump.size()));
+ outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer);
+ }
+}
+
+gralloc1_error_t Gralloc1On0Adapter::createDescriptor(
+ gralloc1_buffer_descriptor_t* outDescriptor)
+{
+ auto descriptorId = sNextBufferDescriptorId++;
+ std::lock_guard<std::mutex> lock(mDescriptorMutex);
+ mDescriptors.emplace(descriptorId, std::make_shared<Descriptor>());
+
+ ALOGV("Created descriptor %" PRIu64, descriptorId);
+
+ *outDescriptor = descriptorId;
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor(
+ gralloc1_buffer_descriptor_t descriptor)
+{
+ ALOGV("Destroying descriptor %" PRIu64, descriptor);
+
+ std::lock_guard<std::mutex> lock(mDescriptorMutex);
+ if (mDescriptors.count(descriptor) == 0) {
+ return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+ }
+
+ mDescriptors.erase(descriptor);
+ return GRALLOC1_ERROR_NONE;
+}
+
+Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle,
+ gralloc1_backing_store_t store, const Descriptor& descriptor,
+ uint32_t stride, uint32_t numFlexPlanes, bool wasAllocated)
+ : mHandle(handle),
+ mReferenceCount(1),
+ mStore(store),
+ mDescriptor(descriptor),
+ mStride(stride),
+ mNumFlexPlanes(numFlexPlanes),
+ mWasAllocated(wasAllocated) {}
+
+gralloc1_error_t Gralloc1On0Adapter::allocate(
+ gralloc1_buffer_descriptor_t id,
+ const std::shared_ptr<Descriptor>& descriptor,
+ buffer_handle_t* outBufferHandle)
+{
+ ALOGV("allocate(%" PRIu64 ")", id);
+
+ // If this function is being called, it's because we handed out its function
+ // pointer, which only occurs when mDevice has been loaded successfully and
+ // we are permitted to allocate
+
+ int usage = static_cast<int>(descriptor->producerUsage) |
+ static_cast<int>(descriptor->consumerUsage);
+ buffer_handle_t handle = nullptr;
+ int stride = 0;
+ ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width,
+ descriptor->height, descriptor->format, usage);
+ auto error = mDevice->alloc(mDevice,
+ static_cast<int>(descriptor->width),
+ static_cast<int>(descriptor->height), descriptor->format,
+ usage, &handle, &stride);
+ if (error != 0) {
+ ALOGE("gralloc0 allocation failed: %d (%s)", error,
+ strerror(-error));
+ return GRALLOC1_ERROR_NO_RESOURCES;
+ }
+
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_SET_USAGES,
+ handle,
+ static_cast<int>(descriptor->producerUsage),
+ static_cast<int>(descriptor->consumerUsage));
+
+ uint64_t backingStore = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE,
+ handle, &backingStore);
+ int numFlexPlanes = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES,
+ handle, &numFlexPlanes);
+
+ *outBufferHandle = handle;
+ auto buffer = std::make_shared<Buffer>(handle, backingStore,
+ *descriptor, stride, numFlexPlanes, true);
+
+ std::lock_guard<std::mutex> lock(mBufferMutex);
+ mBuffers.emplace(handle, std::move(buffer));
+
+ return GRALLOC1_ERROR_NONE;
+}
+
+int32_t Gralloc1On0Adapter::allocateHook(gralloc1_device* device,
+ uint32_t numDescriptors,
+ const gralloc1_buffer_descriptor_t* descriptors,
+ buffer_handle_t* outBuffers)
+{
+ if (!outBuffers) {
+ return GRALLOC1_ERROR_UNDEFINED;
+ }
+
+ auto adapter = getAdapter(device);
+
+ gralloc1_error_t error = GRALLOC1_ERROR_NONE;
+ uint32_t i;
+ for (i = 0; i < numDescriptors; i++) {
+ auto descriptor = adapter->getDescriptor(descriptors[i]);
+ if (!descriptor) {
+ error = GRALLOC1_ERROR_BAD_DESCRIPTOR;
+ break;
+ }
+
+ buffer_handle_t bufferHandle = nullptr;
+ error = adapter->allocate(descriptors[i], descriptor, &bufferHandle);
+ if (error != GRALLOC1_ERROR_NONE) {
+ break;
+ }
+
+ outBuffers[i] = bufferHandle;
+ }
+
+ if (error == GRALLOC1_ERROR_NONE) {
+ if (numDescriptors > 1) {
+ error = GRALLOC1_ERROR_NOT_SHARED;
+ }
+ } else {
+ for (uint32_t j = 0; j < i; j++) {
+ adapter->release(adapter->getBuffer(outBuffers[j]));
+ outBuffers[j] = nullptr;
+ }
+ }
+
+ return error;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+ const std::shared_ptr<Buffer>& buffer)
+{
+ std::lock_guard<std::mutex> lock(mBufferMutex);
+ buffer->retain();
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::release(
+ const std::shared_ptr<Buffer>& buffer)
+{
+ std::lock_guard<std::mutex> lock(mBufferMutex);
+ if (!buffer->release()) {
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ buffer_handle_t handle = buffer->getHandle();
+ if (buffer->wasAllocated()) {
+ ALOGV("Calling free(%p)", handle);
+ int result = mDevice->free(mDevice, handle);
+ if (result != 0) {
+ ALOGE("gralloc0 free failed: %d", result);
+ }
+ } else {
+ ALOGV("Calling unregisterBuffer(%p)", handle);
+ int result = mModule->unregisterBuffer(mModule, handle);
+ if (result != 0) {
+ ALOGE("gralloc0 unregister failed: %d", result);
+ }
+ }
+
+ mBuffers.erase(handle);
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(buffer_handle_t bufferHandle)
+{
+ ALOGV("retain(%p)", bufferHandle);
+
+ std::lock_guard<std::mutex> lock(mBufferMutex);
+
+ if (mBuffers.count(bufferHandle) != 0) {
+ mBuffers[bufferHandle]->retain();
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ ALOGV("Calling registerBuffer(%p)", bufferHandle);
+ int result = mModule->registerBuffer(mModule, bufferHandle);
+ if (result != 0) {
+ ALOGE("gralloc0 register failed: %d", result);
+ return GRALLOC1_ERROR_NO_RESOURCES;
+ }
+
+ uint64_t backingStore = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE,
+ bufferHandle, &backingStore);
+
+ int numFlexPlanes = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES,
+ bufferHandle, &numFlexPlanes);
+
+ int stride = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_STRIDE,
+ bufferHandle, &stride);
+
+ int width = 0;
+ int height = 0;
+ int format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ int producerUsage = 0;
+ int consumerUsage = 0;
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_DIMENSIONS,
+ bufferHandle, &width, &height);
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_FORMAT,
+ bufferHandle, &format);
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_PRODUCER_USAGE,
+ bufferHandle, &producerUsage);
+ mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_CONSUMER_USAGE,
+ bufferHandle, &consumerUsage);
+
+ Descriptor descriptor;
+ descriptor.setDimensions(width, height);
+ descriptor.setFormat(format);
+ descriptor.setProducerUsage(
+ static_cast<gralloc1_producer_usage_t>(producerUsage));
+ descriptor.setConsumerUsage(
+ static_cast<gralloc1_consumer_usage_t>(consumerUsage));
+
+ auto buffer = std::make_shared<Buffer>(bufferHandle, backingStore,
+ descriptor, stride, numFlexPlanes, false);
+ mBuffers.emplace(bufferHandle, std::move(buffer));
+ return GRALLOC1_ERROR_NONE;
+}
+
+static void syncWaitForever(int fd, const char* logname)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ const int warningTimeout = 3500;
+ const int error = sync_wait(fd, warningTimeout);
+ if (error < 0 && errno == ETIME) {
+ ALOGE("%s: fence %d didn't signal in %u ms", logname, fd,
+ warningTimeout);
+ sync_wait(fd, -1);
+ }
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lock(
+ const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion, void** outData,
+ int acquireFence)
+{
+ if (mMinorVersion >= 3) {
+ int result = mModule->lockAsync(mModule, buffer->getHandle(),
+ static_cast<int32_t>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData, acquireFence);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ } else {
+ syncWaitForever(acquireFence, "Gralloc1On0Adapter::lock");
+
+ int result = mModule->lock(mModule, buffer->getHandle(),
+ static_cast<int32_t>(producerUsage | consumerUsage),
+ accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height, outData);
+ ALOGV("gralloc0 lock returned %d", result);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ } else if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+ }
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockFlex(
+ const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion,
+ struct android_flex_layout* outFlex,
+ int acquireFence)
+{
+ if (mMinorVersion >= 3) {
+ int result = mModule->perform(mModule,
+ GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX,
+ buffer->getHandle(),
+ static_cast<int>(producerUsage),
+ static_cast<int>(consumerUsage),
+ accessRegion.left,
+ accessRegion.top,
+ accessRegion.width,
+ accessRegion.height,
+ outFlex, acquireFence);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+ } else {
+ syncWaitForever(acquireFence, "Gralloc1On0Adapter::lockFlex");
+
+ int result = mModule->perform(mModule,
+ GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX,
+ buffer->getHandle(),
+ static_cast<int>(producerUsage),
+ static_cast<int>(consumerUsage),
+ accessRegion.left,
+ accessRegion.top,
+ accessRegion.width,
+ accessRegion.height,
+ outFlex, -1);
+ if (result != 0) {
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ } else if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+ }
+
+ return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::unlock(
+ const std::shared_ptr<Buffer>& buffer,
+ int* outReleaseFence)
+{
+ if (mMinorVersion >= 3) {
+ int fenceFd = -1;
+ int result = mModule->unlockAsync(mModule, buffer->getHandle(),
+ &fenceFd);
+ if (result != 0) {
+ close(fenceFd);
+ ALOGE("gralloc0 unlockAsync failed: %d", result);
+ } else {
+ *outReleaseFence = fenceFd;
+ }
+ } else {
+ int result = mModule->unlock(mModule, buffer->getHandle());
+ if (result != 0) {
+ ALOGE("gralloc0 unlock failed: %d", result);
+ } else {
+ *outReleaseFence = -1;
+ }
+ }
+ return GRALLOC1_ERROR_NONE;
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Descriptor>
+Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId)
+{
+ std::lock_guard<std::mutex> lock(mDescriptorMutex);
+ if (mDescriptors.count(descriptorId) == 0) {
+ return nullptr;
+ }
+
+ return mDescriptors[descriptorId];
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer(
+ buffer_handle_t bufferHandle)
+{
+ std::lock_guard<std::mutex> lock(mBufferMutex);
+ if (mBuffers.count(bufferHandle) == 0) {
+ return nullptr;
+ }
+
+ return mBuffers[bufferHandle];
+}
+
+std::atomic<gralloc1_buffer_descriptor_t>
+ Gralloc1On0Adapter::sNextBufferDescriptorId(1);
+
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.h b/graphics/allocator/2.0/default/Gralloc1On0Adapter.h
new file mode 100644
index 0000000..180015d
--- /dev/null
+++ b/graphics/allocator/2.0/default/Gralloc1On0Adapter.h
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H
+#define ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H
+
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+struct gralloc_module_t;
+struct alloc_device_t;
+
+namespace android {
+namespace hardware {
+
+class Gralloc1On0Adapter : public gralloc1_device_t
+{
+public:
+ Gralloc1On0Adapter(const hw_module_t* module);
+ ~Gralloc1On0Adapter();
+
+ gralloc1_device_t* getDevice() {
+ return static_cast<gralloc1_device_t*>(this);
+ }
+
+private:
+ static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) {
+ return static_cast<Gralloc1On0Adapter*>(device);
+ }
+
+ static int closeHook(struct hw_device_t* device) {
+ delete getAdapter(reinterpret_cast<gralloc1_device_t*>(device));
+ return 0;
+ }
+
+ // getCapabilities
+
+ void doGetCapabilities(uint32_t* outCount,
+ int32_t* /*gralloc1_capability_t*/ outCapabilities);
+ static void getCapabilitiesHook(gralloc1_device_t* device,
+ uint32_t* outCount,
+ int32_t* /*gralloc1_capability_t*/ outCapabilities) {
+ getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+ }
+
+ // getFunction
+
+ gralloc1_function_pointer_t doGetFunction(
+ int32_t /*gralloc1_function_descriptor_t*/ descriptor);
+ static gralloc1_function_pointer_t getFunctionHook(
+ gralloc1_device_t* device,
+ int32_t /*gralloc1_function_descriptor_t*/ descriptor) {
+ return getAdapter(device)->doGetFunction(descriptor);
+ }
+
+ // dump
+
+ void dump(uint32_t* outSize, char* outBuffer);
+ static void dumpHook(gralloc1_device_t* device, uint32_t* outSize,
+ char* outBuffer) {
+ return getAdapter(device)->dump(outSize, outBuffer);
+ }
+ std::string mCachedDump;
+
+ // Buffer descriptor lifecycle functions
+
+ struct Descriptor;
+
+ gralloc1_error_t createDescriptor(
+ gralloc1_buffer_descriptor_t* outDescriptor);
+ static int32_t createDescriptorHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t* outDescriptor) {
+ auto error = getAdapter(device)->createDescriptor(outDescriptor);
+ return static_cast<int32_t>(error);
+ }
+
+ gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor);
+ static int32_t destroyDescriptorHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptor) {
+ auto error = getAdapter(device)->destroyDescriptor(descriptor);
+ return static_cast<int32_t>(error);
+ }
+
+ // Buffer descriptor modification functions
+
+ struct Descriptor : public std::enable_shared_from_this<Descriptor> {
+ Descriptor()
+ : width(0),
+ height(0),
+ format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ layerCount(1),
+ producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+ consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+ gralloc1_error_t setDimensions(uint32_t w, uint32_t h) {
+ width = w;
+ height = h;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setFormat(int32_t f) {
+ format = f;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setLayerCount(uint32_t lc) {
+ layerCount = lc;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
+ producerUsage = usage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) {
+ consumerUsage = usage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ uint32_t width;
+ uint32_t height;
+ int32_t format;
+ uint32_t layerCount;
+ gralloc1_producer_usage_t producerUsage;
+ gralloc1_consumer_usage_t consumerUsage;
+ };
+
+ template <typename ...Args>
+ static int32_t callDescriptorFunction(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId,
+ gralloc1_error_t (Descriptor::*member)(Args...), Args... args) {
+ auto descriptor = getAdapter(device)->getDescriptor(descriptorId);
+ if (!descriptor) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR);
+ }
+ auto error = ((*descriptor).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ static int32_t setConsumerUsageHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+ auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage);
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setConsumerUsage, usage);
+ }
+
+ static int32_t setDimensionsHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint32_t width,
+ uint32_t height) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setDimensions, width, height);
+ }
+
+ static int32_t setFormatHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, int32_t format) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setFormat, format);
+ }
+
+ static int32_t setLayerCountHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint32_t layerCount) {
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setLayerCount, layerCount);
+ }
+
+ static int32_t setProducerUsageHook(gralloc1_device_t* device,
+ gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+ auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
+ return callDescriptorFunction(device, descriptorId,
+ &Descriptor::setProducerUsage, usage);
+ }
+
+ // Buffer handle query functions
+
+ class Buffer {
+ public:
+ Buffer(buffer_handle_t handle, gralloc1_backing_store_t store,
+ const Descriptor& descriptor, uint32_t stride,
+ uint32_t numFlexPlanes, bool wasAllocated);
+
+ buffer_handle_t getHandle() const { return mHandle; }
+
+ void retain() { ++mReferenceCount; }
+
+ // Returns true if the reference count has dropped to 0, indicating that
+ // the buffer needs to be released
+ bool release() { return --mReferenceCount == 0; }
+
+ bool wasAllocated() const { return mWasAllocated; }
+
+ gralloc1_error_t getBackingStore(
+ gralloc1_backing_store_t* outStore) const {
+ *outStore = mStore;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getConsumerUsage(
+ gralloc1_consumer_usage_t* outUsage) const {
+ *outUsage = mDescriptor.consumerUsage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getDimensions(uint32_t* outWidth,
+ uint32_t* outHeight) const {
+ *outWidth = mDescriptor.width;
+ *outHeight = mDescriptor.height;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getFormat(int32_t* outFormat) const {
+ *outFormat = mDescriptor.format;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getLayerCount(uint32_t* outLayerCount) const {
+ *outLayerCount = mDescriptor.layerCount;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
+ *outNumPlanes = mNumFlexPlanes;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getProducerUsage(
+ gralloc1_producer_usage_t* outUsage) const {
+ *outUsage = mDescriptor.producerUsage;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ gralloc1_error_t getStride(uint32_t* outStride) const {
+ *outStride = mStride;
+ return GRALLOC1_ERROR_NONE;
+ }
+
+ private:
+
+ const buffer_handle_t mHandle;
+ size_t mReferenceCount;
+
+ const gralloc1_backing_store_t mStore;
+ const Descriptor mDescriptor;
+ const uint32_t mStride;
+ const uint32_t mNumFlexPlanes;
+
+ // Whether this buffer allocated in this process (as opposed to just
+ // being retained here), which determines whether to free or unregister
+ // the buffer when this Buffer is released
+ const bool mWasAllocated;
+ };
+
+ template <typename ...Args>
+ static int32_t callBufferFunction(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle,
+ gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) {
+ auto buffer = getAdapter(device)->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+ auto error = ((*buffer).*member)(std::forward<Args>(args)...);
+ return static_cast<int32_t>(error);
+ }
+
+ template <typename MF, MF memFunc, typename ...Args>
+ static int32_t bufferHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, Args... args) {
+ return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle,
+ memFunc, std::forward<Args>(args)...);
+ }
+
+ static int32_t getConsumerUsageHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, uint64_t* outUsage) {
+ auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
+ auto error = callBufferFunction(device, bufferHandle,
+ &Buffer::getConsumerUsage, &usage);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outUsage = static_cast<uint64_t>(usage);
+ }
+ return error;
+ }
+
+ static int32_t getProducerUsageHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, uint64_t* outUsage) {
+ auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
+ auto error = callBufferFunction(device, bufferHandle,
+ &Buffer::getProducerUsage, &usage);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outUsage = static_cast<uint64_t>(usage);
+ }
+ return error;
+ }
+
+ // Buffer management functions
+
+ gralloc1_error_t allocate(
+ gralloc1_buffer_descriptor_t id,
+ const std::shared_ptr<Descriptor>& descriptor,
+ buffer_handle_t* outBufferHandle);
+ static int32_t allocateHook(gralloc1_device* device,
+ uint32_t numDescriptors,
+ const gralloc1_buffer_descriptor_t* descriptors,
+ buffer_handle_t* outBuffers);
+
+ gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer);
+ gralloc1_error_t retain(buffer_handle_t bufferHandle);
+ static int32_t retainHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle)
+ {
+ auto adapter = getAdapter(device);
+ return adapter->retain(bufferHandle);
+ }
+
+ gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer);
+ static int32_t releaseHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle) {
+ auto adapter = getAdapter(device);
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ auto error = adapter->release(buffer);
+ return static_cast<int32_t>(error);
+ }
+
+ // Buffer access functions
+
+ gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion, void** outData,
+ int acquireFence);
+ gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer,
+ gralloc1_producer_usage_t producerUsage,
+ gralloc1_consumer_usage_t consumerUsage,
+ const gralloc1_rect_t& accessRegion,
+ struct android_flex_layout* outFlex,
+ int acquireFence);
+
+ template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)(
+ const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t,
+ gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*,
+ int)>
+ static int32_t lockHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle,
+ uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage,
+ uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage,
+ const gralloc1_rect_t* accessRegion, OUT* outData,
+ int32_t acquireFenceFd) {
+ auto adapter = getAdapter(device);
+
+ // Exactly one of producer and consumer usage must be *_USAGE_NONE,
+ // but we can't check this until the upper levels of the framework
+ // correctly distinguish between producer and consumer usage
+ /*
+ bool hasProducerUsage =
+ uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE;
+ bool hasConsumerUsage =
+ uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE;
+ if (hasProducerUsage && hasConsumerUsage ||
+ !hasProducerUsage && !hasConsumerUsage) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ */
+
+ auto producerUsage =
+ static_cast<gralloc1_producer_usage_t>(uintProducerUsage);
+ auto consumerUsage =
+ static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage);
+
+ if (!outData) {
+ const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
+ GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+ if ((producerUsage & producerCpuUsage) != 0) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ if ((consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ) != 0) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+ }
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ if (!accessRegion) {
+ ALOGE("accessRegion is null");
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+ }
+
+ auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage,
+ *accessRegion, outData, acquireFenceFd);
+ return static_cast<int32_t>(error);
+ }
+
+ gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer,
+ int* outReleaseFence);
+ static int32_t unlockHook(gralloc1_device_t* device,
+ buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) {
+ auto adapter = getAdapter(device);
+
+ auto buffer = adapter->getBuffer(bufferHandle);
+ if (!buffer) {
+ return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+ }
+
+ int releaseFence = -1;
+ auto error = adapter->unlock(buffer, &releaseFence);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outReleaseFenceFd = releaseFence;
+ }
+ return static_cast<int32_t>(error);
+ }
+
+ // Adapter internals
+ const gralloc_module_t* mModule;
+ uint8_t mMinorVersion;
+ alloc_device_t* mDevice;
+
+ std::shared_ptr<Descriptor> getDescriptor(
+ gralloc1_buffer_descriptor_t descriptorId);
+ std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle);
+
+ static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId;
+ std::mutex mDescriptorMutex;
+ std::unordered_map<gralloc1_buffer_descriptor_t,
+ std::shared_ptr<Descriptor>> mDescriptors;
+ std::mutex mBufferMutex;
+ std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers;
+};
+
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H
diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
new file mode 100644
index 0000000..c4715cd
--- /dev/null
+++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
@@ -0,0 +1,5 @@
+service gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service
+ class hal
+ user system
+ group graphics drmrpc readproc
+ onrestart restart surfaceflinger
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.cpp b/graphics/allocator/2.0/default/gralloc1-adapter.cpp
new file mode 100644
index 0000000..fcc59cd
--- /dev/null
+++ b/graphics/allocator/2.0/default/gralloc1-adapter.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include "Gralloc1On0Adapter.h"
+#include "gralloc1-adapter.h"
+
+int gralloc1_adapter_device_open(const struct hw_module_t* module,
+ const char* id, struct hw_device_t** device)
+{
+ if (strcmp(id, GRALLOC_HARDWARE_MODULE_ID) != 0) {
+ ALOGE("unknown gralloc1 device id: %s", id);
+ return -EINVAL;
+ }
+
+ auto adapter_device = new android::hardware::Gralloc1On0Adapter(module);
+ *device = &adapter_device->common;
+
+ return 0;
+}
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.h b/graphics/allocator/2.0/default/gralloc1-adapter.h
new file mode 100644
index 0000000..b912ef6
--- /dev/null
+++ b/graphics/allocator/2.0/default/gralloc1-adapter.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_GRALLOC1_ADAPTER_H
+#define ANDROID_HARDWARE_GRALLOC1_ADAPTER_H
+
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+#define GRALLOC1_ADAPTER_MODULE_API_VERSION_1_0 \
+ HARDWARE_MODULE_API_VERSION(1, 0)
+
+enum {
+ GRALLOC1_ADAPTER_PERFORM_FIRST = 10000,
+
+ // void getRealModuleApiVersionMinor(..., int* outMinorVersion);
+ GRALLOC1_ADAPTER_PERFORM_GET_REAL_MODULE_API_VERSION_MINOR =
+ GRALLOC1_ADAPTER_PERFORM_FIRST,
+
+ // void setUsages(..., buffer_handle_t buffer,
+ // int producerUsage,
+ // int consumerUsage);
+ GRALLOC1_ADAPTER_PERFORM_SET_USAGES =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 1,
+
+ // void getDimensions(..., buffer_handle_t buffer,
+ // int* outWidth,
+ // int* outHeight);
+ GRALLOC1_ADAPTER_PERFORM_GET_DIMENSIONS =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 2,
+
+ // void getFormat(..., buffer_handle_t buffer, int* outFormat);
+ GRALLOC1_ADAPTER_PERFORM_GET_FORMAT =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 3,
+
+ // void getProducerUsage(..., buffer_handle_t buffer, int* outUsage);
+ GRALLOC1_ADAPTER_PERFORM_GET_PRODUCER_USAGE =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 4,
+
+ // void getConsumerUsage(..., buffer_handle_t buffer, int* outUsage);
+ GRALLOC1_ADAPTER_PERFORM_GET_CONSUMER_USAGE =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 5,
+
+ // void getBackingStore(..., buffer_handle_t buffer,
+ // uint64_t* outBackingStore);
+ GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 6,
+
+ // void getNumFlexPlanes(..., buffer_handle_t buffer,
+ // int* outNumFlexPlanes);
+ GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 7,
+
+ // void getStride(..., buffer_handle_t buffer, int* outStride);
+ GRALLOC1_ADAPTER_PERFORM_GET_STRIDE =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 8,
+
+ // void lockFlex(..., buffer_handle_t buffer,
+ // int producerUsage,
+ // int consumerUsage,
+ // int left,
+ // int top,
+ // int width,
+ // int height,
+ // android_flex_layout* outLayout,
+ // int acquireFence);
+ GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX =
+ GRALLOC1_ADAPTER_PERFORM_FIRST + 9,
+};
+
+int gralloc1_adapter_device_open(const struct hw_module_t* module,
+ const char* id, struct hw_device_t** device);
+
+__END_DECLS
+
+#endif /* ANDROID_HARDWARE_GRALLOC1_ADAPTER_H */
diff --git a/graphics/allocator/2.0/default/service.cpp b/graphics/allocator/2.0/default/service.cpp
new file mode 100644
index 0000000..a43740c
--- /dev/null
+++ b/graphics/allocator/2.0/default/service.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.graphics.allocator@2.0-service"
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IAllocator>();
+}
diff --git a/graphics/allocator/2.0/types.hal b/graphics/allocator/2.0/types.hal
new file mode 100644
index 0000000..f9d1e1b
--- /dev/null
+++ b/graphics/allocator/2.0/types.hal
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 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.graphics.allocator@2.0;
+
+enum Error : int32_t {
+ NONE = 0, /* no error */
+ BAD_DESCRIPTOR = 1, /* invalid BufferDescriptor */
+ BAD_BUFFER = 2, /* invalid Buffer */
+ BAD_VALUE = 3, /* invalid width, height, etc. */
+ NOT_SHARED = 4, /* buffers not sharing backing store */
+ NO_RESOURCES = 5, /* temporary failure due to resource contention */
+ UNDEFINED = 6, /* an operation has no defined meaning */
+ UNSUPPORTED = 7, /* permanent failure */
+};
+
+enum ProducerUsage : uint64_t {
+ /* bit 0 is reserved */
+
+ /* buffer is read by CPU occasionally */
+ CPU_READ = 1ULL << 1,
+ /* buffer is read by CPU frequently */
+ CPU_READ_OFTEN = 1ULL << 2,
+
+ /* bit 3 is reserved */
+ /* bit 4 is reserved */
+
+ /* buffer is written by CPU occasionally */
+ CPU_WRITE = 1ULL << 5,
+ /* buffer is written by CPU frequently */
+ CPU_WRITE_OFTEN = 1ULL << 6,
+
+ /* bit 7 is reserved */
+ /* bit 8 is reserved */
+
+ /* buffer is used as a GPU render target */
+ GPU_RENDER_TARGET = 1ULL << 9,
+
+ /* bit 10 is reserved */
+ /* bit 11 is reserved */
+ /* bit 12 is reserved */
+ /* bit 13 is reserved */
+
+ /*
+ * Buffer is allocated with hardware-level protection against copying the
+ * contents (or information derived from the contents) into unprotected
+ * memory.
+ */
+ PROTECTED = 1ULL << 14,
+
+ /* bit 15 is reserved */
+ /* bit 16 is reserved */
+
+ /* buffer is used as a camera HAL output */
+ CAMERA = 1ULL << 17,
+
+ /* bit 18 is reserved */
+ /* bit 19 is reserved */
+ /* bit 20 is reserved */
+ /* bit 21 is reserved */
+
+ /* buffer is used as a video decoder output */
+ VIDEO_DECODER = 1ULL << 22,
+
+ /* buffer is used as a sensor direct report output */
+ SENSOR_DIRECT_DATA = 1ULL << 23,
+
+ /* bits 24-27 are reserved for future versions */
+ /* bits 28-31 are reserved for vendor extensions */
+
+ /* bits 32-47 are reserved for future versions */
+ /* bits 48-63 are reserved for vendor extensions */
+};
+
+enum ConsumerUsage : uint64_t {
+ /* bit 0 is reserved */
+
+ /* buffer is read by CPU occasionally */
+ CPU_READ = 1ULL << 1,
+ /* buffer is read by CPU frequently */
+ CPU_READ_OFTEN = 1ULL << 2,
+
+ /* bit 3 is reserved */
+ /* bit 4 is reserved */
+ /* bit 5 is reserved */
+ /* bit 6 is reserved */
+ /* bit 7 is reserved */
+
+ /* buffer is used as a GPU texture */
+ GPU_TEXTURE = 1ULL << 8,
+
+ /* bit 9 is reserved */
+ /* bit 10 is reserved */
+
+ /* buffer is used by hwcomposer HAL */
+ HWCOMPOSER = 1ULL << 11,
+ /* buffer is a hwcomposer HAL client target */
+ CLIENT_TARGET = 1ULL << 12,
+
+ /* bit 13 is reserved */
+ /* bit 14 is reserved */
+
+ /* buffer is used as a hwcomposer HAL cursor */
+ CURSOR = 1ULL << 15,
+
+ /* buffer is used as a video encoder input */
+ VIDEO_ENCODER = 1ULL << 16,
+
+ /* bit 17 is reserved */
+
+ /* buffer is used as a camera HAL input */
+ CAMERA = 1ULL << 18,
+
+ /* bit 19 is reserved */
+
+ /* buffer is used as a renderscript allocation */
+ RENDERSCRIPT = 1ULL << 20,
+
+ /* bit 21 is reserved */
+ /* bit 22 is reserved */
+
+ /* buffer is used as as an OpenGL shader storage or uniform
+ buffer object */
+ GPU_DATA_BUFFER = 1ULL << 23,
+
+ /* bits 24-27 are reserved for future versions */
+ /* bits 28-31 are reserved for vendor extensions */
+
+ /* bits 32-47 are reserved for future versions */
+ /* bits 48-63 are reserved for vendor extensions */
+};
+
+typedef uint64_t BufferDescriptor;
+typedef uint64_t Buffer;
diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..fb77ab3
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/Android.bp
@@ -0,0 +1,62 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_library_static {
+ name: "libVtsHalGraphicsAllocatorTestUtils",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsAllocatorTestUtils.cpp"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_test {
+ name: "VtsHalGraphicsAllocatorV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsAllocatorV2_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.graphics.allocator@2.0",
+ ],
+ static_libs: [
+ "libVtsHalGraphicsAllocatorTestUtils",
+ "VtsHalHidlTargetTestBase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp
new file mode 100644
index 0000000..0dc43be
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+
+Allocator::Allocator() { init(); }
+
+void Allocator::init() {
+ mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>();
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+ std::vector<IAllocator::Capability> capabilities = getCapabilities();
+ mCapabilities.insert(capabilities.begin(), capabilities.end());
+}
+
+sp<IAllocator> Allocator::getRaw() const { return mAllocator; }
+
+bool Allocator::hasCapability(IAllocator::Capability capability) const {
+ return mCapabilities.count(capability) > 0;
+}
+
+std::vector<IAllocator::Capability> Allocator::getCapabilities() {
+ std::vector<IAllocator::Capability> capabilities;
+ mAllocator->getCapabilities(
+ [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+
+ return capabilities;
+}
+
+std::string Allocator::dumpDebugInfo() {
+ std::string debugInfo;
+ mAllocator->dumpDebugInfo(
+ [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+std::unique_ptr<AllocatorClient> Allocator::createClient() {
+ std::unique_ptr<AllocatorClient> client;
+ mAllocator->createClient([&](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<AllocatorClient>(tmpClient);
+ });
+
+ return client;
+}
+
+AllocatorClient::AllocatorClient(const sp<IAllocatorClient>& client)
+ : mClient(client) {}
+
+AllocatorClient::~AllocatorClient() {
+ for (auto buffer : mBuffers) {
+ EXPECT_EQ(Error::NONE, mClient->free(buffer))
+ << "failed to free buffer " << buffer;
+ }
+ mBuffers.clear();
+
+ for (auto descriptor : mDescriptors) {
+ EXPECT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
+ << "failed to destroy descriptor " << descriptor;
+ }
+ mDescriptors.clear();
+}
+
+sp<IAllocatorClient> AllocatorClient::getRaw() const { return mClient; }
+
+BufferDescriptor AllocatorClient::createDescriptor(
+ const IAllocatorClient::BufferDescriptorInfo& info) {
+ BufferDescriptor descriptor = 0;
+ mClient->createDescriptor(
+ info, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+ descriptor = tmpDescriptor;
+
+ EXPECT_TRUE(mDescriptors.insert(descriptor).second)
+ << "duplicated descriptor id " << descriptor;
+ });
+
+ return descriptor;
+}
+
+void AllocatorClient::destroyDescriptor(BufferDescriptor descriptor) {
+ ASSERT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
+ << "failed to destroy descriptor " << descriptor;
+
+ mDescriptors.erase(descriptor);
+}
+
+Error AllocatorClient::testAllocate(
+ const std::vector<BufferDescriptor>& descriptors) {
+ return mClient->testAllocate(descriptors);
+}
+
+bool AllocatorClient::testAllocate(BufferDescriptor descriptor) {
+ std::vector<BufferDescriptor> descriptors(1, descriptor);
+ Error error = testAllocate(descriptors);
+ return (error == Error::NONE || error == Error::NOT_SHARED);
+}
+
+Error AllocatorClient::allocate(
+ const std::vector<BufferDescriptor>& descriptors,
+ std::vector<Buffer>& buffers) {
+ Error error = Error::NO_RESOURCES;
+ mClient->allocate(descriptors, [&](const auto& tmpError,
+ const auto& tmpBuffers) {
+ ASSERT_TRUE(tmpError == Error::NONE || tmpError == Error::NOT_SHARED)
+ << "failed to allocate buffer";
+ ASSERT_EQ(descriptors.size(), tmpBuffers.size()) << "invalid buffer count";
+
+ error = tmpError;
+ buffers = tmpBuffers;
+
+ for (auto buffer : buffers) {
+ EXPECT_TRUE(mBuffers.insert(buffer).second)
+ << "duplicated buffer id " << buffer;
+ }
+ });
+
+ return error;
+}
+
+Buffer AllocatorClient::allocate(BufferDescriptor descriptor) {
+ std::vector<BufferDescriptor> descriptors(1, descriptor);
+ std::vector<Buffer> buffers;
+ allocate(descriptors, buffers);
+ if (::testing::Test::HasFatalFailure()) {
+ return 0;
+ }
+
+ return buffers[0];
+}
+
+void AllocatorClient::free(Buffer buffer) {
+ ASSERT_EQ(Error::NONE, mClient->free(buffer))
+ << "failed to free buffer " << buffer;
+
+ mBuffers.erase(buffer);
+}
+
+native_handle_t* AllocatorClient::exportHandle(BufferDescriptor descriptor,
+ Buffer buffer) {
+ native_handle_t* handle;
+ mClient->exportHandle(
+ descriptor, buffer, [&](const auto& tmpError, const auto& tmpHandle) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to export buffer handle";
+ ASSERT_NE(nullptr, tmpHandle.getNativeHandle())
+ << "invalid buffer handle";
+
+ handle = native_handle_clone(tmpHandle.getNativeHandle());
+ ASSERT_NE(nullptr, handle) << "failed to clone handle";
+ });
+
+ return handle;
+}
+
+} // namespace tests
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h
new file mode 100644
index 0000000..c9bfe8f
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
+#define VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+
+class AllocatorClient;
+
+// A wrapper to IAllocator.
+class Allocator {
+ public:
+ Allocator();
+
+ sp<IAllocator> getRaw() const;
+
+ // Returns true when the allocator supports the specified capability.
+ bool hasCapability(IAllocator::Capability capability) const;
+
+ std::vector<IAllocator::Capability> getCapabilities();
+ std::string dumpDebugInfo();
+ std::unique_ptr<AllocatorClient> createClient();
+
+ private:
+ void init();
+
+ sp<IAllocator> mAllocator;
+ std::unordered_set<IAllocator::Capability> mCapabilities;
+};
+
+// A wrapper to IAllocatorClient.
+class AllocatorClient {
+ public:
+ AllocatorClient(const sp<IAllocatorClient>& client);
+ ~AllocatorClient();
+
+ sp<IAllocatorClient> getRaw() const;
+
+ BufferDescriptor createDescriptor(
+ const IAllocatorClient::BufferDescriptorInfo& info);
+ void destroyDescriptor(BufferDescriptor descriptor);
+
+ Error testAllocate(const std::vector<BufferDescriptor>& descriptors);
+ bool testAllocate(BufferDescriptor descriptor);
+
+ Error allocate(const std::vector<BufferDescriptor>& descriptors,
+ std::vector<Buffer>& buffers);
+ Buffer allocate(BufferDescriptor descriptor);
+ void free(Buffer buffer);
+
+ // Returns a handle to the buffer. The ownership of the handle is
+ // transferred to the caller.
+ native_handle_t* exportHandle(BufferDescriptor descriptor, Buffer buffer);
+
+ private:
+ sp<IAllocatorClient> mClient;
+
+ // Keep track of all descriptors and buffers. When a test fails with
+ // ASSERT_*, the destructor will clean up the resources for the test.
+ std::unordered_set<BufferDescriptor> mDescriptors;
+ std::unordered_set<Buffer> mBuffers;
+};
+
+} // namespace tests
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
new file mode 100644
index 0000000..b1c764f
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "graphics_allocator_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+#define CHECK_FEATURE_OR_SKIP(FEATURE_NAME) \
+ do { \
+ if (!mAllocator->hasCapability(FEATURE_NAME)) { \
+ std::cout << "[ SKIPPED ] Feature " << #FEATURE_NAME \
+ << " not supported" << std::endl; \
+ return; \
+ } \
+ } while (0)
+
+class GraphicsAllocatorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+ ASSERT_NO_FATAL_FAILURE(mClient = mAllocator->createClient());
+
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+ mDummyDescriptorInfo.producerUsageMask =
+ static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
+ mDummyDescriptorInfo.consumerUsageMask =
+ static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+ }
+
+ void TearDown() override {}
+
+ std::unique_ptr<Allocator> mAllocator;
+ std::unique_ptr<AllocatorClient> mClient;
+ IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
+};
+
+TEST_F(GraphicsAllocatorHidlTest, GetCapabilities) {
+ auto capabilities = mAllocator->getCapabilities();
+ for (auto cap : capabilities) {
+ EXPECT_NE(IAllocator::Capability::INVALID, cap);
+ }
+}
+
+TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) {
+ mAllocator->dumpDebugInfo();
+}
+
+TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+ mClient->destroyDescriptor(descriptor);
+}
+
+/**
+ * Test testAllocate with a single buffer descriptor.
+ */
+TEST_F(GraphicsAllocatorHidlTest, TestAllocateBasic) {
+ CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
+
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ ASSERT_TRUE(mClient->testAllocate(descriptor));
+}
+
+/**
+ * Test testAllocate with two buffer descriptors.
+ */
+TEST_F(GraphicsAllocatorHidlTest, TestAllocateArray) {
+ CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
+
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ hidl_vec<BufferDescriptor> descriptors;
+ descriptors.resize(2);
+ descriptors[0] = descriptor;
+ descriptors[1] = descriptor;
+
+ auto error = mClient->testAllocate(descriptors);
+ ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
+}
+
+/**
+ * Test allocate/free with a single buffer descriptor.
+ */
+TEST_F(GraphicsAllocatorHidlTest, AllocateFreeBasic) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
+
+ mClient->free(buffer);
+}
+
+/**
+ * Test allocate/free with an array of buffer descriptors.
+ */
+TEST_F(GraphicsAllocatorHidlTest, AllocateFreeArray) {
+ BufferDescriptor descriptor1;
+ ASSERT_NO_FATAL_FAILURE(descriptor1 =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ BufferDescriptor descriptor2;
+ ASSERT_NO_FATAL_FAILURE(descriptor2 =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ hidl_vec<BufferDescriptor> descriptors;
+ descriptors.resize(3);
+ descriptors[0] = descriptor1;
+ descriptors[1] = descriptor1;
+ descriptors[2] = descriptor2;
+
+ std::vector<Buffer> buffers;
+ ASSERT_NO_FATAL_FAILURE(mClient->allocate(descriptors, buffers));
+
+ for (auto buf : buffers) {
+ mClient->free(buf);
+ }
+}
+
+TEST_F(GraphicsAllocatorHidlTest, ExportHandle) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor =
+ mClient->createDescriptor(mDummyDescriptorInfo));
+
+ Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
+
+ native_handle_t* handle;
+ ASSERT_NO_FATAL_FAILURE(handle = mClient->exportHandle(descriptor, buffer));
+
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+} // namespace anonymous
+} // namespace tests
+} // namespace V2_0
+} // namespace allocator
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+
+ return status;
+}
diff --git a/graphics/allocator/Android.mk b/graphics/allocator/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/allocator/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
new file mode 100644
index 0000000..4ba764f
--- /dev/null
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -0,0 +1,70 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.bufferqueue@1.0_hal",
+ srcs: [
+ "IGraphicBufferProducer.hal",
+ "IProducerListener.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.bufferqueue@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.bufferqueue@1.0",
+ srcs: [
+ ":android.hardware.graphics.bufferqueue@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/bufferqueue/1.0/GraphicBufferProducerAll.cpp",
+ "android/hardware/graphics/bufferqueue/1.0/ProducerListenerAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.bufferqueue@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.bufferqueue@1.0",
+ srcs: [
+ ":android.hardware.graphics.bufferqueue@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/IHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BnHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BpHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BsGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/IProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/IHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BnHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BpHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BsProducerListener.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.bufferqueue@1.0",
+ generated_sources: ["android.hardware.graphics.bufferqueue@1.0_genc++"],
+ generated_headers: ["android.hardware.graphics.bufferqueue@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.bufferqueue@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
new file mode 100644
index 0000000..c59a16c
--- /dev/null
+++ b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2017 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.graphics.bufferqueue@1.0;
+
+import android.hardware.media@1.0::Fence;
+import android.hardware.media@1.0::AnwBuffer;
+import android.hardware.media@1.0::Rect;
+import android.hardware.media@1.0::Region;
+
+import android.hardware.graphics.common@1.0::Dataspace;
+import android.hardware.graphics.common@1.0::PixelFormat;
+
+import IProducerListener;
+
+/**
+ * Ref: frameworks/native/include/gui/IGraphicBufferProducer.h:
+ * IGraphicBufferProducer
+ * This is a wrapper/wrapped HAL interface for the actual binder interface.
+ */
+interface IGraphicBufferProducer {
+
+ /**
+ * Type for return values of functions in IGraphicBufferProducer.
+ */
+ typedef int32_t Status;
+
+ /**
+ * Ref: frameworks/native/include/ui/FenceTime.h: FenceTime::Snapshot
+ *
+ * An atomic snapshot of the FenceTime that is flattenable.
+ */
+ struct FenceTimeSnapshot {
+ enum State : int32_t {
+ EMPTY,
+ FENCE,
+ SIGNAL_TIME,
+ };
+ State state;
+ Fence fence;
+ int64_t signalTimeNs;
+ };
+
+ /**
+ * Ref: frameworks/native/include/gui/FrameTimestamp.h: FrameEventsDelta
+ *
+ * A single frame update from the consumer to producer that can be sent
+ * through a HIDL interface. Although this may be sent multiple times for
+ * the same frame as new timestamps are set, Fences only need to be sent
+ * once.
+ */
+ struct FrameEventsDelta {
+ uint32_t index;
+ uint64_t frameNumber;
+ bool addPostCompositeCalled;
+ bool addRetireCalled;
+ bool addReleaseCalled;
+ int64_t postedTimeNs;
+ int64_t requestedPresentTimeNs;
+ int64_t latchTimeNs;
+ int64_t firstRefreshStartTimeNs;
+ int64_t lastRefreshStartTimeNs;
+ int64_t dequeueReadyTime;
+ FenceTimeSnapshot gpuCompositionDoneFence;
+ FenceTimeSnapshot displayPresentFence;
+ FenceTimeSnapshot displayRetireFence;
+ FenceTimeSnapshot releaseFence;
+ };
+
+ /**
+ * Ref: frameworks/native/include/gui/FrameTimestamp.h: CompositorTiming
+ *
+ * The most recent compositor timing info sent from consumer to producer
+ * through a HIDL interface.
+ */
+ struct CompositorTiming {
+ int64_t deadlineNs;
+ int64_t intervalNs;
+ int64_t presentLatencyNs;
+ };
+
+ /**
+ * Ref: frameworks/native/include/gui/FrameTimestamp.h: FrameEventHistoryDelta
+ *
+ * A collection of updates from consumer to producer that can be sent
+ * through a HIDL interface.
+ */
+ struct FrameEventHistoryDelta {
+ vec<FrameEventsDelta> deltas;
+ CompositorTiming compositorTiming;
+ };
+
+ /**
+ * Modes for disconnection.
+ */
+ enum DisconnectMode : int32_t {
+ /** Disconnect only the specified API. */
+ API,
+ /** Disconnect any API originally connected from the process calling
+ * disconnect. */
+ ALL_LOCAL
+ };
+
+ struct QueueBufferInput {
+ /** A monotonically increasing value in nanoseconds. */
+ int64_t timestamp;
+ /** Whether the timestamp was synthesized at queue time. */
+ int32_t isAutoTimestamp;
+ /** Description of the contents, interpretation depends on format. */
+ Dataspace dataSpace;
+ /** A crop rectangle that's used as a hint to the consumer. */
+ Rect crop;
+ /** A set of flags from NATIVE_WINDOW_SCALING_* in <window.h>. */
+ int32_t scalingMode;
+ /** A set of flags from NATIVE_WINDOW_TRANSFORM_* in <window.h>. */
+ uint32_t transform;
+ /** The sticky transform set in Surface (only used by the LEGACY camera
+ * mode). */
+ uint32_t stickyTransform;
+ /** A fence that the consumer must wait on before reading the buffer;
+ * set this to Fence::NO_FENCE if the buffer is ready immediately. */
+ Fence fence;
+ Region surfaceDamage;
+ /** Whether or not the latest frame timestamps should be retrieved from
+ * the consumer. */
+ bool getFrameTimestamps;
+ };
+
+ struct QueueBufferOutput {
+ uint32_t width;
+ uint32_t height;
+ uint32_t transformHint;
+ uint32_t numPendingBuffers;
+ uint64_t nextFrameNumber;
+ bool bufferReplaced;
+ FrameEventHistoryDelta frameTimestamps;
+ };
+
+ /**
+ * requestBuffer requests a new buffer for the given index. The server (i.e.
+ * the IProducerListener implementation) assigns the newly created
+ * buffer to the given slot index, and the client is expected to mirror the
+ * slot->buffer mapping so that it's not necessary to transfer an
+ * AnwBuffer for every dequeue operation.
+ *
+ * The slot must be in the range of [0, NUM_BUFFER_SLOTS).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - one of the two conditions occurred:
+ * * slot was out of range (see above)
+ * * buffer specified by the slot is not dequeued
+ */
+ requestBuffer(
+ int32_t slot
+ ) generates (
+ Status status,
+ AnwBuffer buffer
+ );
+
+ /**
+ * setMaxDequeuedBufferCount sets the maximum number of buffers that can be
+ * dequeued by the producer at one time. If this method succeeds, any new
+ * buffer slots will be both unallocated and owned by the BufferQueue object
+ * (i.e. they are not owned by the producer or consumer). Calling this may
+ * also cause some buffer slots to be emptied. If the caller is caching the
+ * contents of the buffer slots, it should empty that cache after calling
+ * this method.
+ *
+ * This function should not be called with a value of maxDequeuedBuffers
+ * that is less than the number of currently dequeued buffer slots. Doing so
+ * will result in a BAD_VALUE error.
+ *
+ * The buffer count should be at least 1 (inclusive), but at most
+ * (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
+ * minimum undequeued buffer count can be obtained by calling
+ * query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned.
+ * * BAD_VALUE - one of the below conditions occurred:
+ * * bufferCount was out of range (see above).
+ * * client would have more than the requested number of dequeued
+ * buffers after this call.
+ * * this call would cause the maxBufferCount value to be exceeded.
+ * * failure to adjust the number of available slots.
+ */
+ setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Set the async flag if the producer intends to asynchronously queue
+ * buffers without blocking. Typically this is used for triple-buffering
+ * and/or when the swap interval is set to zero.
+ *
+ * Enabling async mode will internally allocate an additional buffer to
+ * allow for the asynchronous behavior. If it is not enabled queue/dequeue
+ * calls may block.
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned.
+ * * BAD_VALUE - one of the following has occurred:
+ * * this call would cause the maxBufferCount value to be
+ * exceeded
+ * * failure to adjust the number of available slots.
+ */
+ setAsyncMode(
+ bool async
+ ) generates (
+ Status status
+ );
+
+ /**
+ * dequeueBuffer requests a new buffer slot for the client to use. Ownership
+ * of the slot is transfered to the client, meaning that the server will not
+ * use the contents of the buffer associated with that slot.
+ *
+ * The slot index returned may or may not contain a buffer (client-side).
+ * If the slot is empty the client should call requestBuffer to assign a new
+ * buffer to that slot.
+ *
+ * Once the client is done filling this buffer, it is expected to transfer
+ * buffer ownership back to the server with either cancelBuffer on
+ * the dequeued slot or to fill in the contents of its associated buffer
+ * contents and call queueBuffer.
+ *
+ * If dequeueBuffer returns the BUFFER_NEEDS_REALLOCATION flag, the client is
+ * expected to call requestBuffer immediately.
+ *
+ * If dequeueBuffer returns the RELEASE_ALL_BUFFERS flag, the client is
+ * expected to release all of the mirrored slot->buffer mappings.
+ *
+ * The fence parameter will be updated to hold the fence associated with
+ * the buffer. The contents of the buffer must not be overwritten until the
+ * fence signals. If the fence is Fence::NO_FENCE, the buffer may be written
+ * immediately.
+ *
+ * The width and height parameters must be no greater than the minimum of
+ * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ * An error due to invalid dimensions might not be reported until
+ * updateTexImage() is called. If width and height are both zero, the
+ * default values specified by setDefaultBufferSize() are used instead.
+ *
+ * If the format is 0, the default format will be used.
+ *
+ * The usage argument specifies gralloc buffer usage flags. The values
+ * are enumerated in <gralloc.h>, e.g. GRALLOC_USAGE_HW_RENDER. These
+ * will be merged with the usage flags specified by
+ * IGraphicBufferConsumer::setConsumerUsageBits.
+ *
+ * This call will block until a buffer is available to be dequeued. If
+ * both the producer and consumer are controlled by the app, then this call
+ * can never block and will return WOULD_BLOCK if no buffer is available.
+ *
+ * A non-negative value with flags set (see above) will be returned upon
+ * success as status.
+ *
+ * Return of a negative means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - both in async mode and buffer count was less than the
+ * max numbers of buffers that can be allocated at once.
+ * * INVALID_OPERATION - cannot attach the buffer because it would cause
+ * too many buffers to be dequeued, either because
+ * the producer already has a single buffer dequeued
+ * and did not set a buffer count, or because a
+ * buffer count was set and this call would cause
+ * it to be exceeded.
+ * * WOULD_BLOCK - no buffer is currently available, and blocking is disabled
+ * since both the producer/consumer are controlled by app
+ * * NO_MEMORY - out of memory, cannot allocate the graphics buffer.
+ * * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while
+ * waiting for a buffer to become available.
+ *
+ * All other negative values are an unknown error returned downstream
+ * from the graphics allocator (typically errno).
+ */
+ dequeueBuffer(
+ uint32_t width,
+ uint32_t height,
+ PixelFormat format,
+ uint32_t usage,
+ bool getFrameTimestamps
+ ) generates (
+ Status status,
+ int32_t slot,
+ Fence fence,
+ FrameEventHistoryDelta outTimestamps
+ );
+
+ /**
+ * detachBuffer attempts to remove all ownership of the buffer in the given
+ * slot from the buffer queue. If this call succeeds, the slot will be
+ * freed, and there will be no way to obtain the buffer from this interface.
+ * The freed slot will remain unallocated until either it is selected to
+ * hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+ * to the slot. The buffer must have already been dequeued, and the caller
+ * must already possesses the sp<AnwBuffer> (i.e., must have called
+ * requestBuffer).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - the given slot number is invalid, either because it is
+ * out of the range [0, NUM_BUFFER_SLOTS), or because the slot
+ * it refers to is not currently dequeued and requested.
+ */
+ detachBuffer(
+ int32_t slot
+ ) generates (
+ Status status
+ );
+
+ /**
+ * detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer,
+ * and detachBuffer in sequence, except for two things:
+ *
+ * 1) It is unnecessary to know the dimensions, format, or usage of the
+ * next buffer.
+ * 2) It will not block, since if it cannot find an appropriate buffer to
+ * return, it will return an error instead.
+ *
+ * Only slots that are free but still contain an AnwBuffer will be
+ * considered, and the oldest of those will be returned. buffer is
+ * equivalent to buffer from the requestBuffer call, and fence is
+ * equivalent to fence from the dequeueBuffer call.
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - either outBuffer or outFence were NULL.
+ * * NO_MEMORY - no slots were found that were both free and contained a
+ * AnwBuffer.
+ */
+ detachNextBuffer(
+ ) generates (
+ Status status,
+ AnwBuffer buffer,
+ Fence fence
+ );
+
+ /**
+ * attachBuffer attempts to transfer ownership of a buffer to the buffer
+ * queue. If this call succeeds, it will be as if this buffer was dequeued
+ * from the returned slot number. As such, this call will fail if attaching
+ * this buffer would cause too many buffers to be simultaneously dequeued.
+ *
+ * If attachBuffer returns the RELEASE_ALL_BUFFERS flag, the caller is
+ * expected to release all of the mirrored slot->buffer mappings.
+ *
+ * A non-negative value with flags set (see above) will be returned upon
+ * success.
+ *
+ * Return of a negative value means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - outSlot or buffer were NULL, invalid combination of
+ * async mode and buffer count override, or the generation
+ * number of the buffer did not match the buffer queue.
+ * * INVALID_OPERATION - cannot attach the buffer because it would cause
+ * too many buffers to be dequeued, either because
+ * the producer already has a single buffer dequeued
+ * and did not set a buffer count, or because a
+ * buffer count was set and this call would cause
+ * it to be exceeded.
+ * * WOULD_BLOCK - no buffer slot is currently available, and blocking is
+ * disabled since both the producer/consumer are
+ * controlled by the app.
+ * * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while
+ * waiting for a slot to become available.
+ */
+ attachBuffer(
+ AnwBuffer buffer
+ ) generates (
+ Status status,
+ int32_t slot
+ );
+
+ /**
+ * queueBuffer indicates that the client has finished filling in the
+ * contents of the buffer associated with slot and transfers ownership of
+ * that slot back to the server.
+ *
+ * It is not valid to call queueBuffer on a slot that is not owned
+ * by the client or one for which a buffer associated via requestBuffer
+ * (an attempt to do so will fail with a return value of BAD_VALUE).
+ *
+ * In addition, the input must be described by the client (as documented
+ * below). Any other properties (zero point, etc)
+ * are client-dependent, and should be documented by the client.
+ *
+ * The slot must be in the range of [0, NUM_BUFFER_SLOTS).
+ *
+ * Upon success, the output will be filled with meaningful values
+ * (refer to the documentation below).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - one of the below conditions occurred:
+ * * fence was NULL
+ * * scaling mode was unknown
+ * * both in async mode and buffer count was less than the
+ * max numbers of buffers that can be allocated at once
+ * * slot index was out of range (see above).
+ * * the slot was not in the dequeued state
+ * * the slot was enqueued without requesting a buffer
+ * * crop rect is out of bounds of the buffer dimensions
+ */
+ queueBuffer(
+ int32_t slot,
+ QueueBufferInput input
+ ) generates (
+ Status status,
+ QueueBufferOutput output
+ );
+
+ /**
+ * cancelBuffer indicates that the client does not wish to fill in the
+ * buffer associated with slot and transfers ownership of the slot back to
+ * the server.
+ *
+ * The buffer is not queued for use by the consumer.
+ *
+ * The slot must be in the range of [0, NUM_BUFFER_SLOTS).
+ *
+ * The buffer will not be overwritten until the fence signals. The fence
+ * will usually be the one obtained from dequeueBuffer.
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned or the producer is not
+ * connected.
+ * * BAD_VALUE - one of the below conditions occurred:
+ * * fence was NULL
+ * * slot index was out of range (see above).
+ * * the slot was not in the dequeued state
+ */
+ cancelBuffer(
+ int32_t slot,
+ Fence fence
+ ) generates (
+ Status status
+ );
+
+ /**
+ * query retrieves some information for this surface
+ * 'what' tokens allowed are that of NATIVE_WINDOW_* in <window.h>
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - the buffer queue has been abandoned.
+ * * BAD_VALUE - what was out of range
+ */
+ query(
+ int32_t what
+ ) generates (
+ int32_t result,
+ int32_t value
+ );
+
+ /**
+ * connect attempts to connect a client API to the IGraphicBufferProducer.
+ * This must be called before any other IGraphicBufferProducer methods are
+ * called except for getAllocator. A consumer must be already connected.
+ *
+ * This method will fail if the connect was previously called on the
+ * IGraphicBufferProducer and no corresponding disconnect call was made.
+ *
+ * The listener is an optional binder callback object that can be used if
+ * the producer wants to be notified when the consumer releases a buffer
+ * back to the BufferQueue. It is also used to detect the death of the
+ * producer. If only the latter functionality is desired, there is a
+ * DummyProducerListener class in IProducerListener.h that can be used.
+ *
+ * The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
+ *
+ * The producerControlledByApp should be set to true if the producer is hosted
+ * by an untrusted process (typically app_process-forked processes). If both
+ * the producer and the consumer are app-controlled then all buffer queues
+ * will operate in async mode regardless of the async flag.
+ *
+ * Upon success, the output will be filled with meaningful data
+ * (refer to QueueBufferOutput documentation above).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * NO_INIT - one of the following occurred:
+ * * the buffer queue was abandoned
+ * * no consumer has yet connected
+ * * BAD_VALUE - one of the following has occurred:
+ * * the producer is already connected
+ * * api was out of range (see above).
+ * * output was NULL.
+ * * Failure to adjust the number of available slots. This can
+ * happen because of trying to allocate/deallocate the async
+ * buffer in response to the value of producerControlledByApp.
+ * * DEAD_OBJECT - the token is hosted by an already-dead process
+ *
+ * Additional negative errors may be returned by the internals, they
+ * should be treated as opaque fatal unrecoverable errors.
+ */
+ connect(
+ IProducerListener listener,
+ int32_t api,
+ bool producerControlledByApp
+ ) generates (
+ Status status,
+ QueueBufferOutput output
+ );
+
+ /**
+ * disconnect attempts to disconnect a client API from the
+ * IGraphicBufferProducer. Calling this method will cause any subsequent
+ * calls to other IGraphicBufferProducer methods to fail except for
+ * getAllocator and connect. Successfully calling connect after this will
+ * allow the other methods to succeed again.
+ *
+ * The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
+ *
+ * Alternatively if mode is AllLocal, then the API value is ignored, and any API
+ * connected from the same PID calling disconnect will be disconnected.
+ *
+ * Disconnecting from an abandoned IGraphicBufferProducer is legal and
+ * is considered a no-op.
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * BAD_VALUE - one of the following has occurred:
+ * * the api specified does not match the one that was connected
+ * * api was out of range (see above).
+ * * DEAD_OBJECT - the token is hosted by an already-dead process
+ */
+ disconnect(
+ int32_t api,
+ DisconnectMode mode /* = DisconnectMode::API */
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Attaches a sideband buffer stream to the IGraphicBufferProducer.
+ *
+ * A sideband stream is a device-specific mechanism for passing buffers
+ * from the producer to the consumer without using dequeueBuffer/
+ * queueBuffer. If a sideband stream is present, the consumer can choose
+ * whether to acquire buffers from the sideband stream or from the queued
+ * buffers.
+ *
+ * Passing NULL or a different stream handle will detach the previous
+ * handle if any.
+ */
+ setSidebandStream(
+ handle stream
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Allocates buffers based on the given dimensions/format.
+ *
+ * This function will allocate up to the maximum number of buffers
+ * permitted by the current BufferQueue configuration. It will use the
+ * given format, dimensions, and usage bits, which are interpreted in the
+ * same way as for dequeueBuffer, and the async flag must be set the same
+ * way as for dequeueBuffer to ensure that the correct number of buffers are
+ * allocated. This is most useful to avoid an allocation delay during
+ * dequeueBuffer. If there are already the maximum number of buffers
+ * allocated, this function has no effect.
+ */
+ allocateBuffers(
+ uint32_t width,
+ uint32_t height,
+ PixelFormat format,
+ uint32_t usage
+ );
+
+ /**
+ * Sets whether dequeueBuffer is allowed to allocate new buffers.
+ *
+ * Normally dequeueBuffer does not discriminate between free slots which
+ * already have an allocated buffer and those which do not, and will
+ * allocate a new buffer if the slot doesn't have a buffer or if the slot's
+ * buffer doesn't match the requested size, format, or usage. This method
+ * allows the producer to restrict the eligible slots to those which already
+ * have an allocated buffer of the correct size, format, and usage. If no
+ * eligible slot is available, dequeueBuffer will block or return an error
+ * as usual.
+ */
+ allowAllocation(
+ bool allow
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Sets the current generation number of the BufferQueue.
+ *
+ * This generation number will be inserted into any buffers allocated by the
+ * BufferQueue, and any attempts to attach a buffer with a different
+ * generation number will fail. Buffers already in the queue are not
+ * affected and will retain their current generation number. The generation
+ * number defaults to 0.
+ */
+ setGenerationNumber(
+ uint32_t generationNumber
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Returns the name of the connected consumer.
+ */
+ getConsumerName(
+ ) generates (
+ string name
+ );
+
+ /**
+ * Used to enable/disable shared buffer mode.
+ *
+ * When shared buffer mode is enabled the first buffer that is queued or
+ * dequeued will be cached and returned to all subsequent calls to
+ * dequeueBuffer and acquireBuffer. This allows the producer and consumer to
+ * simultaneously access the same buffer.
+ */
+ setSharedBufferMode(
+ bool sharedBufferMode
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Used to enable/disable auto-refresh.
+ *
+ * Auto refresh has no effect outside of shared buffer mode. In shared
+ * buffer mode, when enabled, it indicates to the consumer that it should
+ * attempt to acquire buffers even if it is not aware of any being
+ * available.
+ */
+ setAutoRefresh(
+ bool autoRefresh
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Sets how long dequeueBuffer will wait for a buffer to become available
+ * before returning an error (TIMED_OUT).
+ *
+ * This timeout also affects the attachBuffer call, which will block if
+ * there is not a free slot available into which the attached buffer can be
+ * placed.
+ *
+ * By default, the BufferQueue will wait forever, which is indicated by a
+ * timeout of -1. If set (to a value other than -1), this will disable
+ * non-blocking mode and its corresponding spare buffer (which is used to
+ * ensure a buffer is always available).
+ *
+ * Return of a value other than NO_ERROR means an error has occurred:
+ * * BAD_VALUE - Failure to adjust the number of available slots. This can
+ * happen because of trying to allocate/deallocate the async
+ * buffer.
+ */
+ setDequeueTimeout(
+ int64_t timeoutNs
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Returns the last queued buffer along with a fence which must signal
+ * before the contents of the buffer are read. If there are no buffers in
+ * the queue, buffer.nativeHandle and fence will be null handles.
+ *
+ * transformMatrix is meaningless if buffer.nativeHandle is null.
+ */
+ getLastQueuedBuffer(
+ ) generates (
+ Status status,
+ AnwBuffer buffer,
+ Fence fence,
+ float[16] transformMatrix
+ );
+
+ /**
+ * Gets the frame events that haven't already been retrieved.
+ */
+ getFrameTimestamps(
+ ) generates (
+ FrameEventHistoryDelta timeStamps
+ );
+
+ /**
+ * Returns a unique id for this BufferQueue.
+ */
+ getUniqueId(
+ ) generates (
+ Status status,
+ uint64_t outId
+ );
+
+};
+
+
diff --git a/graphics/bufferqueue/1.0/IProducerListener.hal b/graphics/bufferqueue/1.0/IProducerListener.hal
new file mode 100644
index 0000000..206a500
--- /dev/null
+++ b/graphics/bufferqueue/1.0/IProducerListener.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.graphics.bufferqueue@1.0;
+
+/**
+ * Ref: frameworks/native/include/gui/IProducerListener.h: IProducerListener
+ * This is a wrapper/wrapped HAL interface for the actual binder interface.
+ */
+interface IProducerListener {
+ oneway onBufferReleased();
+ needsReleaseNotify() generates (bool result);
+};
+
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
new file mode 100644
index 0000000..99370e8
--- /dev/null
+++ b/graphics/common/1.0/Android.bp
@@ -0,0 +1,53 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.common@1.0_hal",
+ srcs: [
+ "types.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.common@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.common@1.0",
+ srcs: [
+ ":android.hardware.graphics.common@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/common/1.0/types.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.common@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.common@1.0",
+ srcs: [
+ ":android.hardware.graphics.common@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/common/1.0/types.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.common@1.0",
+ generated_sources: ["android.hardware.graphics.common@1.0_genc++"],
+ generated_headers: ["android.hardware.graphics.common@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.common@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+}
diff --git a/graphics/common/1.0/Android.mk b/graphics/common/1.0/Android.mk
new file mode 100644
index 0000000..c08053d
--- /dev/null
+++ b/graphics/common/1.0/Android.mk
@@ -0,0 +1,291 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.graphics.common@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (ColorMode)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.ColorMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ColorTransform)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorTransform.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.ColorTransform
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Dataspace)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Dataspace.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Dataspace
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Hdr)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Hdr.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Hdr
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PixelFormat)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/PixelFormat.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.PixelFormat
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Transform)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Transform.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Transform
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.graphics.common@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+#
+# Build types.hal (ColorMode)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.ColorMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ColorTransform)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorTransform.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.ColorTransform
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Dataspace)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Dataspace.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Dataspace
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Hdr)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Hdr.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Hdr
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PixelFormat)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/PixelFormat.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.PixelFormat
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Transform)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Transform.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0::types.Transform
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.graphics.common@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.graphics.common@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/graphics/common/1.0/types.hal b/graphics/common/1.0/types.hal
new file mode 100644
index 0000000..dfecec1
--- /dev/null
+++ b/graphics/common/1.0/types.hal
@@ -0,0 +1,1409 @@
+/*
+ * Copyright (C) 2016 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.graphics.common@1.0;
+
+/**
+ * pixel format definitions
+ */
+@export(name="android_pixel_format_t", value_prefix="HAL_PIXEL_FORMAT_")
+enum PixelFormat : int32_t {
+ /*
+ * "linear" color pixel formats:
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ *
+ * The color space determines, for example, if the formats are linear or
+ * gamma-corrected; or whether any special operations are performed when
+ * reading or writing into a buffer in one of these formats.
+ */
+ RGBA_8888 = 1,
+ RGBX_8888 = 2,
+ RGB_888 = 3,
+ RGB_565 = 4,
+ BGRA_8888 = 5,
+
+ /*
+ * The following formats use 10bit integers for R, G, and B and
+ * 2 bits for alpha. This is used to improve color precision on
+ * wide-color devices, e.g. Display-P3 or scRGB.
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ RGBA_1010102 = 0x2B,
+
+ /*
+ * The following formats use a 16bit float per color component.
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ RGBA_FP16 = 0x16,
+
+ /*
+ * 0x101 - 0x1FF
+ *
+ * This range is reserved for pixel formats that are specific to the HAL
+ * implementation. Implementations can use any value in this range to
+ * communicate video pixel formats between their HAL modules. These formats
+ * must not have an alpha channel. Additionally, an EGLimage created from a
+ * gralloc buffer of one of these formats must be supported for use with the
+ * GL_OES_EGL_image_external OpenGL ES extension.
+ */
+
+ /*
+ * Android YUV format:
+ *
+ * This format is exposed outside of the HAL to software decoders and
+ * applications. EGLImageKHR must support it in conjunction with the
+ * OES_EGL_image_external extension.
+ *
+ * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
+ * by (W/2) x (H/2) Cr and Cb planes.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * y_size = stride * height
+ * c_stride = ALIGN(stride/2, 16)
+ * c_size = c_stride * height/2
+ * size = y_size + c_size * 2
+ * cr_offset = y_size
+ * cb_offset = y_size + c_size
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ YV12 = 0x32315659, // YCrCb 4:2:0 Planar
+
+
+ /*
+ * Android Y8 format:
+ *
+ * This format is exposed outside of the HAL to the framework.
+ * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
+ * and no other HW_ flags will be used.
+ *
+ * Y8 is a YUV planar format comprised of a WxH Y plane,
+ * with each pixel being represented by 8 bits.
+ *
+ * It is equivalent to just the Y plane from YV12.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * size = stride * height
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ Y8 = 0x20203859,
+
+ /*
+ * Android Y16 format:
+ *
+ * This format is exposed outside of the HAL to the framework.
+ * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
+ * and no other HW_ flags will be used.
+ *
+ * Y16 is a YUV planar format comprised of a WxH Y plane,
+ * with each pixel being represented by 16 bits.
+ *
+ * It is just like Y8, but has double the bits per pixel (little endian).
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer, except that dataSpace field
+ * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
+ * image where each sample is a distance value measured by a depth camera,
+ * plus an associated confidence value.
+ */
+ Y16 = 0x20363159,
+
+ /*
+ * Android RAW sensor format:
+ *
+ * This format is exposed outside of the camera HAL to applications.
+ *
+ * RAW16 is a single-channel, 16-bit, little endian format, typically
+ * representing raw Bayer-pattern images from an image sensor, with minimal
+ * processing.
+ *
+ * The exact pixel layout of the data in the buffer is sensor-dependent, and
+ * needs to be queried from the camera device.
+ *
+ * Generally, not all 16 bits are used; more common values are 10 or 12
+ * bits. If not all bits are used, the lower-order bits are filled first.
+ * All parameters to interpret the raw data (black and white points,
+ * color space, etc) must be queried from the camera device.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ * - strides are specified in pixels, not in bytes
+ *
+ * size = stride * height * 2
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ *
+ * When used with ANativeWindow, the dataSpace should be
+ * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+ * extra metadata to define.
+ */
+ RAW16 = 0x20,
+
+ /*
+ * Android RAW10 format:
+ *
+ * This format is exposed outside of the camera HAL to applications.
+ *
+ * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+ * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+ * contains the 2 least significant bits of the 4 pixels, the exact layout data
+ * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+ * bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * =====|=====|=====|=====|=====|=====|=====|=====|
+ * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+ * |-----|-----|-----|-----|-----|-----|-----|-----|
+ * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+ * ===============================================
+ *
+ * This format assumes
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (10 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (10 / 8), padding bytes will be present at the end of each
+ * row (including the last row).
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ *
+ * When used with ANativeWindow, the dataSpace field should be
+ * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+ * extra metadata to define.
+ */
+ RAW10 = 0x25,
+
+ /*
+ * Android RAW12 format:
+ *
+ * This format is exposed outside of camera HAL to applications.
+ *
+ * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
+ * unprocessed format, usually representing raw Bayer-pattern images coming from
+ * an image sensor.
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+ * and second byte contains the top 8 bits of first and second pixel. The third
+ * byte contains the 4 least significant bits of the two pixels, the exact layout
+ * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+ * the jth bit of the ith pixel):
+ *
+ * bit 7 bit 0
+ * ======|======|======|======|======|======|======|======|
+ * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
+ * |------|------|------|------|------|------|------|------|
+ * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
+ * =======================================================
+ *
+ * This format assumes:
+ * - a width multiple of 4 pixels
+ * - an even height
+ * - a vertical stride equal to the height
+ * - strides are specified in bytes, not in pixels
+ *
+ * size = stride * height
+ *
+ * When stride is equal to width * (12 / 8), there will be no padding bytes at
+ * the end of each row, the entire image data is densely packed. When stride is
+ * larger than width * (12 / 8), padding bytes will be present at the end of
+ * each row (including the last row).
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ *
+ * When used with ANativeWindow, the dataSpace field should be
+ * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+ * extra metadata to define.
+ */
+ RAW12 = 0x26,
+
+ /*
+ * Android opaque RAW format:
+ *
+ * This format is exposed outside of the camera HAL to applications.
+ *
+ * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+ * image sensor. The actual structure of buffers of this format is
+ * implementation-dependent.
+ *
+ * This format must be accepted by the gralloc module when used with the
+ * following usage flags:
+ * - GRALLOC_USAGE_HW_CAMERA_*
+ * - GRALLOC_USAGE_SW_*
+ * - GRALLOC_USAGE_RENDERSCRIPT
+ *
+ * When used with ANativeWindow, the dataSpace field should be
+ * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+ * extra metadata to define.
+ */
+ RAW_OPAQUE = 0x24,
+
+ /*
+ * Android binary blob graphics buffer format:
+ *
+ * This format is used to carry task-specific data which does not have a
+ * standard image structure. The details of the format are left to the two
+ * endpoints.
+ *
+ * A typical use case is for transporting JPEG-compressed images from the
+ * Camera HAL to the framework or to applications.
+ *
+ * Buffers of this format must have a height of 1, and width equal to their
+ * size in bytes.
+ *
+ * When used with ANativeWindow, the mapping of the dataSpace field to
+ * buffer contents for BLOB is as follows:
+ *
+ * dataSpace value | Buffer contents
+ * -------------------------------+-----------------------------------------
+ * HAL_DATASPACE_JFIF | An encoded JPEG image
+ * HAL_DATASPACE_DEPTH | An android_depth_points buffer
+ * HAL_DATASPACE_SENSOR | Sensor event data.
+ * Other | Unsupported
+ *
+ */
+ BLOB = 0x21,
+
+ /*
+ * Android format indicating that the choice of format is entirely up to the
+ * device-specific Gralloc implementation.
+ *
+ * The Gralloc implementation should examine the usage bits passed in when
+ * allocating a buffer with this format, and it should derive the pixel
+ * format from those usage flags. This format will never be used with any
+ * of the GRALLOC_USAGE_SW_* usage flags.
+ *
+ * If a buffer of this format is to be used as an OpenGL ES texture, the
+ * framework will assume that sampling the texture will always return an
+ * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ IMPLEMENTATION_DEFINED = 0x22,
+
+ /*
+ * Android flexible YCbCr 4:2:0 formats
+ *
+ * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called YCbCr, it can be
+ * used to describe formats with either chromatic ordering, as well as
+ * whole planar or semiplanar layouts.
+ *
+ * struct android_ycbcr (below) is the the struct used to describe it.
+ *
+ * This format must be accepted by the gralloc module when
+ * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
+ *
+ * This format is locked for use by gralloc's (*lock_ycbcr) method, and
+ * locking with the (*lock) method will return an error.
+ *
+ * When used with ANativeWindow, the dataSpace field describes the color
+ * space of the buffer.
+ */
+ YCBCR_420_888 = 0x23,
+
+ /*
+ * Android flexible YCbCr 4:2:2 formats
+ *
+ * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called YCbCr, it can be
+ * used to describe formats with either chromatic ordering, as well as
+ * whole planar or semiplanar layouts.
+ *
+ * This format is currently only used by SW readable buffers
+ * produced by MediaCodecs, so the gralloc module can ignore this format.
+ */
+ YCBCR_422_888 = 0x27,
+
+ /*
+ * Android flexible YCbCr 4:4:4 formats
+ *
+ * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called YCbCr, it can be
+ * used to describe formats with either chromatic ordering, as well as
+ * whole planar or semiplanar layouts.
+ *
+ * This format is currently only used by SW readable buffers
+ * produced by MediaCodecs, so the gralloc module can ignore this format.
+ */
+ YCBCR_444_888 = 0x28,
+
+ /*
+ * Android flexible RGB 888 formats
+ *
+ * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called RGB, it can be
+ * used to describe formats with either color ordering and optional
+ * padding, as well as whole planar layout.
+ *
+ * This format is currently only used by SW readable buffers
+ * produced by MediaCodecs, so the gralloc module can ignore this format.
+ */
+ FLEX_RGB_888 = 0x29,
+
+ /*
+ * Android flexible RGBA 8888 formats
+ *
+ * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
+ * buffer layout, while still describing the general format in a
+ * layout-independent manner. While called RGBA, it can be
+ * used to describe formats with any of the component orderings, as
+ * well as whole planar layout.
+ *
+ * This format is currently only used by SW readable buffers
+ * produced by MediaCodecs, so the gralloc module can ignore this format.
+ */
+ FLEX_RGBA_8888 = 0x2A,
+
+ /* Legacy formats (deprecated), used by ImageFormat.java */
+ YCBCR_422_SP = 0x10, // NV16
+ YCRCB_420_SP = 0x11, // NV21
+ YCBCR_422_I = 0x14, // YUY2
+ JPEG = 0x100,
+};
+
+/**
+ * Transformation definitions
+ *
+ * IMPORTANT NOTE:
+ * ROT_90 is applied CLOCKWISE and AFTER FLIP_{H|V}.
+ *
+ */
+@export(name="android_transform_t", value_prefix="HAL_TRANSFORM_")
+enum Transform : int32_t {
+ /* flip source image horizontally (around the vertical axis) */
+ FLIP_H = 0x01,
+ /* flip source image vertically (around the horizontal axis)*/
+ FLIP_V = 0x02,
+ /* rotate source image 90 degrees clockwise */
+ ROT_90 = 0x04,
+ /* rotate source image 180 degrees */
+ ROT_180 = 0x03,
+ /* rotate source image 270 degrees clockwise */
+ ROT_270 = 0x07,
+
+ /* 0x08 is reserved */
+};
+
+/**
+ * Dataspace Definitions
+ * ======================
+ *
+ * Dataspace is the definition of how pixel values should be interpreted.
+ *
+ * For many formats, this is the colorspace of the image data, which includes
+ * primaries (including white point) and the transfer characteristic function,
+ * which describes both gamma curve and numeric range (within the bit depth).
+ *
+ * Other dataspaces include depth measurement data from a depth camera.
+ *
+ * A dataspace is comprised of a number of fields.
+ *
+ * Version
+ * --------
+ * The top 2 bits represent the revision of the field specification. This is
+ * currently always 0.
+ *
+ *
+ * bits 31-30 29 - 0
+ * +-----+----------------------------------------------------+
+ * fields | Rev | Revision specific fields |
+ * +-----+----------------------------------------------------+
+ *
+ * Field layout for version = 0:
+ * ----------------------------
+ *
+ * A dataspace is comprised of the following fields:
+ * Standard
+ * Transfer function
+ * Range
+ *
+ * bits 31-30 29-27 26 - 22 21 - 16 15 - 0
+ * +-----+-----+--------+--------+----------------------------+
+ * fields | 0 |Range|Transfer|Standard| Legacy and custom |
+ * +-----+-----+--------+--------+----------------------------+
+ * VV RRR TTTTT SSSSSS LLLLLLLL LLLLLLLL
+ *
+ * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
+ * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
+ * or a custom value.
+ */
+@export(name="android_dataspace_t", value_prefix="HAL_DATASPACE_")
+enum Dataspace : int32_t {
+ /*
+ * Default-assumption data space, when not explicitly specified.
+ *
+ * It is safest to assume the buffer is an image with sRGB primaries and
+ * encoding ranges, but the consumer and/or the producer of the data may
+ * simply be using defaults. No automatic gamma transform should be
+ * expected, except for a possible display gamma transform when drawn to a
+ * screen.
+ */
+ UNKNOWN = 0x0,
+
+ /*
+ * Arbitrary dataspace with manually defined characteristics. Definition
+ * for colorspaces or other meaning must be communicated separately.
+ *
+ * This is used when specifying primaries, transfer characteristics,
+ * etc. separately.
+ *
+ * A typical use case is in video encoding parameters (e.g. for H.264),
+ * where a colorspace can have separately defined primaries, transfer
+ * characteristics, etc.
+ */
+ ARBITRARY = 0x1,
+
+ /*
+ * Color-description aspects
+ *
+ * The following aspects define various characteristics of the color
+ * specification. These represent bitfields, so that a data space value
+ * can specify each of them independently.
+ */
+
+ STANDARD_SHIFT = 16,
+
+ /*
+ * Standard aspect
+ *
+ * Defines the chromaticity coordinates of the source primaries in terms of
+ * the CIE 1931 definition of x and y specified in ISO 11664-1.
+ */
+ STANDARD_MASK = 63 << STANDARD_SHIFT, // 0x3F
+
+ /*
+ * Chromacity coordinates are unknown or are determined by the application.
+ * Implementations shall use the following suggested standards:
+ *
+ * All YCbCr formats: BT709 if size is 720p or larger (since most video
+ * content is letterboxed this corresponds to width is
+ * 1280 or greater, or height is 720 or greater).
+ * BT601_625 if size is smaller than 720p or is JPEG.
+ * All RGB formats: BT709.
+ *
+ * For all other formats standard is undefined, and implementations should use
+ * an appropriate standard for the data represented.
+ */
+ STANDARD_UNSPECIFIED = 0 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT709 = 1 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_625 = 2 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT601_625_UNADJUSTED = 3 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_525 = 4 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ */
+ STANDARD_BT601_525_UNADJUSTED = 5 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT2020 = 6 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion using the linear domain.
+ */
+ STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.21 0.71
+ * blue 0.14 0.08
+ * red 0.67 0.33
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT470M = 8 << STANDARD_SHIFT,
+
+ /*
+ * Primaries: x y
+ * green 0.243 0.692
+ * blue 0.145 0.049
+ * red 0.681 0.319
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_FILM = 9 << STANDARD_SHIFT,
+
+ /*
+ * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+ * Primaries: x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_DCI_P3 = 10 << STANDARD_SHIFT,
+
+ /*
+ * Adobe RGB
+ * Primaries: x y
+ * green 0.210 0.710
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_ADOBE_RGB = 11 << STANDARD_SHIFT,
+
+
+
+ TRANSFER_SHIFT = 22,
+
+ /*
+ * Transfer aspect
+ *
+ * Transfer characteristics are the opto-electronic transfer characteristic
+ * at the source as a function of linear optical intensity (luminance).
+ *
+ * For digital signals, E corresponds to the recorded value. Normally, the
+ * transfer function is applied in RGB space to each of the R, G and B
+ * components independently. This may result in color shift that can be
+ * minized by applying the transfer function in Lab space only for the L
+ * component. Implementation may apply the transfer function in RGB space
+ * for all pixel formats if desired.
+ */
+
+ TRANSFER_MASK = 31 << TRANSFER_SHIFT, // 0x1F
+
+ /*
+ * Transfer characteristics are unknown or are determined by the
+ * application.
+ *
+ * Implementations should use the following transfer functions:
+ *
+ * For YCbCr formats: use TRANSFER_SMPTE_170M
+ * For RGB formats: use TRANSFER_SRGB
+ *
+ * For all other formats transfer function is undefined, and implementations
+ * should use an appropriate standard for the data represented.
+ */
+ TRANSFER_UNSPECIFIED = 0 << TRANSFER_SHIFT,
+
+ /*
+ * Transfer characteristic curve:
+ * E = L
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_LINEAR = 1 << TRANSFER_SHIFT,
+
+ /*
+ * Transfer characteristic curve:
+ *
+ * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
+ * = 12.92 * L for 0 <= L < 0.0031308
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SRGB = 2 << TRANSFER_SHIFT,
+
+ /*
+ * BT.601 525, BT.601 625, BT.709, BT.2020
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
+ * = 4.500 * L for 0 <= L < 0.018
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SMPTE_170M = 3 << TRANSFER_SHIFT,
+
+ /*
+ * Assumed display gamma 2.2.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.2)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_2 = 4 << TRANSFER_SHIFT,
+
+ /*
+ * display gamma 2.6.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.6)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_6 = 5 << TRANSFER_SHIFT,
+
+ /*
+ * display gamma 2.8.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.8)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_8 = 6 << TRANSFER_SHIFT,
+
+ /*
+ * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+ *
+ * Transfer characteristic curve:
+ * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+ * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+ * c2 = 32 * 2413 / 4096 = 18.8515625
+ * c3 = 32 * 2392 / 4096 = 18.6875
+ * m = 128 * 2523 / 4096 = 78.84375
+ * n = 0.25 * 2610 / 4096 = 0.1593017578125
+ * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+ * L = 1 corresponds to 10000 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_ST2084 = 7 << TRANSFER_SHIFT,
+
+ /*
+ * ARIB STD-B67 Hybrid Log Gamma
+ *
+ * Transfer characteristic curve:
+ * E = r * L^0.5 for 0 <= L <= 1
+ * = a * ln(L - b) + c for 1 < L
+ * a = 0.17883277
+ * b = 0.28466892
+ * c = 0.55991073
+ * r = 0.5
+ * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+ * to reference white level of 100 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_HLG = 8 << TRANSFER_SHIFT,
+
+ RANGE_SHIFT = 27,
+
+ /*
+ * Range aspect
+ *
+ * Defines the range of values corresponding to the unit range of 0-1.
+ * This is defined for YCbCr only, but can be expanded to RGB space.
+ */
+ RANGE_MASK = 7 << RANGE_SHIFT, // 0x7
+
+ /*
+ * Range is unknown or are determined by the application. Implementations
+ * shall use the following suggested ranges:
+ *
+ * All YCbCr formats: limited range.
+ * All RGB or RGBA formats (including RAW and Bayer): full range.
+ * All Y formats: full range
+ *
+ * For all other formats range is undefined, and implementations should use
+ * an appropriate range for the data represented.
+ */
+ RANGE_UNSPECIFIED = 0 << RANGE_SHIFT,
+
+ /*
+ * Full range uses all values for Y, Cb and Cr from
+ * 0 to 2^b-1, where b is the bit depth of the color format.
+ */
+ RANGE_FULL = 1 << RANGE_SHIFT,
+
+ /*
+ * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+ * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+ * the color format.
+ *
+ * E.g. For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ */
+ RANGE_LIMITED = 2 << RANGE_SHIFT,
+
+ /*
+ * Extended range is used for scRGB. Intended for use with
+ * floating point pixel formats. [0.0 - 1.0] is the standard
+ * sRGB space. Values outside the range 0.0 - 1.0 can encode
+ * color outside the sRGB gamut.
+ * Used to blend / merge multiple dataspaces on a single display.
+ */
+ RANGE_EXTENDED = 3 << RANGE_SHIFT,
+
+ /*
+ * Legacy dataspaces
+ */
+
+ /*
+ * sRGB linear encoding:
+ *
+ * The red, green, and blue components are stored in sRGB space, but
+ * are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are encoded using the full range ([0,255] for 8-bit) for all
+ * components.
+ */
+ SRGB_LINEAR = 0x200, // deprecated, use V0_SRGB_LINEAR
+
+ V0_SRGB_LINEAR = STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL,
+
+
+ /*
+ * scRGB linear encoding:
+ *
+ * The red, green, and blue components are stored in extended sRGB space,
+ * but are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are floating point.
+ * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+ * Values beyond the range [0.0 - 1.0] would correspond to other colors
+ * spaces and/or HDR content.
+ */
+ V0_SCRGB_LINEAR = STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED,
+
+
+ /*
+ * sRGB gamma encoding:
+ *
+ * The red, green and blue components are stored in sRGB space, and
+ * converted to linear space when read, using the SRGB transfer function
+ * for each of the R, G and B components. When written, the inverse
+ * transformation is performed.
+ *
+ * The alpha component, if present, is always stored in linear space and
+ * is left unmodified when read or written.
+ *
+ * Use full range and BT.709 standard.
+ */
+ SRGB = 0x201, // deprecated, use V0_SRGB
+
+ V0_SRGB = STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL,
+
+
+ /*
+ * scRGB:
+ *
+ * The red, green, and blue components are stored in extended sRGB space,
+ * but are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are floating point.
+ * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+ * Values beyond the range [0.0 - 1.0] would correspond to other colors
+ * spaces and/or HDR content.
+ */
+ V0_SCRGB = STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED,
+
+ /*
+ * YCbCr Colorspaces
+ * -----------------
+ *
+ * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+ * of x and y specified by ISO 11664-1.
+ *
+ * Transfer characteristics are the opto-electronic transfer characteristic
+ * at the source as a function of linear optical intensity (luminance).
+ */
+
+ /*
+ * JPEG File Interchange Format (JFIF)
+ *
+ * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+ *
+ * Use full range, BT.601 transfer and BT.601_625 standard.
+ */
+ JFIF = 0x101, // deprecated, use V0_JFIF
+
+ V0_JFIF = STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL,
+
+ /*
+ * ITU-R Recommendation 601 (BT.601) - 625-line
+ *
+ * Standard-definition television, 625 Lines (PAL)
+ *
+ * Use limited range, BT.601 transfer and BT.601_625 standard.
+ */
+ BT601_625 = 0x102, // deprecated, use V0_BT601_625
+
+ V0_BT601_625 = STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
+
+
+ /*
+ * ITU-R Recommendation 601 (BT.601) - 525-line
+ *
+ * Standard-definition television, 525 Lines (NTSC)
+ *
+ * Use limited range, BT.601 transfer and BT.601_525 standard.
+ */
+ BT601_525 = 0x103, // deprecated, use V0_BT601_525
+
+ V0_BT601_525 = STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
+
+ /*
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * Use limited range, BT.709 transfer and BT.709 standard.
+ */
+ BT709 = 0x104, // deprecated, use V0_BT709
+
+ V0_BT709 = STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
+
+
+ /*
+ * SMPTE EG 432-1 and SMPTE RP 431-2.
+ *
+ * Digital Cinema DCI-P3
+ *
+ * Use full range, linear transfer and D65 DCI-P3 standard
+ */
+ DCI_P3_LINEAR = STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL,
+
+
+ /*
+ * SMPTE EG 432-1 and SMPTE RP 431-2.
+ *
+ * Digital Cinema DCI-P3
+ *
+ * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.6 gamma encoding is not supported in HW.
+ */
+ DCI_P3 = STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL,
+
+
+ /*
+ * Display P3
+ *
+ * Display P3 uses same primaries and white-point as DCI-P3
+ * linear transfer function makes this the same as DCI_P3_LINEAR.
+ */
+ DISPLAY_P3_LINEAR = STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL,
+
+
+ /*
+ * Display P3
+ *
+ * Use same primaries and white-point as DCI-P3
+ * but sRGB transfer function.
+ */
+ DISPLAY_P3 = STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL,
+
+
+ /*
+ * Adobe RGB
+ *
+ * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.2 gamma encoding is not supported in HW.
+ */
+ ADOBE_RGB = STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL,
+
+
+ /*
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, linear transfer and BT2020 standard
+ */
+ BT2020_LINEAR = STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL,
+
+
+ /*
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, BT.709 transfer and BT2020 standard
+ */
+ BT2020 = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL,
+
+ /*
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+ */
+ BT2020_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL,
+
+
+ /*
+ * Data spaces for non-color formats
+ */
+
+ /*
+ * The buffer contains depth ranging measurements from a depth camera.
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
+ * and an associated confidence value. The 3 MSBs of the sample make
+ * up the confidence value, and the low 13 LSBs of the sample make up
+ * the depth measurement.
+ * For the confidence section, 0 means 100% confidence, 1 means 0%
+ * confidence. The mapping to a linear float confidence value between
+ * 0.f and 1.f can be obtained with
+ * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
+ * The depth measurement can be extracted simply with
+ * uint16_t range = (depthSample & 0x1FFF);
+ * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+ * a variable-length float (x,y,z, confidence) coordinate point list.
+ * The point cloud will be represented with the android_depth_points
+ * structure.
+ */
+ DEPTH = 0x1000,
+
+
+ /*
+ * The buffer contains sensor events from sensor direct report.
+ * This value is valid with formats:
+ * HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms
+ * a lock free queue. Format of sensor event structure is specified
+ * in Sensors HAL.
+ */
+ SENSOR = 0x1001
+};
+
+/*
+ * Color modes that may be supported by a display.
+ *
+ * Definitions:
+ * Rendering intent generally defines the goal in mapping a source (input)
+ * color to a destination device color for a given color mode.
+ *
+ * It is important to keep in mind three cases where mapping may be applied:
+ * 1. The source gamut is much smaller than the destination (display) gamut
+ * 2. The source gamut is much larger than the destination gamut (this will
+ * ordinarily be handled using colorimetric rendering, below)
+ * 3. The source and destination gamuts are roughly equal, although not
+ * completely overlapping
+ * Also, a common requirement for mappings is that skin tones should be
+ * preserved, or at least remain natural in appearance.
+ *
+ * Colorimetric Rendering Intent (All cases):
+ * Colorimetric indicates that colors should be preserved. In the case
+ * that the source gamut lies wholly within the destination gamut or is
+ * about the same (#1, #3), this will simply mean that no manipulations
+ * (no saturation boost, for example) are applied. In the case where some
+ * source colors lie outside the destination gamut (#2, #3), those will
+ * need to be mapped to colors that are within the destination gamut,
+ * while the already in-gamut colors remain unchanged.
+ *
+ * Non-colorimetric transforms can take many forms. There are no hard
+ * rules and it's left to the implementation to define.
+ * Two common intents are described below.
+ *
+ * Stretched-Gamut Enhancement Intent (Source < Destination):
+ * When the destination gamut is much larger than the source gamut (#1), the
+ * source primaries may be redefined to reflect the full extent of the
+ * destination space, or to reflect an intermediate gamut.
+ * Skin-tone preservation would likely be applied. An example might be sRGB
+ * input displayed on a DCI-P3 capable device, with skin-tone preservation.
+ *
+ * Within-Gamut Enhancement Intent (Source >= Destination):
+ * When the device (destination) gamut is not larger than the source gamut
+ * (#2 or #3), but the appearance of a larger gamut is desired, techniques
+ * such as saturation boost may be applied to the source colors. Skin-tone
+ * preservation may be applied. There is no unique method for within-gamut
+ * enhancement; it would be defined within a flexible color mode.
+ *
+ */
+@export(name="android_color_mode_t", value_prefix="HAL_COLOR_MODE_")
+enum ColorMode : int32_t {
+ /*
+ * DEFAULT is the "native" gamut of the display.
+ * White Point: Vendor/OEM defined
+ * Panel Gamma: Vendor/OEM defined (typically 2.2)
+ * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
+ */
+ NATIVE = 0,
+
+ /*
+ * STANDARD_BT601_625 corresponds with display
+ * settings that implement the ITU-R Recommendation BT.601
+ * or Rec 601. Using 625 line version
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ STANDARD_BT601_625 = 1,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ STANDARD_BT601_625_UNADJUSTED = 2,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ STANDARD_BT601_525 = 3,
+
+ /*
+ * Primaries:
+ * x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ *
+ * Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.500 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
+ */
+ STANDARD_BT601_525_UNADJUSTED = 4,
+
+ /*
+ * REC709 corresponds with display settings that implement
+ * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
+ * (with [0 to 1] range) value of R, G, or B.
+ *
+ * if Vnonlinear < 0.081
+ * Vlinear = Vnonlinear / 4.5
+ * else
+ * Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
+ *
+ * HDTV REC709 Gamma Correction (GC):
+ *
+ * if Vlinear < 0.018
+ * Vnonlinear = 4.5 * Vlinear
+ * else
+ * Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
+ */
+ STANDARD_BT709 = 5,
+
+ /*
+ * DCI_P3 corresponds with display settings that implement
+ * SMPTE EG 432-1 and SMPTE RP 431-2
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ *
+ * Gamma: 2.6
+ */
+ DCI_P3 = 6,
+
+ /*
+ * SRGB corresponds with display settings that implement
+ * the sRGB color space. Uses the same primaries as ITU-R Recommendation
+ * BT.709
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
+ *
+ * if Vnonlinear ≤ 0.03928
+ * Vlinear = Vnonlinear / 12.92
+ * else
+ * Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
+ *
+ * PC/Internet (sRGB) Gamma Correction (GC):
+ *
+ * if Vlinear ≤ 0.0031308
+ * Vnonlinear = 12.92 * Vlinear
+ * else
+ * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
+ */
+ SRGB = 7,
+
+ /*
+ * ADOBE_RGB corresponds with the RGB color space developed
+ * by Adobe Systems, Inc. in 1998.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.210 0.710
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Gamma: 2.2
+ */
+ ADOBE_RGB = 8,
+
+ /*
+ * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+ * the D65 white point and the SRGB transfer functions.
+ * Rendering Intent: Colorimetric
+ * Primaries:
+ * x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ *
+ * PC/Internet (sRGB) Gamma Correction (GC):
+ *
+ * if Vlinear ≤ 0.0030186
+ * Vnonlinear = 12.92 * Vlinear
+ * else
+ * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
+ *
+ * Note: In most cases sRGB transfer function will be fine.
+ */
+ DISPLAY_P3 = 9
+};
+
+/*
+ * Color transforms that may be applied by hardware composer to the whole
+ * display.
+ */
+@export(name="android_color_transform_t", value_prefix="HAL_COLOR_TRANSFORM_")
+enum ColorTransform : int32_t {
+ /* Applies no transform to the output color */
+ IDENTITY = 0,
+
+ /* Applies an arbitrary transform defined by a 4x4 affine matrix */
+ ARBITRARY_MATRIX = 1,
+
+ /* Applies a transform that inverts the value or luminance of the color, but
+ * does not modify hue or saturation */
+ VALUE_INVERSE = 2,
+
+ /* Applies a transform that maps all colors to shades of gray */
+ GRAYSCALE = 3,
+
+ /* Applies a transform which corrects for protanopic color blindness */
+ CORRECT_PROTANOPIA = 4,
+
+ /* Applies a transform which corrects for deuteranopic color blindness */
+ CORRECT_DEUTERANOPIA = 5,
+
+ /* Applies a transform which corrects for tritanopic color blindness */
+ CORRECT_TRITANOPIA = 6
+};
+
+/*
+ * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
+ */
+@export(name="android_hdr_t", value_prefix="HAL_HDR_")
+enum Hdr : int32_t {
+ /* Device supports Dolby Vision HDR */
+ DOLBY_VISION = 1,
+
+ /* Device supports HDR10 */
+ HDR10 = 2,
+
+ /* Device supports hybrid log-gamma HDR */
+ HLG = 3
+};
diff --git a/graphics/composer/2.1/Android.bp b/graphics/composer/2.1/Android.bp
new file mode 100644
index 0000000..f309439
--- /dev/null
+++ b/graphics/composer/2.1/Android.bp
@@ -0,0 +1,78 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.composer@2.1_hal",
+ srcs: [
+ "types.hal",
+ "IComposer.hal",
+ "IComposerCallback.hal",
+ "IComposerClient.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.composer@2.1_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.composer@2.1",
+ srcs: [
+ ":android.hardware.graphics.composer@2.1_hal",
+ ],
+ out: [
+ "android/hardware/graphics/composer/2.1/types.cpp",
+ "android/hardware/graphics/composer/2.1/ComposerAll.cpp",
+ "android/hardware/graphics/composer/2.1/ComposerCallbackAll.cpp",
+ "android/hardware/graphics/composer/2.1/ComposerClientAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.composer@2.1_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.composer@2.1",
+ srcs: [
+ ":android.hardware.graphics.composer@2.1_hal",
+ ],
+ out: [
+ "android/hardware/graphics/composer/2.1/types.h",
+ "android/hardware/graphics/composer/2.1/IComposer.h",
+ "android/hardware/graphics/composer/2.1/IHwComposer.h",
+ "android/hardware/graphics/composer/2.1/BnHwComposer.h",
+ "android/hardware/graphics/composer/2.1/BpHwComposer.h",
+ "android/hardware/graphics/composer/2.1/BsComposer.h",
+ "android/hardware/graphics/composer/2.1/IComposerCallback.h",
+ "android/hardware/graphics/composer/2.1/IHwComposerCallback.h",
+ "android/hardware/graphics/composer/2.1/BnHwComposerCallback.h",
+ "android/hardware/graphics/composer/2.1/BpHwComposerCallback.h",
+ "android/hardware/graphics/composer/2.1/BsComposerCallback.h",
+ "android/hardware/graphics/composer/2.1/IComposerClient.h",
+ "android/hardware/graphics/composer/2.1/IHwComposerClient.h",
+ "android/hardware/graphics/composer/2.1/BnHwComposerClient.h",
+ "android/hardware/graphics/composer/2.1/BpHwComposerClient.h",
+ "android/hardware/graphics/composer/2.1/BsComposerClient.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.1",
+ generated_sources: ["android.hardware.graphics.composer@2.1_genc++"],
+ generated_headers: ["android.hardware.graphics.composer@2.1_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.composer@2.1_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/graphics/composer/2.1/Android.mk b/graphics/composer/2.1/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/composer/2.1/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/composer/2.1/IComposer.hal b/graphics/composer/2.1/IComposer.hal
new file mode 100644
index 0000000..553a537
--- /dev/null
+++ b/graphics/composer/2.1/IComposer.hal
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.graphics.composer@2.1;
+
+import IComposerClient;
+
+interface IComposer {
+ /*
+ * Optional capabilities which may be supported by some devices. The
+ * particular set of supported capabilities for a given device may be
+ * retrieved using getCapabilities.
+ */
+ enum Capability : int32_t {
+ INVALID = 0,
+
+ /*
+ * Specifies that the device supports sideband stream layers, for
+ * which buffer content updates and other synchronization will not be
+ * provided through the usual validate/present cycle and must be
+ * handled by an external implementation-defined mechanism. Only
+ * changes to layer state (such as position, size, etc.) need to be
+ * performed through the validate/present cycle.
+ */
+ SIDEBAND_STREAM = 1,
+
+ /*
+ * Specifies that the device will apply a color transform even when
+ * either the client or the device has chosen that all layers should
+ * be composed by the client. This will prevent the client from
+ * applying the color transform during its composition step.
+ */
+ SKIP_CLIENT_COLOR_TRANSFORM = 2,
+ };
+
+ /*
+ * Provides a list of supported capabilities (as described in the
+ * definition of Capability above). This list must not change after
+ * initialization.
+ *
+ * @return capabilities is a list of supported capabilities.
+ */
+ @entry
+ @exit
+ @callflow(next="*")
+ getCapabilities() generates (vec<Capability> capabilities);
+
+ /*
+ * Retrieves implementation-defined debug information, which will be
+ * displayed during, for example, `dumpsys SurfaceFlinger`.
+ *
+ * @return debugInfo is a string of debug information.
+ */
+ @entry
+ @exit
+ @callflow(next="*")
+ dumpDebugInfo() generates (string debugInfo);
+
+ /*
+ * Creates a client of the composer. All resources created by the client
+ * are owned by the client and are only visible to the client.
+ *
+ * There can only be one client at any time.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when no more client can be created currently.
+ * @return client is the newly created client.
+ */
+ @entry
+ @callflow(next="*")
+ createClient() generates (Error error, IComposerClient client);
+};
diff --git a/graphics/composer/2.1/IComposerCallback.hal b/graphics/composer/2.1/IComposerCallback.hal
new file mode 100644
index 0000000..541d7eb
--- /dev/null
+++ b/graphics/composer/2.1/IComposerCallback.hal
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 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.graphics.composer@2.1;
+
+interface IComposerCallback {
+ enum Connection : int32_t {
+ INVALID = 0,
+
+ /* The display has been connected */
+ CONNECTED = 1,
+ /* The display has been disconnected */
+ DISCONNECTED = 2,
+ };
+
+ /*
+ * Notifies the client that the given display has either been connected or
+ * disconnected. Every active display (even a built-in physical display)
+ * must trigger at least one hotplug notification, even if it only occurs
+ * immediately after callback registration.
+ *
+ * Displays which have been connected are assumed to be in PowerMode::OFF,
+ * and the onVsync callback should not be called for a display until vsync
+ * has been enabled with setVsyncEnabled.
+ *
+ * The client may call back into the device while the callback is in
+ * progress. The device must serialize calls to this callback such that
+ * only one thread is calling it at a time.
+ *
+ * @param display is the display that triggers the hotplug event.
+ * @param connected indicates whether the display is connected or
+ * disconnected.
+ */
+ @callflow(next="*")
+ onHotplug(Display display, Connection connected);
+
+ /*
+ * Notifies the client to trigger a screen refresh. This forces all layer
+ * state for this display to be resent, and the display to be validated
+ * and presented, even if there have been no changes.
+
+ * This refresh will occur some time after the callback is initiated, but
+ * not necessarily before it returns. It is safe to trigger this callback
+ * from other functions which call into the device.
+ *
+ * @param display is the display to refresh.
+ */
+ @callflow(next="*")
+ oneway onRefresh(Display display);
+
+ /*
+ * Notifies the client that a vsync event has occurred. This callback must
+ * only be triggered when vsync is enabled for this display (through
+ * setVsyncEnabled).
+ *
+ * @param display is the display which has received a vsync event
+ * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event
+ * occurred, in nanoseconds.
+ */
+ @callflow(next="*")
+ oneway onVsync(Display display, int64_t timestamp);
+};
diff --git a/graphics/composer/2.1/IComposerClient.hal b/graphics/composer/2.1/IComposerClient.hal
new file mode 100644
index 0000000..107ac5e
--- /dev/null
+++ b/graphics/composer/2.1/IComposerClient.hal
@@ -0,0 +1,1142 @@
+/*
+ * Copyright (C) 2016 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.graphics.composer@2.1;
+
+import android.hardware.graphics.common@1.0;
+import IComposerCallback;
+
+interface IComposerClient {
+ /* Display attributes queryable through getDisplayAttribute. */
+ enum Attribute : int32_t {
+ INVALID = 0,
+
+ /* Dimensions in pixels */
+ WIDTH = 1,
+ HEIGHT = 2,
+
+ /* Vsync period in nanoseconds */
+ VSYNC_PERIOD = 3,
+
+ /*
+ * Dots per thousand inches (DPI * 1000). Scaling by 1000 allows these
+ * numbers to be stored in an int32_t without losing too much
+ * precision. If the DPI for a configuration is unavailable or is
+ * considered unreliable, the device may return UNSUPPORTED instead.
+ */
+ DPI_X = 4,
+ DPI_Y = 5,
+ };
+
+ /* Display requests returned by getDisplayRequests. */
+ enum DisplayRequest : uint32_t {
+ /*
+ * Instructs the client to provide a new client target buffer, even if
+ * no layers are marked for client composition.
+ */
+ FLIP_CLIENT_TARGET = 1 << 0,
+
+ /*
+ * Instructs the client to write the result of client composition
+ * directly into the virtual display output buffer. If any of the
+ * layers are not marked as Composition::CLIENT or the given display
+ * is not a virtual display, this request has no effect.
+ */
+ WRITE_CLIENT_TARGET_TO_OUTPUT = 1 << 1,
+ };
+
+ /* Layer requests returned from getDisplayRequests. */
+ enum LayerRequest : uint32_t {
+ /*
+ * The client must clear its target with transparent pixels where
+ * this layer would be. The client may ignore this request if the
+ * layer must be blended.
+ */
+ CLEAR_CLIENT_TARGET = 1 << 0,
+ };
+
+ /* Power modes for use with setPowerMode. */
+ enum PowerMode : int32_t {
+ /* The display is fully off (blanked). */
+ OFF = 0,
+
+ /*
+ * These are optional low power modes. getDozeSupport may be called to
+ * determine whether a given display supports these modes.
+ */
+
+ /*
+ * The display is turned on and configured in a low power state that
+ * is suitable for presenting ambient information to the user,
+ * possibly with lower fidelity than ON, but with greater efficiency.
+ */
+ DOZE = 1,
+
+ /*
+ * The display is configured as in DOZE but may stop applying display
+ * updates from the client. This is effectively a hint to the device
+ * that drawing to the display has been suspended and that the the
+ * device must remain on in a low power state and continue
+ * displaying its current contents indefinitely until the power mode
+ * changes.
+ *
+ * This mode may also be used as a signal to enable hardware-based
+ * doze functionality. In this case, the device is free to take over
+ * the display and manage it autonomously to implement a low power
+ * always-on display.
+ */
+ DOZE_SUSPEND = 3,
+
+ /* The display is fully on. */
+ ON = 2,
+ };
+
+ /* Vsync values passed to setVsyncEnabled. */
+ enum Vsync : int32_t {
+ INVALID = 0,
+
+ /* Enable vsync. */
+ ENABLE = 1,
+
+ /* Disable vsync. */
+ DISABLE = 2,
+ };
+
+ /* Blend modes, settable per layer. */
+ enum BlendMode : int32_t {
+ INVALID = 0,
+
+ /* colorOut = colorSrc */
+ NONE = 1,
+
+ /* colorOut = colorSrc + colorDst * (1 - alphaSrc) */
+ PREMULTIPLIED = 2,
+
+ /* colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */
+ COVERAGE = 3,
+ };
+
+ /* Possible composition types for a given layer. */
+ enum Composition : int32_t {
+ INVALID = 0,
+
+ /*
+ * The client must composite this layer into the client target buffer
+ * (provided to the device through setClientTarget).
+ *
+ * The device must not request any composition type changes for layers
+ * of this type.
+ */
+ CLIENT = 1,
+
+ /*
+ * The device must handle the composition of this layer through a
+ * hardware overlay or other similar means.
+ *
+ * Upon validateDisplay, the device may request a change from this
+ * type to CLIENT.
+ */
+ DEVICE = 2,
+
+ /*
+ * The device must render this layer using the color set through
+ * setLayerColor. If this functionality is not supported on a layer
+ * that the client sets to SOLID_COLOR, the device must request that
+ * the composition type of that layer is changed to CLIENT upon the
+ * next call to validateDisplay.
+ *
+ * Upon validateDisplay, the device may request a change from this
+ * type to CLIENT.
+ */
+ SOLID_COLOR = 3,
+
+ /*
+ * Similar to DEVICE, but the position of this layer may also be set
+ * asynchronously through setCursorPosition. If this functionality is
+ * not supported on a layer that the client sets to CURSOR, the device
+ * must request that the composition type of that layer is changed to
+ * CLIENT upon the next call to validateDisplay.
+ *
+ * Upon validateDisplay, the device may request a change from this
+ * type to either DEVICE or CLIENT. Changing to DEVICE will prevent
+ * the use of setCursorPosition but still permit the device to
+ * composite the layer.
+ */
+ CURSOR = 4,
+
+ /*
+ * The device must handle the composition of this layer, as well as
+ * its buffer updates and content synchronization. Only supported on
+ * devices which provide Capability::SIDEBAND_STREAM.
+ *
+ * Upon validateDisplay, the device may request a change from this
+ * type to either DEVICE or CLIENT, but it is unlikely that content
+ * will display correctly in these cases.
+ */
+ SIDEBAND = 5,
+ };
+
+ /* Display types returned by getDisplayType. */
+ enum DisplayType : int32_t {
+ INVALID = 0,
+
+ /*
+ * All physical displays, including both internal displays and
+ * hotpluggable external displays.
+ */
+ PHYSICAL = 1,
+
+ /* Virtual displays created by createVirtualDisplay. */
+ VIRTUAL = 2,
+ };
+
+ /* Special index values (always negative) for command queue commands. */
+ enum HandleIndex : int32_t {
+ /* No handle */
+ EMPTY = -1,
+
+ /* Use cached handle */
+ CACHED = -2,
+ };
+
+ struct Rect {
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
+
+ struct FRect {
+ float left;
+ float top;
+ float right;
+ float bottom;
+ };
+
+ struct Color {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+ };
+
+ /*
+ * Provides a IComposerCallback object for the device to call.
+ *
+ * This function must be called only once.
+ *
+ * @param callback is the IComposerCallback object.
+ */
+ @entry
+ @callflow(next="*")
+ registerCallback(IComposerCallback callback);
+
+ /*
+ * Returns the maximum number of virtual displays supported by this device
+ * (which may be 0). The client must not attempt to create more than this
+ * many virtual displays on this device. This number must not change for
+ * the lifetime of the device.
+ *
+ * @return count is the maximum number of virtual displays supported.
+ */
+ @callflow(next="*")
+ getMaxVirtualDisplayCount() generates (uint32_t count);
+
+ /*
+ * Creates a new virtual display with the given width and height. The
+ * format passed into this function is the default format requested by the
+ * consumer of the virtual display output buffers.
+ *
+ * The display must be assumed to be on from the time the first frame is
+ * presented until the display is destroyed.
+ *
+ * @param width is the width in pixels.
+ * @param height is the height in pixels.
+ * @param formatHint is the default output buffer format selected by
+ * the consumer.
+ * @param outputBufferSlotCount is the number of output buffer slots to be
+ * reserved.
+ * @return error is NONE upon success. Otherwise,
+ * UNSUPPORTED when the width or height is too large for the
+ * device to be able to create a virtual display.
+ * NO_RESOURCES when the device is unable to create a new virtual
+ * display at this time.
+ * @return display is the newly-created virtual display.
+ * @return format is the format of the buffer the device will produce.
+ */
+ @callflow(next="*")
+ createVirtualDisplay(uint32_t width,
+ uint32_t height,
+ PixelFormat formatHint,
+ uint32_t outputBufferSlotCount)
+ generates (Error error,
+ Display display,
+ PixelFormat format);
+
+ /*
+ * Destroys a virtual display. After this call all resources consumed by
+ * this display may be freed by the device and any operations performed on
+ * this display must fail.
+ *
+ * @param display is the virtual display to destroy.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when the display handle which was passed in does
+ * not refer to a virtual display.
+ */
+ @callflow(next="*")
+ destroyVirtualDisplay(Display display) generates (Error error);
+
+ /*
+ * Creates a new layer on the given display.
+ *
+ * @param display is the display on which to create the layer.
+ * @param bufferSlotCount is the number of buffer slot to be reserved.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * NO_RESOURCES when the device was unable to create a layer this
+ * time.
+ * @return layer is the handle of the new layer.
+ */
+ @callflow(next="*")
+ createLayer(Display display,
+ uint32_t bufferSlotCount)
+ generates (Error error,
+ Layer layer);
+
+ /*
+ * Destroys the given layer.
+ *
+ * @param display is the display on which the layer was created.
+ * @param layer is the layer to destroy.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_LAYER when an invalid layer handle was passed in.
+ */
+ @callflow(next="*")
+ destroyLayer(Display display, Layer layer) generates (Error error);
+
+ /*
+ * Retrieves which display configuration is currently active.
+ *
+ * If no display configuration is currently active, this function must
+ * return BAD_CONFIG. It is the responsibility of the client to call
+ * setActiveConfig with a valid configuration before attempting to present
+ * anything on the display.
+ *
+ * @param display is the display to which the active config is queried.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when no configuration is currently active.
+ * @return config is the currently active display configuration.
+ */
+ @callflow(next="*")
+ getActiveConfig(Display display) generates (Error error, Config config);
+
+ /*
+ * Returns whether a client target with the given properties can be
+ * handled by the device.
+ *
+ * This function must return true for a client target with width and
+ * height equal to the active display configuration dimensions,
+ * PixelFormat::RGBA_8888, and Dataspace::UNKNOWN. It is not required to
+ * return true for any other configuration.
+ *
+ * @param display is the display to query.
+ * @param width is the client target width in pixels.
+ * @param height is the client target height in pixels.
+ * @param format is the client target format.
+ * @param dataspace is the client target dataspace, as described in
+ * setLayerDataspace.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * UNSUPPORTED when the given configuration is not supported.
+ */
+ @callflow(next="*")
+ getClientTargetSupport(Display display,
+ uint32_t width,
+ uint32_t height,
+ PixelFormat format,
+ Dataspace dataspace)
+ generates (Error error);
+
+ /*
+ * Returns the color modes supported on this display.
+ *
+ * All devices must support at least ColorMode::NATIVE.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return modes is an array of color modes.
+ */
+ @callflow(next="*")
+ getColorModes(Display display)
+ generates (Error error,
+ vec<ColorMode> modes);
+
+ /*
+ * Returns a display attribute value for a particular display
+ * configuration.
+ *
+ * @param display is the display to query.
+ * @param config is the display configuration for which to return
+ * attribute values.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when config does not name a valid configuration for
+ * this display.
+ * BAD_PARAMETER when attribute is unrecognized.
+ * UNSUPPORTED when attribute cannot be queried for the config.
+ * @return value is the value of the attribute.
+ */
+ @callflow(next="*")
+ getDisplayAttribute(Display display,
+ Config config,
+ Attribute attribute)
+ generates (Error error,
+ int32_t value);
+
+ /*
+ * Returns handles for all of the valid display configurations on this
+ * display.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return configs is an array of configuration handles.
+ */
+ @callflow(next="*")
+ getDisplayConfigs(Display display)
+ generates (Error error,
+ vec<Config> configs);
+
+ /*
+ * Returns a human-readable version of the display's name.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return name is the name of the display.
+ */
+ @callflow(next="*")
+ getDisplayName(Display display) generates (Error error, string name);
+
+ /*
+ * Returns whether the given display is a physical or virtual display.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return type is the type of the display.
+ */
+ @callflow(next="*")
+ getDisplayType(Display display) generates (Error error, DisplayType type);
+
+ /*
+ * Returns whether the given display supports PowerMode::DOZE and
+ * PowerMode::DOZE_SUSPEND. DOZE_SUSPEND may not provide any benefit over
+ * DOZE (see the definition of PowerMode for more information), but if
+ * both DOZE and DOZE_SUSPEND are no different from PowerMode::ON, the
+ * device must not claim support.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return support is true only when the display supports doze modes.
+ */
+ @callflow(next="*")
+ getDozeSupport(Display display) generates (Error error, bool support);
+
+ /*
+ * Returns the high dynamic range (HDR) capabilities of the given display,
+ * which are invariant with regard to the active configuration.
+ *
+ * Displays which are not HDR-capable must return no types.
+ *
+ * @param display is the display to query.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return types is an array of HDR types, may have 0 elements if the
+ * display is not HDR-capable.
+ * @return maxLuminance is the desired content maximum luminance for this
+ * display in cd/m^2.
+ * @return maxAverageLuminance - the desired content maximum frame-average
+ * luminance for this display in cd/m^2.
+ * @return minLuminance is the desired content minimum luminance for this
+ * display in cd/m^2.
+ */
+ @callflow(next="*")
+ getHdrCapabilities(Display display)
+ generates (Error error,
+ vec<Hdr> types,
+ float maxLuminance,
+ float maxAverageLuminance,
+ float minLuminance);
+
+ /*
+ * Set the number of client target slots to be reserved.
+ *
+ * @param display is the display to which the slots are reserved.
+ * @param clientTargetSlotCount is the slot count for client targets.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * NO_RESOURCES when unable to reserve the slots.
+ */
+ @callflow(next="*")
+ setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount)
+ generates (Error error);
+
+ /*
+ * Sets the active configuration for this display. Upon returning, the
+ * given display configuration must be active and remain so until either
+ * this function is called again or the display is disconnected.
+ *
+ * @param display is the display to which the active config is set.
+ * @param config is the new display configuration.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when the configuration handle passed in is not valid
+ * for this display.
+ */
+ @callflow(next="*")
+ setActiveConfig(Display display, Config config) generates (Error error);
+
+ /*
+ * Sets the color mode of the given display.
+ *
+ * Upon returning from this function, the color mode change must have
+ * fully taken effect.
+ *
+ * All devices must support at least ColorMode::NATIVE, and displays are
+ * assumed to be in this mode upon hotplug.
+ *
+ * @param display is the display to which the color mode is set.
+ * @param mode is the mode to set to.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when mode is not a valid color mode.
+ * UNSUPPORTED when mode is not supported on this display.
+ */
+ @callflow(next="*")
+ setColorMode(Display display, ColorMode mode) generates (Error error);
+
+ /*
+ * Sets the power mode of the given display. The transition must be
+ * complete when this function returns. It is valid to call this function
+ * multiple times with the same power mode.
+ *
+ * All displays must support PowerMode::ON and PowerMode::OFF. Whether a
+ * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be
+ * queried using getDozeSupport.
+ *
+ * @param display is the display to which the power mode is set.
+ * @param mode is the new power mode.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when mode was not a valid power mode.
+ * UNSUPPORTED when mode is not supported on this display.
+ */
+ @callflow(next="*")
+ setPowerMode(Display display, PowerMode mode) generates (Error error);
+
+ /*
+ * Enables or disables the vsync signal for the given display. Virtual
+ * displays never generate vsync callbacks, and any attempt to enable
+ * vsync for a virtual display though this function must succeed and have
+ * no other effect.
+ *
+ * @param display is the display to which the vsync mode is set.
+ * @param enabled indicates whether to enable or disable vsync
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_PARAMETER when enabled was an invalid value.
+ */
+ @callflow(next="*")
+ setVsyncEnabled(Display display, Vsync enabled) generates (Error error);
+
+ /*
+ * Sets the input command message queue.
+ *
+ * @param descriptor is the descriptor of the input command message queue.
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when failed to set the queue temporarily.
+ */
+ @callflow(next="*")
+ setInputCommandQueue(fmq_sync<uint32_t> descriptor)
+ generates (Error error);
+
+ /*
+ * Gets the output command message queue.
+ *
+ * This function must only be called inside executeCommands closure.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when failed to get the queue temporarily.
+ * @return descriptor is the descriptor of the output command queue.
+ */
+ @callflow(next="*")
+ getOutputCommandQueue()
+ generates (Error error,
+ fmq_sync<uint32_t> descriptor);
+
+ /*
+ * Executes commands from the input command message queue. Return values
+ * generated by the input commands are written to the output command
+ * message queue in the form of value commands.
+ *
+ * @param inLength is the length of input commands.
+ * @param inHandles is an array of handles referenced by the input
+ * commands.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_PARAMETER when inLength is not equal to the length of
+ * commands in the input command message queue.
+ * NO_RESOURCES when the output command message queue was not
+ * properly drained.
+ * @param outQueueChanged indicates whether the output command message
+ * queue has changed.
+ * @param outLength is the length of output commands.
+ * @param outHandles is an array of handles referenced by the output
+ * commands.
+ */
+ @callflow(next="*")
+ executeCommands(uint32_t inLength,
+ vec<handle> inHandles)
+ generates (Error error,
+ bool outQueueChanged,
+ uint32_t outLength,
+ vec<handle> outHandles);
+
+ /*
+ * SELECT_DISPLAY has this pseudo prototype
+ *
+ * selectDisplay(Display display);
+ *
+ * Selects the current display implied by all other commands.
+ *
+ * @param display is the newly selected display.
+ *
+ *
+ * SELECT_LAYER has this pseudo prototype
+ *
+ * selectLayer(Layer layer);
+ *
+ * Selects the current layer implied by all implicit layer commands.
+ *
+ * @param layer is the newly selected layer.
+ *
+ *
+ * SET_ERROR has this pseudo prototype
+ *
+ * setError(uint32_t location, Error error);
+ *
+ * Indicates an error generated by a command.
+ *
+ * @param location is the offset of the command in the input command
+ * message queue.
+ * @param error is the error generated by the command.
+ *
+ *
+ * SET_CHANGED_COMPOSITION_TYPES has this pseudo prototype
+ *
+ * setChangedCompositionTypes(vec<Layer> layers,
+ * vec<Composition> types);
+ *
+ * Sets the layers for which the device requires a different composition
+ * type than had been set prior to the last call to VALIDATE_DISPLAY. The
+ * client must either update its state with these types and call
+ * ACCEPT_DISPLAY_CHANGES, or must set new types and attempt to validate
+ * the display again.
+ *
+ * @param layers is an array of layer handles.
+ * @param types is an array of composition types, each corresponding to
+ * an element of layers.
+ *
+ *
+ * SET_DISPLAY_REQUESTS has this pseudo prototype
+ *
+ * setDisplayRequests(uint32_t displayRequestMask,
+ * vec<Layer> layers,
+ * vec<uint32_t> layerRequestMasks);
+ *
+ * Sets the display requests and the layer requests required for the last
+ * validated configuration.
+ *
+ * Display requests provide information about how the client must handle
+ * the client target. Layer requests provide information about how the
+ * client must handle an individual layer.
+ *
+ * @param displayRequestMask is the display requests for the current
+ * validated state.
+ * @param layers is an array of layers which all have at least one
+ * request.
+ * @param layerRequestMasks is the requests corresponding to each element
+ * of layers.
+ *
+ *
+ * SET_PRESENT_FENCE has this pseudo prototype
+ *
+ * setPresentFence(int32_t presentFenceIndex);
+ *
+ * Sets the present fence as a result of PRESENT_DISPLAY. For physical
+ * displays, this fence must be signaled at the vsync when the result
+ * of composition of this frame starts to appear (for video-mode panels)
+ * or starts to transfer to panel memory (for command-mode panels). For
+ * virtual displays, this fence must be signaled when writes to the output
+ * buffer have completed and it is safe to read from it.
+ *
+ * @param presentFenceIndex is an index into outHandles array.
+ *
+ *
+ * SET_RELEASE_FENCES has this pseudo prototype
+ *
+ * setReleaseFences(vec<Layer> layers,
+ * vec<int32_t> releaseFenceIndices);
+ *
+ * Sets the release fences for device layers on this display which will
+ * receive new buffer contents this frame.
+ *
+ * A release fence is a file descriptor referring to a sync fence object
+ * which must be signaled after the device has finished reading from the
+ * buffer presented in the prior frame. This indicates that it is safe to
+ * start writing to the buffer again. If a given layer's fence is not
+ * returned from this function, it must be assumed that the buffer
+ * presented on the previous frame is ready to be written.
+ *
+ * The fences returned by this function must be unique for each layer
+ * (even if they point to the same underlying sync object).
+ *
+ * @param layers is an array of layer handles.
+ * @param releaseFenceIndices are indices into outHandles array, each
+ * corresponding to an element of layers.
+ *
+ *
+ * SET_COLOR_TRANSFORM has this pseudo prototype
+ *
+ * setColorTransform(float[16] matrix,
+ * ColorTransform hint);
+ *
+ * Sets a color transform which will be applied after composition.
+ *
+ * If hint is not ColorTransform::ARBITRARY, then the device may use the
+ * hint to apply the desired color transform instead of using the color
+ * matrix directly.
+ *
+ * If the device is not capable of either using the hint or the matrix to
+ * apply the desired color transform, it must force all layers to client
+ * composition during VALIDATE_DISPLAY.
+ *
+ * If IComposer::Capability::SKIP_CLIENT_COLOR_TRANSFORM is present, then
+ * the client must never apply the color transform during client
+ * composition, even if all layers are being composed by the client.
+ *
+ * The matrix provided is an affine color transformation of the following
+ * form:
+ *
+ * |r.r r.g r.b 0|
+ * |g.r g.g g.b 0|
+ * |b.r b.g b.b 0|
+ * |Tr Tg Tb 1|
+ *
+ * This matrix must be provided in row-major form:
+ *
+ * {r.r, r.g, r.b, 0, g.r, ...}.
+ *
+ * Given a matrix of this form and an input color [R_in, G_in, B_in], the
+ * output color [R_out, G_out, B_out] will be:
+ *
+ * R_out = R_in * r.r + G_in * g.r + B_in * b.r + Tr
+ * G_out = R_in * r.g + G_in * g.g + B_in * b.g + Tg
+ * B_out = R_in * r.b + G_in * g.b + B_in * b.b + Tb
+ *
+ * @param matrix is a 4x4 transform matrix (16 floats) as described above.
+ * @param hint is a hint value which may be used instead of the given
+ * matrix unless it is ColorTransform::ARBITRARY.
+ *
+ *
+ * SET_CLIENT_TARGET has this pseudo prototype
+ *
+ * setClientTarget(uint32_t targetSlot,
+ * int32_t targetIndex,
+ * int32_t acquireFenceIndex,
+ * Dataspace dataspace,
+ * vec<Rect> damage);
+ *
+ * Sets the buffer handle which will receive the output of client
+ * composition. Layers marked as Composition::CLIENT must be composited
+ * into this buffer prior to the call to PRESENT_DISPLAY, and layers not
+ * marked as Composition::CLIENT must be composited with this buffer by
+ * the device.
+ *
+ * The buffer handle provided may be empty if no layers are being
+ * composited by the client. This must not result in an error (unless an
+ * invalid display handle is also provided).
+ *
+ * Also provides a file descriptor referring to an acquire sync fence
+ * object, which must be signaled when it is safe to read from the client
+ * target buffer. If it is already safe to read from this buffer, an
+ * empty handle may be passed instead.
+ *
+ * For more about dataspaces, see SET_LAYER_DATASPACE.
+ *
+ * The damage parameter describes a surface damage region as defined in
+ * the description of SET_LAYER_SURFACE_DAMAGE.
+ *
+ * Will be called before PRESENT_DISPLAY if any of the layers are marked
+ * as Composition::CLIENT. If no layers are so marked, then it is not
+ * necessary to call this function. It is not necessary to call
+ * validateDisplay after changing the target through this function.
+ *
+ * @param targetSlot is the client target buffer slot to use.
+ * @param targetIndex is an index into inHandles for the new target
+ * buffer.
+ * @param acquireFenceIndex is an index into inHandles for a sync fence
+ * file descriptor as described above.
+ * @param dataspace is the dataspace of the buffer, as described in
+ * setLayerDataspace.
+ * @param damage is the surface damage region.
+ *
+ *
+ * SET_OUTPUT_BUFFER has this pseudo prototype
+ *
+ * setOutputBuffer(uint32_t bufferSlot,
+ * int32_t bufferIndex,
+ * int32_t releaseFenceIndex);
+ *
+ * Sets the output buffer for a virtual display. That is, the buffer to
+ * which the composition result will be written.
+ *
+ * Also provides a file descriptor referring to a release sync fence
+ * object, which must be signaled when it is safe to write to the output
+ * buffer. If it is already safe to write to the output buffer, an empty
+ * handle may be passed instead.
+ *
+ * Must be called at least once before PRESENT_DISPLAY, but does not have
+ * any interaction with layer state or display validation.
+ *
+ * @param bufferSlot is the new output buffer.
+ * @param bufferIndex is the new output buffer.
+ * @param releaseFenceIndex is a sync fence file descriptor as described
+ * above.
+ *
+ *
+ * VALIDATE_DISPLAY has this pseudo prototype
+ *
+ * validateDisplay();
+ *
+ * Instructs the device to inspect all of the layer state and determine if
+ * there are any composition type changes necessary before presenting the
+ * display. Permitted changes are described in the definition of
+ * Composition above.
+ *
+ *
+ * ACCEPT_DISPLAY_CHANGES has this pseudo prototype
+ *
+ * acceptDisplayChanges();
+ *
+ * Accepts the changes required by the device from the previous
+ * validateDisplay call (which may be queried using
+ * getChangedCompositionTypes) and revalidates the display. This function
+ * is equivalent to requesting the changed types from
+ * getChangedCompositionTypes, setting those types on the corresponding
+ * layers, and then calling validateDisplay again.
+ *
+ * After this call it must be valid to present this display. Calling this
+ * after validateDisplay returns 0 changes must succeed with NONE, but
+ * must have no other effect.
+ *
+ *
+ * PRESENT_DISPLAY has this pseudo prototype
+ *
+ * presentDisplay();
+ *
+ * Presents the current display contents on the screen (or in the case of
+ * virtual displays, into the output buffer).
+ *
+ * Prior to calling this function, the display must be successfully
+ * validated with validateDisplay. Note that setLayerBuffer and
+ * setLayerSurfaceDamage specifically do not count as layer state, so if
+ * there are no other changes to the layer state (or to the buffer's
+ * properties as described in setLayerBuffer), then it is safe to call
+ * this function without first validating the display.
+ *
+ *
+ * SET_LAYER_CURSOR_POSITION has this pseudo prototype
+ *
+ * setLayerCursorPosition(int32_t x, int32_t y);
+ *
+ * Asynchronously sets the position of a cursor layer.
+ *
+ * Prior to validateDisplay, a layer may be marked as Composition::CURSOR.
+ * If validation succeeds (i.e., the device does not request a composition
+ * change for that layer), then once a buffer has been set for the layer
+ * and it has been presented, its position may be set by this function at
+ * any time between presentDisplay and any subsequent validateDisplay
+ * calls for this display.
+ *
+ * Once validateDisplay is called, this function must not be called again
+ * until the validate/present sequence is completed.
+ *
+ * May be called from any thread so long as it is not interleaved with the
+ * validate/present sequence as described above.
+ *
+ * @param layer is the layer to which the position is set.
+ * @param x is the new x coordinate (in pixels from the left of the
+ * screen).
+ * @param y is the new y coordinate (in pixels from the top of the
+ * screen).
+ *
+ *
+ * SET_LAYER_BUFFER has this pseudo prototype
+ *
+ * setLayerBuffer(uint32_t bufferSlot,
+ * int32_t bufferIndex,
+ * int32_t acquireFenceIndex);
+ *
+ * Sets the buffer handle to be displayed for this layer. If the buffer
+ * properties set at allocation time (width, height, format, and usage)
+ * have not changed since the previous frame, it is not necessary to call
+ * validateDisplay before calling presentDisplay unless new state needs to
+ * be validated in the interim.
+ *
+ * Also provides a file descriptor referring to an acquire sync fence
+ * object, which must be signaled when it is safe to read from the given
+ * buffer. If it is already safe to read from the buffer, an empty handle
+ * may be passed instead.
+ *
+ * This function must return NONE and have no other effect if called for a
+ * layer with a composition type of Composition::SOLID_COLOR (because it
+ * has no buffer) or Composition::SIDEBAND or Composition::CLIENT (because
+ * synchronization and buffer updates for these layers are handled
+ * elsewhere).
+ *
+ * @param layer is the layer to which the buffer is set.
+ * @param bufferSlot is the buffer slot to use.
+ * @param bufferIndex is the buffer handle to set.
+ * @param acquireFenceIndex is a sync fence file descriptor as described above.
+ *
+ *
+ * SET_LAYER_SURFACE_DAMAGE has this pseudo prototype
+ *
+ * setLayerSurfaceDamage(vec<Rect> damage);
+ *
+ * Provides the region of the source buffer which has been modified since
+ * the last frame. This region does not need to be validated before
+ * calling presentDisplay.
+ *
+ * Once set through this function, the damage region remains the same
+ * until a subsequent call to this function.
+ *
+ * If damage is non-empty, then it may be assumed that any portion of the
+ * source buffer not covered by one of the rects has not been modified
+ * this frame. If damage is empty, then the whole source buffer must be
+ * treated as if it has been modified.
+ *
+ * If the layer's contents are not modified relative to the prior frame,
+ * damage must contain exactly one empty rect([0, 0, 0, 0]).
+ *
+ * The damage rects are relative to the pre-transformed buffer, and their
+ * origin is the top-left corner. They must not exceed the dimensions of
+ * the latched buffer.
+ *
+ * @param layer is the layer to which the damage region is set.
+ * @param damage is the new surface damage region.
+ *
+ *
+ * SET_LAYER_BLEND_MODE has this pseudo prototype
+ *
+ * setLayerBlendMode(BlendMode mode)
+ *
+ * Sets the blend mode of the given layer.
+ *
+ * @param mode is the new blend mode.
+ *
+ *
+ * SET_LAYER_COLOR has this pseudo prototype
+ *
+ * setLayerColor(Color color);
+ *
+ * Sets the color of the given layer. If the composition type of the layer
+ * is not Composition::SOLID_COLOR, this call must succeed and have no
+ * other effect.
+ *
+ * @param color is the new color.
+ *
+ *
+ * SET_LAYER_COMPOSITION_TYPE has this pseudo prototype
+ *
+ * setLayerCompositionType(Composition type);
+ *
+ * Sets the desired composition type of the given layer. During
+ * validateDisplay, the device may request changes to the composition
+ * types of any of the layers as described in the definition of
+ * Composition above.
+ *
+ * @param type is the new composition type.
+ *
+ *
+ * SET_LAYER_DATASPACE has this pseudo prototype
+ *
+ * setLayerDataspace(Dataspace dataspace);
+ *
+ * Sets the dataspace that the current buffer on this layer is in.
+ *
+ * The dataspace provides more information about how to interpret the
+ * buffer contents, such as the encoding standard and color transform.
+ *
+ * See the values of Dataspace for more information.
+ *
+ * @param dataspace is the new dataspace.
+ *
+ *
+ * SET_LAYER_DISPLAY_FRAME has this pseudo prototype
+ *
+ * setLayerDisplayFrame(Rect frame);
+ *
+ * Sets the display frame (the portion of the display covered by a layer)
+ * of the given layer. This frame must not exceed the display dimensions.
+ *
+ * @param frame is the new display frame.
+ *
+ *
+ * SET_LAYER_PLANE_ALPHA has this pseudo prototype
+ *
+ * setLayerPlaneAlpha(float alpha);
+ *
+ * Sets an alpha value (a floating point value in the range [0.0, 1.0])
+ * which will be applied to the whole layer. It can be conceptualized as a
+ * preprocessing step which applies the following function:
+ * if (blendMode == BlendMode::PREMULTIPLIED)
+ * out.rgb = in.rgb * planeAlpha
+ * out.a = in.a * planeAlpha
+ *
+ * If the device does not support this operation on a layer which is
+ * marked Composition::DEVICE, it must request a composition type change
+ * to Composition::CLIENT upon the next validateDisplay call.
+ *
+ * @param alpha is the plane alpha value to apply.
+ *
+ *
+ * SET_LAYER_SIDEBAND_STREAM has this pseudo prototype
+ *
+ * setLayerSidebandStream(int32_t streamIndex)
+ *
+ * Sets the sideband stream for this layer. If the composition type of the
+ * given layer is not Composition::SIDEBAND, this call must succeed and
+ * have no other effect.
+ *
+ * @param streamIndex is the new sideband stream.
+ *
+ *
+ * SET_LAYER_SOURCE_CROP has this pseudo prototype
+ *
+ * setLayerSourceCrop(FRect crop);
+ *
+ * Sets the source crop (the portion of the source buffer which will fill
+ * the display frame) of the given layer. This crop rectangle must not
+ * exceed the dimensions of the latched buffer.
+ *
+ * If the device is not capable of supporting a true float source crop
+ * (i.e., it will truncate or round the floats to integers), it must set
+ * this layer to Composition::CLIENT when crop is non-integral for the
+ * most accurate rendering.
+ *
+ * If the device cannot support float source crops, but still wants to
+ * handle the layer, it must use the following code (or similar) to
+ * convert to an integer crop:
+ * intCrop.left = (int) ceilf(crop.left);
+ * intCrop.top = (int) ceilf(crop.top);
+ * intCrop.right = (int) floorf(crop.right);
+ * intCrop.bottom = (int) floorf(crop.bottom);
+ *
+ * @param crop is the new source crop.
+ *
+ *
+ * SET_LAYER_TRANSFORM has this pseudo prototype
+ *
+ * Sets the transform (rotation/flip) of the given layer.
+ *
+ * setLayerTransform(Transform transform);
+ *
+ * @param transform is the new transform.
+ *
+ *
+ * SET_LAYER_VISIBLE_REGION has this pseudo prototype
+ *
+ * setLayerVisibleRegion(vec<Rect> visible);
+ *
+ * Specifies the portion of the layer that is visible, including portions
+ * under translucent areas of other layers. The region is in screen space,
+ * and must not exceed the dimensions of the screen.
+ *
+ * @param visible is the new visible region, in screen space.
+ *
+ *
+ * SET_LAYER_Z_ORDER has this pseudo prototype
+ *
+ * setLayerZOrder(uint32_t z);
+ *
+ * Sets the desired Z order (height) of the given layer. A layer with a
+ * greater Z value occludes a layer with a lesser Z value.
+ *
+ * @param z is the new Z order.
+ */
+ enum Command : int32_t {
+ LENGTH_MASK = 0xffff,
+ OPCODE_SHIFT = 16,
+ OPCODE_MASK = 0xffff << OPCODE_SHIFT,
+
+ /* special commands */
+ SELECT_DISPLAY = 0x000 << OPCODE_SHIFT,
+ SELECT_LAYER = 0x001 << OPCODE_SHIFT,
+
+ /* value commands (for return values) */
+ SET_ERROR = 0x100 << OPCODE_SHIFT,
+ SET_CHANGED_COMPOSITION_TYPES = 0x101 << OPCODE_SHIFT,
+ SET_DISPLAY_REQUESTS = 0x102 << OPCODE_SHIFT,
+ SET_PRESENT_FENCE = 0x103 << OPCODE_SHIFT,
+ SET_RELEASE_FENCES = 0x104 << OPCODE_SHIFT,
+
+ /* display commands */
+ SET_COLOR_TRANSFORM = 0x200 << OPCODE_SHIFT,
+ SET_CLIENT_TARGET = 0x201 << OPCODE_SHIFT,
+ SET_OUTPUT_BUFFER = 0x202 << OPCODE_SHIFT,
+ VALIDATE_DISPLAY = 0x203 << OPCODE_SHIFT,
+ ACCEPT_DISPLAY_CHANGES = 0x204 << OPCODE_SHIFT,
+ PRESENT_DISPLAY = 0x205 << OPCODE_SHIFT,
+
+ /* layer commands (VALIDATE_DISPLAY not required) */
+ SET_LAYER_CURSOR_POSITION = 0x300 << OPCODE_SHIFT,
+ SET_LAYER_BUFFER = 0x301 << OPCODE_SHIFT,
+ SET_LAYER_SURFACE_DAMAGE = 0x302 << OPCODE_SHIFT,
+
+ /* layer state commands (VALIDATE_DISPLAY required) */
+ SET_LAYER_BLEND_MODE = 0x400 << OPCODE_SHIFT,
+ SET_LAYER_COLOR = 0x401 << OPCODE_SHIFT,
+ SET_LAYER_COMPOSITION_TYPE = 0x402 << OPCODE_SHIFT,
+ SET_LAYER_DATASPACE = 0x403 << OPCODE_SHIFT,
+ SET_LAYER_DISPLAY_FRAME = 0x404 << OPCODE_SHIFT,
+ SET_LAYER_PLANE_ALPHA = 0x405 << OPCODE_SHIFT,
+ SET_LAYER_SIDEBAND_STREAM = 0x406 << OPCODE_SHIFT,
+ SET_LAYER_SOURCE_CROP = 0x407 << OPCODE_SHIFT,
+ SET_LAYER_TRANSFORM = 0x408 << OPCODE_SHIFT,
+ SET_LAYER_VISIBLE_REGION = 0x409 << OPCODE_SHIFT,
+ SET_LAYER_Z_ORDER = 0x40a << OPCODE_SHIFT,
+
+ /* 0x800 - 0xfff are reserved for vendor extensions */
+ /* 0x1000 - 0xffff are reserved */
+ };
+};
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
new file mode 100644
index 0000000..0367fcd
--- /dev/null
+++ b/graphics/composer/2.1/default/Android.bp
@@ -0,0 +1,73 @@
+cc_library_static {
+ name: "libhwcomposer-client",
+ defaults: ["hidl_defaults"],
+ export_include_dirs: ["."],
+ srcs: ["ComposerClient.cpp"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.1-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Hwc.cpp"],
+ static_libs: ["libhwcomposer-client"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libsync",
+ "libutils",
+ "libhwc2on1adapter"
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.graphics.composer@2.1-service",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.composer@2.1-service.rc"],
+ static_libs: ["libhwcomposer-client"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+}
+
+cc_library_static {
+ name: "libhwcomposer-command-buffer",
+ defaults: ["hidl_defaults"],
+ shared_libs: ["android.hardware.graphics.composer@2.1"],
+ export_include_dirs: ["."],
+}
diff --git a/graphics/composer/2.1/default/ComposerBase.h b/graphics/composer/2.1/default/ComposerBase.h
new file mode 100644
index 0000000..85b1a4d
--- /dev/null
+++ b/graphics/composer/2.1/default/ComposerBase.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <hardware/hwcomposer2.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Hdr;
+
+class ComposerBase {
+public:
+ virtual ~ComposerBase() {};
+
+ virtual void removeClient() = 0;
+ virtual void enableCallback(bool enable) = 0;
+ virtual uint32_t getMaxVirtualDisplayCount() = 0;
+ virtual Error createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat* format, Display* outDisplay) = 0;
+ virtual Error destroyVirtualDisplay(Display display) = 0;
+ virtual Error createLayer(Display display, Layer* outLayer) = 0;
+ virtual Error destroyLayer(Display display, Layer layer) = 0;
+
+ virtual Error getActiveConfig(Display display, Config* outConfig) = 0;
+ virtual Error getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) = 0;
+ virtual Error getColorModes(Display display,
+ hidl_vec<ColorMode>* outModes) = 0;
+ virtual Error getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) = 0;
+ virtual Error getDisplayConfigs(Display display,
+ hidl_vec<Config>* outConfigs) = 0;
+ virtual Error getDisplayName(Display display, hidl_string* outName) = 0;
+ virtual Error getDisplayType(Display display,
+ IComposerClient::DisplayType* outType) = 0;
+ virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
+ virtual Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) = 0;
+
+ virtual Error setActiveConfig(Display display, Config config) = 0;
+ virtual Error setColorMode(Display display, ColorMode mode) = 0;
+ virtual Error setPowerMode(Display display,
+ IComposerClient::PowerMode mode) = 0;
+ virtual Error setVsyncEnabled(Display display,
+ IComposerClient::Vsync enabled) = 0;
+
+ virtual Error setColorTransform(Display display, const float* matrix,
+ int32_t hint) = 0;
+ virtual Error setClientTarget(Display display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace,
+ const std::vector<hwc_rect_t>& damage) = 0;
+ virtual Error setOutputBuffer(Display display, buffer_handle_t buffer,
+ int32_t releaseFence) = 0;
+ virtual Error validateDisplay(Display display,
+ std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) = 0;
+ virtual Error acceptDisplayChanges(Display display) = 0;
+ virtual Error presentDisplay(Display display, int32_t* outPresentFence,
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) = 0;
+
+ virtual Error setLayerCursorPosition(Display display, Layer layer,
+ int32_t x, int32_t y) = 0;
+ virtual Error setLayerBuffer(Display display, Layer layer,
+ buffer_handle_t buffer, int32_t acquireFence) = 0;
+ virtual Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) = 0;
+ virtual Error setLayerBlendMode(Display display, Layer layer,
+ int32_t mode) = 0;
+ virtual Error setLayerColor(Display display, Layer layer,
+ IComposerClient::Color color) = 0;
+ virtual Error setLayerCompositionType(Display display, Layer layer,
+ int32_t type) = 0;
+ virtual Error setLayerDataspace(Display display, Layer layer,
+ int32_t dataspace) = 0;
+ virtual Error setLayerDisplayFrame(Display display, Layer layer,
+ const hwc_rect_t& frame) = 0;
+ virtual Error setLayerPlaneAlpha(Display display, Layer layer,
+ float alpha) = 0;
+ virtual Error setLayerSidebandStream(Display display, Layer layer,
+ buffer_handle_t stream) = 0;
+ virtual Error setLayerSourceCrop(Display display, Layer layer,
+ const hwc_frect_t& crop) = 0;
+ virtual Error setLayerTransform(Display display, Layer layer,
+ int32_t transform) = 0;
+ virtual Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) = 0;
+ virtual Error setLayerZOrder(Display display, Layer layer,
+ uint32_t z) = 0;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
new file mode 100644
index 0000000..d599b44
--- /dev/null
+++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -0,0 +1,1210 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "HwcPassthrough"
+
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+
+#include "ComposerClient.h"
+#include "ComposerBase.h"
+#include "IComposerCommandBuffer.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+namespace {
+
+class HandleImporter {
+public:
+ HandleImporter() : mInitialized(false) {}
+
+ bool initialize()
+ {
+ // allow only one client
+ if (mInitialized) {
+ return false;
+ }
+
+ if (!openGralloc()) {
+ return false;
+ }
+
+ mInitialized = true;
+ return true;
+ }
+
+ void cleanup()
+ {
+ if (!mInitialized) {
+ return;
+ }
+
+ closeGralloc();
+ mInitialized = false;
+ }
+
+ // In IComposer, any buffer_handle_t is owned by the caller and we need to
+ // make a clone for hwcomposer2. We also need to translate empty handle
+ // to nullptr. This function does that, in-place.
+ bool importBuffer(buffer_handle_t& handle)
+ {
+ if (!handle) {
+ return true;
+ }
+
+ if (!handle->numFds && !handle->numInts) {
+ handle = nullptr;
+ return true;
+ }
+
+ buffer_handle_t clone = cloneBuffer(handle);
+ if (!clone) {
+ return false;
+ }
+
+ handle = clone;
+ return true;
+ }
+
+ void freeBuffer(buffer_handle_t handle)
+ {
+ if (!handle) {
+ return;
+ }
+
+ releaseBuffer(handle);
+ }
+
+private:
+ bool mInitialized;
+
+ // Some existing gralloc drivers do not support retaining more than once,
+ // when we are in passthrough mode.
+ bool openGralloc()
+ {
+ const hw_module_t* module = nullptr;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return false;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major > 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return false;
+ }
+
+ if (major == 1) {
+ err = gralloc1_open(module, &mDevice);
+ if (err) {
+ ALOGE("failed to open gralloc1 device");
+ return false;
+ }
+
+ mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN));
+ mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE));
+ if (!mRetain || !mRelease) {
+ ALOGE("invalid gralloc1 device");
+ gralloc1_close(mDevice);
+ return false;
+ }
+ } else {
+ mModule = reinterpret_cast<const gralloc_module_t*>(module);
+ }
+
+ return true;
+ }
+
+ void closeGralloc()
+ {
+ if (mDevice) {
+ gralloc1_close(mDevice);
+ }
+ }
+
+ buffer_handle_t cloneBuffer(buffer_handle_t handle)
+ {
+ native_handle_t* clone = native_handle_clone(handle);
+ if (!clone) {
+ ALOGE("failed to clone buffer %p", handle);
+ return nullptr;
+ }
+
+ bool err;
+ if (mDevice) {
+ err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE);
+ } else {
+ err = (mModule->registerBuffer(mModule, clone) != 0);
+ }
+
+ if (err) {
+ ALOGE("failed to retain/register buffer %p", clone);
+ native_handle_close(clone);
+ native_handle_delete(clone);
+ return nullptr;
+ }
+
+ return clone;
+ }
+
+ void releaseBuffer(buffer_handle_t handle)
+ {
+ if (mDevice) {
+ mRelease(mDevice, handle);
+ } else {
+ mModule->unregisterBuffer(mModule, handle);
+ }
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
+ }
+
+ // gralloc1
+ gralloc1_device_t* mDevice;
+ GRALLOC1_PFN_RETAIN mRetain;
+ GRALLOC1_PFN_RELEASE mRelease;
+
+ // gralloc0
+ const gralloc_module_t* mModule;
+};
+
+HandleImporter sHandleImporter;
+
+} // anonymous namespace
+
+BufferCacheEntry::BufferCacheEntry()
+ : mHandle(nullptr)
+{
+}
+
+BufferCacheEntry::BufferCacheEntry(BufferCacheEntry&& other)
+{
+ mHandle = other.mHandle;
+ other.mHandle = nullptr;
+}
+
+BufferCacheEntry& BufferCacheEntry::operator=(buffer_handle_t handle)
+{
+ clear();
+ mHandle = handle;
+ return *this;
+}
+
+BufferCacheEntry::~BufferCacheEntry()
+{
+ clear();
+}
+
+void BufferCacheEntry::clear()
+{
+ if (mHandle) {
+ sHandleImporter.freeBuffer(mHandle);
+ }
+}
+
+ComposerClient::ComposerClient(ComposerBase& hal)
+ : mHal(hal), mWriter(kWriterInitialSize)
+{
+}
+
+ComposerClient::~ComposerClient()
+{
+ // We want to call hwc2_close here (and move hwc2_open to the
+ // constructor), with the assumption that hwc2_close would
+ //
+ // - clean up all resources owned by the client
+ // - make sure all displays are blank (since there is no layer)
+ //
+ // But since SF used to crash at this point, different hwcomposer2
+ // implementations behave differently on hwc2_close. Our only portable
+ // choice really is to abort(). But that is not an option anymore
+ // because we might also have VTS or VR as clients that can come and go.
+ //
+ // Below we manually clean all resources (layers and virtual
+ // displays), and perform a presentDisplay afterwards.
+ ALOGW("destroying composer client");
+
+ mHal.enableCallback(false);
+
+ // no need to grab the mutex as any in-flight hwbinder call would have
+ // kept the client alive
+ for (const auto& dpy : mDisplayData) {
+ ALOGW("destroying client resources for display %" PRIu64, dpy.first);
+
+ for (const auto& ly : dpy.second.Layers) {
+ mHal.destroyLayer(dpy.first, ly.first);
+ }
+
+ if (dpy.second.IsVirtual) {
+ mHal.destroyVirtualDisplay(dpy.first);
+ } else {
+ ALOGW("performing a final presentDisplay");
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+ mHal.validateDisplay(dpy.first, &changedLayers, &compositionTypes,
+ &displayRequestMask, &requestedLayers, &requestMasks);
+
+ mHal.acceptDisplayChanges(dpy.first);
+
+ int32_t presentFence = -1;
+ std::vector<Layer> releasedLayers;
+ std::vector<int32_t> releaseFences;
+ mHal.presentDisplay(dpy.first, &presentFence, &releasedLayers, &releaseFences);
+ if (presentFence >= 0) {
+ close(presentFence);
+ }
+ for (auto fence : releaseFences) {
+ if (fence >= 0) {
+ close(fence);
+ }
+ }
+ }
+ }
+
+ mDisplayData.clear();
+
+ sHandleImporter.cleanup();
+
+ mHal.removeClient();
+
+ ALOGW("removed composer client");
+}
+
+void ComposerClient::initialize()
+{
+ mReader = createCommandReader();
+ if (!sHandleImporter.initialize()) {
+ LOG_ALWAYS_FATAL("failed to initialize handle importer");
+ }
+}
+
+void ComposerClient::onHotplug(Display display,
+ IComposerCallback::Connection connected)
+{
+ {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ mDisplayData.emplace(display, DisplayData(false));
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mDisplayData.erase(display);
+ }
+ }
+
+ auto ret = mCallback->onHotplug(display, connected);
+ ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s",
+ ret.description().c_str());
+}
+
+void ComposerClient::onRefresh(Display display)
+{
+ auto ret = mCallback->onRefresh(display);
+ ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s",
+ ret.description().c_str());
+}
+
+void ComposerClient::onVsync(Display display, int64_t timestamp)
+{
+ auto ret = mCallback->onVsync(display, timestamp);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s",
+ ret.description().c_str());
+}
+
+Return<void> ComposerClient::registerCallback(
+ const sp<IComposerCallback>& callback)
+{
+ // no locking as we require this function to be called only once
+ mCallback = callback;
+ mHal.enableCallback(callback != nullptr);
+
+ return Void();
+}
+
+Return<uint32_t> ComposerClient::getMaxVirtualDisplayCount()
+{
+ return mHal.getMaxVirtualDisplayCount();
+}
+
+Return<void> ComposerClient::createVirtualDisplay(uint32_t width,
+ uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
+ createVirtualDisplay_cb hidl_cb)
+{
+ Display display = 0;
+ Error err = mHal.createVirtualDisplay(width, height,
+ &formatHint, &display);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.emplace(display, DisplayData(true)).first;
+ dpy->second.OutputBuffers.resize(outputBufferSlotCount);
+ }
+
+ hidl_cb(err, display, formatHint);
+ return Void();
+}
+
+Return<Error> ComposerClient::destroyVirtualDisplay(Display display)
+{
+ Error err = mHal.destroyVirtualDisplay(display);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ mDisplayData.erase(display);
+ }
+
+ return err;
+}
+
+Return<void> ComposerClient::createLayer(Display display,
+ uint32_t bufferSlotCount, createLayer_cb hidl_cb)
+{
+ Layer layer = 0;
+ Error err = mHal.createLayer(display, &layer);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
+ ly->second.Buffers.resize(bufferSlotCount);
+ }
+
+ hidl_cb(err, layer);
+ return Void();
+}
+
+Return<Error> ComposerClient::destroyLayer(Display display, Layer layer)
+{
+ Error err = mHal.destroyLayer(display, layer);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ dpy->second.Layers.erase(layer);
+ }
+
+ return err;
+}
+
+Return<void> ComposerClient::getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb)
+{
+ Config config = 0;
+ Error err = mHal.getActiveConfig(display, &config);
+
+ hidl_cb(err, config);
+ return Void();
+}
+
+Return<Error> ComposerClient::getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace)
+{
+ Error err = mHal.getClientTargetSupport(display,
+ width, height, format, dataspace);
+ return err;
+}
+
+Return<void> ComposerClient::getColorModes(Display display,
+ getColorModes_cb hidl_cb)
+{
+ hidl_vec<ColorMode> modes;
+ Error err = mHal.getColorModes(display, &modes);
+
+ hidl_cb(err, modes);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayAttribute(Display display,
+ Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb)
+{
+ int32_t value = 0;
+ Error err = mHal.getDisplayAttribute(display, config, attribute, &value);
+
+ hidl_cb(err, value);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb)
+{
+ hidl_vec<Config> configs;
+ Error err = mHal.getDisplayConfigs(display, &configs);
+
+ hidl_cb(err, configs);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayName(Display display,
+ getDisplayName_cb hidl_cb)
+{
+ hidl_string name;
+ Error err = mHal.getDisplayName(display, &name);
+
+ hidl_cb(err, name);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayType(Display display,
+ getDisplayType_cb hidl_cb)
+{
+ DisplayType type = DisplayType::INVALID;
+ Error err = mHal.getDisplayType(display, &type);
+
+ hidl_cb(err, type);
+ return Void();
+}
+
+Return<void> ComposerClient::getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb)
+{
+ bool support = false;
+ Error err = mHal.getDozeSupport(display, &support);
+
+ hidl_cb(err, support);
+ return Void();
+}
+
+Return<void> ComposerClient::getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb)
+{
+ hidl_vec<Hdr> types;
+ float max_lumi = 0.0f;
+ float max_avg_lumi = 0.0f;
+ float min_lumi = 0.0f;
+ Error err = mHal.getHdrCapabilities(display, &types,
+ &max_lumi, &max_avg_lumi, &min_lumi);
+
+ hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
+ return Void();
+}
+
+Return<Error> ComposerClient::setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount)
+{
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ if (dpy == mDisplayData.end()) {
+ return Error::BAD_DISPLAY;
+ }
+
+ dpy->second.ClientTargets.resize(clientTargetSlotCount);
+
+ return Error::NONE;
+}
+
+Return<Error> ComposerClient::setActiveConfig(Display display, Config config)
+{
+ Error err = mHal.setActiveConfig(display, config);
+ return err;
+}
+
+Return<Error> ComposerClient::setColorMode(Display display, ColorMode mode)
+{
+ Error err = mHal.setColorMode(display, mode);
+ return err;
+}
+
+Return<Error> ComposerClient::setPowerMode(Display display, PowerMode mode)
+{
+ Error err = mHal.setPowerMode(display, mode);
+ return err;
+}
+
+Return<Error> ComposerClient::setVsyncEnabled(Display display, Vsync enabled)
+{
+ Error err = mHal.setVsyncEnabled(display, enabled);
+ return err;
+}
+
+Return<Error> ComposerClient::setInputCommandQueue(
+ const MQDescriptorSync<uint32_t>& descriptor)
+{
+ std::lock_guard<std::mutex> lock(mCommandMutex);
+ return mReader->setMQDescriptor(descriptor) ?
+ Error::NONE : Error::NO_RESOURCES;
+}
+
+Return<void> ComposerClient::getOutputCommandQueue(
+ getOutputCommandQueue_cb hidl_cb)
+{
+ // no locking as we require this function to be called inside
+ // executeCommands_cb
+
+ auto outDescriptor = mWriter.getMQDescriptor();
+ if (outDescriptor) {
+ hidl_cb(Error::NONE, *outDescriptor);
+ } else {
+ hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
+ }
+
+ return Void();
+}
+
+Return<void> ComposerClient::executeCommands(uint32_t inLength,
+ const hidl_vec<hidl_handle>& inHandles,
+ executeCommands_cb hidl_cb)
+{
+ std::lock_guard<std::mutex> lock(mCommandMutex);
+
+ bool outChanged = false;
+ uint32_t outLength = 0;
+ hidl_vec<hidl_handle> outHandles;
+
+ if (!mReader->readQueue(inLength, inHandles)) {
+ hidl_cb(Error::BAD_PARAMETER, outChanged, outLength, outHandles);
+ return Void();
+ }
+
+ Error err = mReader->parse();
+ if (err == Error::NONE &&
+ !mWriter.writeQueue(&outChanged, &outLength, &outHandles)) {
+ err = Error::NO_RESOURCES;
+ }
+
+ hidl_cb(err, outChanged, outLength, outHandles);
+
+ mReader->reset();
+ mWriter.reset();
+
+ return Void();
+}
+
+std::unique_ptr<ComposerClient::CommandReader>
+ComposerClient::createCommandReader()
+{
+ return std::unique_ptr<ComposerClient::CommandReader>(
+ new CommandReader(*this));
+}
+
+ComposerClient::CommandReader::CommandReader(ComposerClient& client)
+ : mClient(client), mHal(client.mHal), mWriter(client.mWriter)
+{
+}
+
+ComposerClient::CommandReader::~CommandReader()
+{
+}
+
+Error ComposerClient::CommandReader::parse()
+{
+ IComposerClient::Command command;
+ uint16_t length = 0;
+
+ while (!isEmpty()) {
+ if (!beginCommand(&command, &length)) {
+ break;
+ }
+
+ bool parsed = parseCommand(command, length);
+ endCommand();
+
+ if (!parsed) {
+ ALOGE("failed to parse command 0x%x, length %" PRIu16,
+ command, length);
+ break;
+ }
+ }
+
+ return (isEmpty()) ? Error::NONE : Error::BAD_PARAMETER;
+}
+
+bool ComposerClient::CommandReader::parseCommand(
+ IComposerClient::Command command, uint16_t length) {
+ switch (command) {
+ case IComposerClient::Command::SELECT_DISPLAY:
+ return parseSelectDisplay(length);
+ case IComposerClient::Command::SELECT_LAYER:
+ return parseSelectLayer(length);
+ case IComposerClient::Command::SET_COLOR_TRANSFORM:
+ return parseSetColorTransform(length);
+ case IComposerClient::Command::SET_CLIENT_TARGET:
+ return parseSetClientTarget(length);
+ case IComposerClient::Command::SET_OUTPUT_BUFFER:
+ return parseSetOutputBuffer(length);
+ case IComposerClient::Command::VALIDATE_DISPLAY:
+ return parseValidateDisplay(length);
+ case IComposerClient::Command::ACCEPT_DISPLAY_CHANGES:
+ return parseAcceptDisplayChanges(length);
+ case IComposerClient::Command::PRESENT_DISPLAY:
+ return parsePresentDisplay(length);
+ case IComposerClient::Command::SET_LAYER_CURSOR_POSITION:
+ return parseSetLayerCursorPosition(length);
+ case IComposerClient::Command::SET_LAYER_BUFFER:
+ return parseSetLayerBuffer(length);
+ case IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE:
+ return parseSetLayerSurfaceDamage(length);
+ case IComposerClient::Command::SET_LAYER_BLEND_MODE:
+ return parseSetLayerBlendMode(length);
+ case IComposerClient::Command::SET_LAYER_COLOR:
+ return parseSetLayerColor(length);
+ case IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE:
+ return parseSetLayerCompositionType(length);
+ case IComposerClient::Command::SET_LAYER_DATASPACE:
+ return parseSetLayerDataspace(length);
+ case IComposerClient::Command::SET_LAYER_DISPLAY_FRAME:
+ return parseSetLayerDisplayFrame(length);
+ case IComposerClient::Command::SET_LAYER_PLANE_ALPHA:
+ return parseSetLayerPlaneAlpha(length);
+ case IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM:
+ return parseSetLayerSidebandStream(length);
+ case IComposerClient::Command::SET_LAYER_SOURCE_CROP:
+ return parseSetLayerSourceCrop(length);
+ case IComposerClient::Command::SET_LAYER_TRANSFORM:
+ return parseSetLayerTransform(length);
+ case IComposerClient::Command::SET_LAYER_VISIBLE_REGION:
+ return parseSetLayerVisibleRegion(length);
+ case IComposerClient::Command::SET_LAYER_Z_ORDER:
+ return parseSetLayerZOrder(length);
+ default:
+ return false;
+ }
+}
+
+bool ComposerClient::CommandReader::parseSelectDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kSelectDisplayLength) {
+ return false;
+ }
+
+ mDisplay = read64();
+ mWriter.selectDisplay(mDisplay);
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSelectLayer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSelectLayerLength) {
+ return false;
+ }
+
+ mLayer = read64();
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetColorTransform(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetColorTransformLength) {
+ return false;
+ }
+
+ float matrix[16];
+ for (int i = 0; i < 16; i++) {
+ matrix[i] = readFloat();
+ }
+ auto transform = readSigned();
+
+ auto err = mHal.setColorTransform(mDisplay, matrix, transform);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetClientTarget(uint16_t length)
+{
+ // 4 parameters followed by N rectangles
+ if ((length - 4) % 4 != 0) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto clientTarget = readHandle(&useCache);
+ auto fence = readFence();
+ auto dataspace = readSigned();
+ auto damage = readRegion((length - 4) / 4);
+
+ auto err = lookupBuffer(BufferCache::CLIENT_TARGETS,
+ slot, useCache, clientTarget, &clientTarget);
+ if (err == Error::NONE) {
+ err = mHal.setClientTarget(mDisplay, clientTarget, fence,
+ dataspace, damage);
+
+ updateBuffer(BufferCache::CLIENT_TARGETS, slot, useCache,
+ clientTarget);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetOutputBuffer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetOutputBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto outputBuffer = readHandle(&useCache);
+ auto fence = readFence();
+
+ auto err = lookupBuffer(BufferCache::OUTPUT_BUFFERS,
+ slot, useCache, outputBuffer, &outputBuffer);
+ if (err == Error::NONE) {
+ err = mHal.setOutputBuffer(mDisplay, outputBuffer, fence);
+
+ updateBuffer(BufferCache::OUTPUT_BUFFERS,
+ slot, useCache, outputBuffer);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseValidateDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kValidateDisplayLength) {
+ return false;
+ }
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal.validateDisplay(mDisplay, &changedLayers,
+ &compositionTypes, &displayRequestMask,
+ &requestedLayers, &requestMasks);
+ if (err == Error::NONE) {
+ mWriter.setChangedCompositionTypes(changedLayers,
+ compositionTypes);
+ mWriter.setDisplayRequests(displayRequestMask,
+ requestedLayers, requestMasks);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseAcceptDisplayChanges(uint16_t length)
+{
+ if (length != CommandWriterBase::kAcceptDisplayChangesLength) {
+ return false;
+ }
+
+ auto err = mHal.acceptDisplayChanges(mDisplay);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parsePresentDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kPresentDisplayLength) {
+ return false;
+ }
+
+ int presentFence = -1;
+ std::vector<Layer> layers;
+ std::vector<int> fences;
+ auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences);
+ if (err == Error::NONE) {
+ mWriter.setPresentFence(presentFence);
+ mWriter.setReleaseFences(layers, fences);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerCursorPosition(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerCursorPositionLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerCursorPosition(mDisplay, mLayer,
+ readSigned(), readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerBuffer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto buffer = readHandle(&useCache);
+ auto fence = readFence();
+
+ auto err = lookupBuffer(BufferCache::LAYER_BUFFERS,
+ slot, useCache, buffer, &buffer);
+ if (err == Error::NONE) {
+ err = mHal.setLayerBuffer(mDisplay, mLayer, buffer, fence);
+
+ updateBuffer(BufferCache::LAYER_BUFFERS,
+ slot, useCache, buffer);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSurfaceDamage(uint16_t length)
+{
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto damage = readRegion(length / 4);
+ auto err = mHal.setLayerSurfaceDamage(mDisplay, mLayer, damage);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerBlendMode(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerBlendModeLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerBlendMode(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerColor(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerColorLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerColor(mDisplay, mLayer, readColor());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerCompositionType(
+ uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerCompositionTypeLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerCompositionType(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerDataspace(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerDataspaceLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerDataspace(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerDisplayFrame(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerDisplayFrameLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerDisplayFrame(mDisplay, mLayer, readRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerPlaneAlpha(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerPlaneAlphaLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerPlaneAlpha(mDisplay, mLayer, readFloat());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSidebandStream(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerSidebandStreamLength) {
+ return false;
+ }
+
+ auto stream = readHandle();
+
+ auto err = lookupLayerSidebandStream(stream, &stream);
+ if (err == Error::NONE) {
+ err = mHal.setLayerSidebandStream(mDisplay, mLayer, stream);
+
+ updateLayerSidebandStream(stream);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSourceCrop(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerSourceCropLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerSourceCrop(mDisplay, mLayer, readFRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerTransform(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerTransformLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerTransform(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerVisibleRegion(uint16_t length)
+{
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto region = readRegion(length / 4);
+ auto err = mHal.setLayerVisibleRegion(mDisplay, mLayer, region);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerZOrder(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerZOrderLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerZOrder(mDisplay, mLayer, read());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+hwc_rect_t ComposerClient::CommandReader::readRect()
+{
+ return hwc_rect_t{
+ readSigned(),
+ readSigned(),
+ readSigned(),
+ readSigned(),
+ };
+}
+
+std::vector<hwc_rect_t> ComposerClient::CommandReader::readRegion(size_t count)
+{
+ std::vector<hwc_rect_t> region;
+ region.reserve(count);
+ while (count > 0) {
+ region.emplace_back(readRect());
+ count--;
+ }
+
+ return region;
+}
+
+hwc_frect_t ComposerClient::CommandReader::readFRect()
+{
+ return hwc_frect_t{
+ readFloat(),
+ readFloat(),
+ readFloat(),
+ readFloat(),
+ };
+}
+
+Error ComposerClient::CommandReader::lookupBufferCacheEntryLocked(
+ BufferCache cache, uint32_t slot, BufferCacheEntry** outEntry)
+{
+ auto dpy = mClient.mDisplayData.find(mDisplay);
+ if (dpy == mClient.mDisplayData.end()) {
+ return Error::BAD_DISPLAY;
+ }
+
+ BufferCacheEntry* entry = nullptr;
+ switch (cache) {
+ case BufferCache::CLIENT_TARGETS:
+ if (slot < dpy->second.ClientTargets.size()) {
+ entry = &dpy->second.ClientTargets[slot];
+ }
+ break;
+ case BufferCache::OUTPUT_BUFFERS:
+ if (slot < dpy->second.OutputBuffers.size()) {
+ entry = &dpy->second.OutputBuffers[slot];
+ }
+ break;
+ case BufferCache::LAYER_BUFFERS:
+ {
+ auto ly = dpy->second.Layers.find(mLayer);
+ if (ly == dpy->second.Layers.end()) {
+ return Error::BAD_LAYER;
+ }
+ if (slot < ly->second.Buffers.size()) {
+ entry = &ly->second.Buffers[slot];
+ }
+ }
+ break;
+ case BufferCache::LAYER_SIDEBAND_STREAMS:
+ {
+ auto ly = dpy->second.Layers.find(mLayer);
+ if (ly == dpy->second.Layers.end()) {
+ return Error::BAD_LAYER;
+ }
+ if (slot == 0) {
+ entry = &ly->second.SidebandStream;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!entry) {
+ ALOGW("invalid buffer slot %" PRIu32, slot);
+ return Error::BAD_PARAMETER;
+ }
+
+ *outEntry = entry;
+
+ return Error::NONE;
+}
+
+Error ComposerClient::CommandReader::lookupBuffer(BufferCache cache,
+ uint32_t slot, bool useCache, buffer_handle_t handle,
+ buffer_handle_t* outHandle)
+{
+ if (useCache) {
+ std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex);
+
+ BufferCacheEntry* entry;
+ Error error = lookupBufferCacheEntryLocked(cache, slot, &entry);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ // input handle is ignored
+ *outHandle = entry->getHandle();
+ } else {
+ if (!sHandleImporter.importBuffer(handle)) {
+ return Error::NO_RESOURCES;
+ }
+
+ *outHandle = handle;
+ }
+
+ return Error::NONE;
+}
+
+void ComposerClient::CommandReader::updateBuffer(BufferCache cache,
+ uint32_t slot, bool useCache, buffer_handle_t handle)
+{
+ // handle was looked up from cache
+ if (useCache) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex);
+
+ BufferCacheEntry* entry = nullptr;
+ lookupBufferCacheEntryLocked(cache, slot, &entry);
+ LOG_FATAL_IF(!entry, "failed to find the cache entry to update");
+
+ *entry = handle;
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/default/ComposerClient.h b/graphics/composer/2.1/default/ComposerClient.h
new file mode 100644
index 0000000..c973351
--- /dev/null
+++ b/graphics/composer/2.1/default/ComposerClient.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
+
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <hardware/hwcomposer2.h>
+#include "IComposerCommandBuffer.h"
+#include "ComposerBase.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+class BufferCacheEntry {
+public:
+ BufferCacheEntry();
+ BufferCacheEntry(BufferCacheEntry&& other);
+
+ BufferCacheEntry(const BufferCacheEntry& other) = delete;
+ BufferCacheEntry& operator=(const BufferCacheEntry& other) = delete;
+
+ BufferCacheEntry& operator=(buffer_handle_t handle);
+ ~BufferCacheEntry();
+
+ buffer_handle_t getHandle() const { return mHandle; }
+
+private:
+ void clear();
+
+ buffer_handle_t mHandle;
+};
+
+class ComposerClient : public IComposerClient {
+public:
+ ComposerClient(ComposerBase& hal);
+ virtual ~ComposerClient();
+
+ void initialize();
+
+ void onHotplug(Display display, IComposerCallback::Connection connected);
+ void onRefresh(Display display);
+ void onVsync(Display display, int64_t timestamp);
+
+ // IComposerClient interface
+ Return<void> registerCallback(
+ const sp<IComposerCallback>& callback) override;
+ Return<uint32_t> getMaxVirtualDisplayCount() override;
+ Return<void> createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint, uint32_t outputBufferSlotCount,
+ createVirtualDisplay_cb hidl_cb) override;
+ Return<Error> destroyVirtualDisplay(Display display) override;
+ Return<void> createLayer(Display display, uint32_t bufferSlotCount,
+ createLayer_cb hidl_cb) override;
+ Return<Error> destroyLayer(Display display, Layer layer) override;
+ Return<void> getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb) override;
+ Return<Error> getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override;
+ Return<void> getColorModes(Display display,
+ getColorModes_cb hidl_cb) override;
+ Return<void> getDisplayAttribute(Display display,
+ Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb) override;
+ Return<void> getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb) override;
+ Return<void> getDisplayName(Display display,
+ getDisplayName_cb hidl_cb) override;
+ Return<void> getDisplayType(Display display,
+ getDisplayType_cb hidl_cb) override;
+ Return<void> getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb) override;
+ Return<void> getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb) override;
+ Return<Error> setActiveConfig(Display display, Config config) override;
+ Return<Error> setColorMode(Display display, ColorMode mode) override;
+ Return<Error> setPowerMode(Display display, PowerMode mode) override;
+ Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
+ Return<Error> setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount) override;
+ Return<Error> setInputCommandQueue(
+ const MQDescriptorSync<uint32_t>& descriptor) override;
+ Return<void> getOutputCommandQueue(
+ getOutputCommandQueue_cb hidl_cb) override;
+ Return<void> executeCommands(uint32_t inLength,
+ const hidl_vec<hidl_handle>& inHandles,
+ executeCommands_cb hidl_cb) override;
+
+protected:
+ struct LayerBuffers {
+ std::vector<BufferCacheEntry> Buffers;
+ BufferCacheEntry SidebandStream;
+ };
+
+ struct DisplayData {
+ bool IsVirtual;
+
+ std::vector<BufferCacheEntry> ClientTargets;
+ std::vector<BufferCacheEntry> OutputBuffers;
+
+ std::unordered_map<Layer, LayerBuffers> Layers;
+
+ DisplayData(bool isVirtual) : IsVirtual(isVirtual) {}
+ };
+
+ class CommandReader : public CommandReaderBase {
+ public:
+ CommandReader(ComposerClient& client);
+ virtual ~CommandReader();
+
+ Error parse();
+
+ protected:
+ virtual bool parseCommand(IComposerClient::Command command,
+ uint16_t length);
+
+ bool parseSelectDisplay(uint16_t length);
+ bool parseSelectLayer(uint16_t length);
+ bool parseSetColorTransform(uint16_t length);
+ bool parseSetClientTarget(uint16_t length);
+ bool parseSetOutputBuffer(uint16_t length);
+ bool parseValidateDisplay(uint16_t length);
+ bool parseAcceptDisplayChanges(uint16_t length);
+ bool parsePresentDisplay(uint16_t length);
+ bool parseSetLayerCursorPosition(uint16_t length);
+ bool parseSetLayerBuffer(uint16_t length);
+ bool parseSetLayerSurfaceDamage(uint16_t length);
+ bool parseSetLayerBlendMode(uint16_t length);
+ bool parseSetLayerColor(uint16_t length);
+ bool parseSetLayerCompositionType(uint16_t length);
+ bool parseSetLayerDataspace(uint16_t length);
+ bool parseSetLayerDisplayFrame(uint16_t length);
+ bool parseSetLayerPlaneAlpha(uint16_t length);
+ bool parseSetLayerSidebandStream(uint16_t length);
+ bool parseSetLayerSourceCrop(uint16_t length);
+ bool parseSetLayerTransform(uint16_t length);
+ bool parseSetLayerVisibleRegion(uint16_t length);
+ bool parseSetLayerZOrder(uint16_t length);
+
+ hwc_rect_t readRect();
+ std::vector<hwc_rect_t> readRegion(size_t count);
+ hwc_frect_t readFRect();
+
+ enum class BufferCache {
+ CLIENT_TARGETS,
+ OUTPUT_BUFFERS,
+ LAYER_BUFFERS,
+ LAYER_SIDEBAND_STREAMS,
+ };
+ Error lookupBufferCacheEntryLocked(BufferCache cache, uint32_t slot,
+ BufferCacheEntry** outEntry);
+ Error lookupBuffer(BufferCache cache, uint32_t slot,
+ bool useCache, buffer_handle_t handle,
+ buffer_handle_t* outHandle);
+ void updateBuffer(BufferCache cache, uint32_t slot,
+ bool useCache, buffer_handle_t handle);
+
+ Error lookupLayerSidebandStream(buffer_handle_t handle,
+ buffer_handle_t* outHandle)
+ {
+ return lookupBuffer(BufferCache::LAYER_SIDEBAND_STREAMS,
+ 0, false, handle, outHandle);
+ }
+ void updateLayerSidebandStream(buffer_handle_t handle)
+ {
+ updateBuffer(BufferCache::LAYER_SIDEBAND_STREAMS,
+ 0, false, handle);
+ }
+
+ ComposerClient& mClient;
+ ComposerBase& mHal;
+ CommandWriterBase& mWriter;
+
+ Display mDisplay;
+ Layer mLayer;
+ };
+
+ virtual std::unique_ptr<CommandReader> createCommandReader();
+
+ ComposerBase& mHal;
+
+ // 64KiB minus a small space for metadata such as read/write pointers
+ static constexpr size_t kWriterInitialSize =
+ 64 * 1024 / sizeof(uint32_t) - 16;
+ std::mutex mCommandMutex;
+ std::unique_ptr<CommandReader> mReader;
+ CommandWriterBase mWriter;
+
+ sp<IComposerCallback> mCallback;
+
+ std::mutex mDisplayDataMutex;
+ std::unordered_map<Display, DisplayData> mDisplayData;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp
new file mode 100644
index 0000000..1497065
--- /dev/null
+++ b/graphics/composer/2.1/default/Hwc.cpp
@@ -0,0 +1,737 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "HwcPassthrough"
+
+#include "Hwc.h"
+
+#include <type_traits>
+#include <log/log.h>
+
+#include "ComposerClient.h"
+#include "hardware/hwcomposer.h"
+#include "hwc2on1adapter/HWC2On1Adapter.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+
+HwcHal::HwcHal(const hw_module_t* module)
+ : mDevice(nullptr), mDispatch(), mAdapter()
+{
+ // Determine what kind of module is available (HWC2 vs HWC1.X).
+ hw_device_t* device = nullptr;
+ int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
+ if (error != 0) {
+ ALOGE("Failed to open HWC device (%s), aborting", strerror(-error));
+ abort();
+ }
+ uint32_t majorVersion = (device->version >> 24) & 0xF;
+
+ // If we don't have a HWC2, we need to wrap whatever we have in an adapter.
+ if (majorVersion != 2) {
+ uint32_t minorVersion = device->version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+ minorVersion = (minorVersion >> 16) & 0xF;
+ ALOGI("Found HWC implementation v%d.%d", majorVersion, minorVersion);
+ if (minorVersion < 1) {
+ ALOGE("Cannot adapt to HWC version %d.%d. Minimum supported is 1.1",
+ majorVersion, minorVersion);
+ abort();
+ }
+ mAdapter = std::make_unique<HWC2On1Adapter>(
+ reinterpret_cast<hwc_composer_device_1*>(device));
+
+ // Place the adapter in front of the device module.
+ mDevice = mAdapter.get();
+ } else {
+ mDevice = reinterpret_cast<hwc2_device_t*>(device);
+ }
+
+ initCapabilities();
+ initDispatch();
+}
+
+HwcHal::~HwcHal()
+{
+ hwc2_close(mDevice);
+}
+
+void HwcHal::initCapabilities()
+{
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<Capability> caps(count);
+ mDevice->getCapabilities(mDevice, &count, reinterpret_cast<
+ std::underlying_type<Capability>::type*>(caps.data()));
+ caps.resize(count);
+
+ mCapabilities.insert(caps.cbegin(), caps.cend());
+}
+
+template<typename T>
+void HwcHal::initDispatch(hwc2_function_descriptor_t desc, T* outPfn)
+{
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ LOG_ALWAYS_FATAL("failed to get hwcomposer2 function %d", desc);
+ }
+
+ *outPfn = reinterpret_cast<T>(pfn);
+}
+
+void HwcHal::initDispatch()
+{
+ initDispatch(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES,
+ &mDispatch.acceptDisplayChanges);
+ initDispatch(HWC2_FUNCTION_CREATE_LAYER, &mDispatch.createLayer);
+ initDispatch(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY,
+ &mDispatch.createVirtualDisplay);
+ initDispatch(HWC2_FUNCTION_DESTROY_LAYER, &mDispatch.destroyLayer);
+ initDispatch(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
+ &mDispatch.destroyVirtualDisplay);
+ initDispatch(HWC2_FUNCTION_DUMP, &mDispatch.dump);
+ initDispatch(HWC2_FUNCTION_GET_ACTIVE_CONFIG, &mDispatch.getActiveConfig);
+ initDispatch(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
+ &mDispatch.getChangedCompositionTypes);
+ initDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
+ &mDispatch.getClientTargetSupport);
+ initDispatch(HWC2_FUNCTION_GET_COLOR_MODES, &mDispatch.getColorModes);
+ initDispatch(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE,
+ &mDispatch.getDisplayAttribute);
+ initDispatch(HWC2_FUNCTION_GET_DISPLAY_CONFIGS,
+ &mDispatch.getDisplayConfigs);
+ initDispatch(HWC2_FUNCTION_GET_DISPLAY_NAME, &mDispatch.getDisplayName);
+ initDispatch(HWC2_FUNCTION_GET_DISPLAY_REQUESTS,
+ &mDispatch.getDisplayRequests);
+ initDispatch(HWC2_FUNCTION_GET_DISPLAY_TYPE, &mDispatch.getDisplayType);
+ initDispatch(HWC2_FUNCTION_GET_DOZE_SUPPORT, &mDispatch.getDozeSupport);
+ initDispatch(HWC2_FUNCTION_GET_HDR_CAPABILITIES,
+ &mDispatch.getHdrCapabilities);
+ initDispatch(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
+ &mDispatch.getMaxVirtualDisplayCount);
+ initDispatch(HWC2_FUNCTION_GET_RELEASE_FENCES,
+ &mDispatch.getReleaseFences);
+ initDispatch(HWC2_FUNCTION_PRESENT_DISPLAY, &mDispatch.presentDisplay);
+ initDispatch(HWC2_FUNCTION_REGISTER_CALLBACK,
+ &mDispatch.registerCallback);
+ initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG, &mDispatch.setActiveConfig);
+ initDispatch(HWC2_FUNCTION_SET_CLIENT_TARGET, &mDispatch.setClientTarget);
+ initDispatch(HWC2_FUNCTION_SET_COLOR_MODE, &mDispatch.setColorMode);
+ initDispatch(HWC2_FUNCTION_SET_COLOR_TRANSFORM,
+ &mDispatch.setColorTransform);
+ initDispatch(HWC2_FUNCTION_SET_CURSOR_POSITION,
+ &mDispatch.setCursorPosition);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_BLEND_MODE,
+ &mDispatch.setLayerBlendMode);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_BUFFER, &mDispatch.setLayerBuffer);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_COLOR, &mDispatch.setLayerColor);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
+ &mDispatch.setLayerCompositionType);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_DATASPACE,
+ &mDispatch.setLayerDataspace);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME,
+ &mDispatch.setLayerDisplayFrame);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA,
+ &mDispatch.setLayerPlaneAlpha);
+
+ if (hasCapability(Capability::SIDEBAND_STREAM)) {
+ initDispatch(HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM,
+ &mDispatch.setLayerSidebandStream);
+ }
+
+ initDispatch(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP,
+ &mDispatch.setLayerSourceCrop);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
+ &mDispatch.setLayerSurfaceDamage);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_TRANSFORM,
+ &mDispatch.setLayerTransform);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
+ &mDispatch.setLayerVisibleRegion);
+ initDispatch(HWC2_FUNCTION_SET_LAYER_Z_ORDER, &mDispatch.setLayerZOrder);
+ initDispatch(HWC2_FUNCTION_SET_OUTPUT_BUFFER, &mDispatch.setOutputBuffer);
+ initDispatch(HWC2_FUNCTION_SET_POWER_MODE, &mDispatch.setPowerMode);
+ initDispatch(HWC2_FUNCTION_SET_VSYNC_ENABLED, &mDispatch.setVsyncEnabled);
+ initDispatch(HWC2_FUNCTION_VALIDATE_DISPLAY, &mDispatch.validateDisplay);
+}
+
+bool HwcHal::hasCapability(Capability capability) const
+{
+ return (mCapabilities.count(capability) > 0);
+}
+
+Return<void> HwcHal::getCapabilities(getCapabilities_cb hidl_cb)
+{
+ std::vector<Capability> caps(
+ mCapabilities.cbegin(), mCapabilities.cend());
+
+ hidl_vec<Capability> caps_reply;
+ caps_reply.setToExternal(caps.data(), caps.size());
+ hidl_cb(caps_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb)
+{
+ uint32_t len = 0;
+ mDispatch.dump(mDevice, &len, nullptr);
+
+ std::vector<char> buf(len + 1);
+ mDispatch.dump(mDevice, &len, buf.data());
+ buf.resize(len + 1);
+ buf[len] = '\0';
+
+ hidl_string buf_reply;
+ buf_reply.setToExternal(buf.data(), len);
+ hidl_cb(buf_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::createClient(createClient_cb hidl_cb)
+{
+ Error err = Error::NONE;
+ sp<ComposerClient> client;
+
+ {
+ std::lock_guard<std::mutex> lock(mClientMutex);
+
+ // only one client is allowed
+ if (mClient == nullptr) {
+ client = new ComposerClient(*this);
+ client->initialize();
+ mClient = client;
+ } else {
+ err = Error::NO_RESOURCES;
+ }
+ }
+
+ hidl_cb(err, client);
+
+ return Void();
+}
+
+sp<ComposerClient> HwcHal::getClient()
+{
+ std::lock_guard<std::mutex> lock(mClientMutex);
+ return (mClient != nullptr) ? mClient.promote() : nullptr;
+}
+
+void HwcHal::removeClient()
+{
+ std::lock_guard<std::mutex> lock(mClientMutex);
+ mClient = nullptr;
+}
+
+void HwcHal::hotplugHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connected)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+ auto client = hal->getClient();
+ if (client != nullptr) {
+ client->onHotplug(display,
+ static_cast<IComposerCallback::Connection>(connected));
+ }
+}
+
+void HwcHal::refreshHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+ auto client = hal->getClient();
+ if (client != nullptr) {
+ client->onRefresh(display);
+ }
+}
+
+void HwcHal::vsyncHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+ auto client = hal->getClient();
+ if (client != nullptr) {
+ client->onVsync(display, timestamp);
+ }
+}
+
+void HwcHal::enableCallback(bool enable)
+{
+ if (enable) {
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+ reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+ } else {
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+ nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+ nullptr);
+ }
+}
+
+uint32_t HwcHal::getMaxVirtualDisplayCount()
+{
+ return mDispatch.getMaxVirtualDisplayCount(mDevice);
+}
+
+Error HwcHal::createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat* format, Display* outDisplay)
+{
+ int32_t hwc_format = static_cast<int32_t>(*format);
+ int32_t err = mDispatch.createVirtualDisplay(mDevice, width, height,
+ &hwc_format, outDisplay);
+ *format = static_cast<PixelFormat>(hwc_format);
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::destroyVirtualDisplay(Display display)
+{
+ int32_t err = mDispatch.destroyVirtualDisplay(mDevice, display);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::createLayer(Display display, Layer* outLayer)
+{
+ int32_t err = mDispatch.createLayer(mDevice, display, outLayer);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::destroyLayer(Display display, Layer layer)
+{
+ int32_t err = mDispatch.destroyLayer(mDevice, display, layer);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getActiveConfig(Display display, Config* outConfig)
+{
+ int32_t err = mDispatch.getActiveConfig(mDevice, display, outConfig);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace)
+{
+ int32_t err = mDispatch.getClientTargetSupport(mDevice, display,
+ width, height, static_cast<int32_t>(format),
+ static_cast<int32_t>(dataspace));
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getColorModes(Display display, hidl_vec<ColorMode>* outModes)
+{
+ uint32_t count = 0;
+ int32_t err = mDispatch.getColorModes(mDevice, display, &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outModes->resize(count);
+ err = mDispatch.getColorModes(mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<ColorMode>::type*>(
+ outModes->data()));
+ if (err != HWC2_ERROR_NONE) {
+ *outModes = hidl_vec<ColorMode>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+}
+
+Error HwcHal::getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue)
+{
+ int32_t err = mDispatch.getDisplayAttribute(mDevice, display, config,
+ static_cast<int32_t>(attribute), outValue);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs)
+{
+ uint32_t count = 0;
+ int32_t err = mDispatch.getDisplayConfigs(mDevice, display,
+ &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outConfigs->resize(count);
+ err = mDispatch.getDisplayConfigs(mDevice, display,
+ &count, outConfigs->data());
+ if (err != HWC2_ERROR_NONE) {
+ *outConfigs = hidl_vec<Config>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+}
+
+Error HwcHal::getDisplayName(Display display, hidl_string* outName)
+{
+ uint32_t count = 0;
+ int32_t err = mDispatch.getDisplayName(mDevice, display, &count, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ std::vector<char> buf(count + 1);
+ err = mDispatch.getDisplayName(mDevice, display, &count, buf.data());
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+ buf.resize(count + 1);
+ buf[count] = '\0';
+
+ *outName = buf.data();
+
+ return Error::NONE;
+}
+
+Error HwcHal::getDisplayType(Display display,
+ IComposerClient::DisplayType* outType)
+{
+ int32_t hwc_type = HWC2_DISPLAY_TYPE_INVALID;
+ int32_t err = mDispatch.getDisplayType(mDevice, display, &hwc_type);
+ *outType = static_cast<IComposerClient::DisplayType>(hwc_type);
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getDozeSupport(Display display, bool* outSupport)
+{
+ int32_t hwc_support = 0;
+ int32_t err = mDispatch.getDozeSupport(mDevice, display, &hwc_support);
+ *outSupport = hwc_support;
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance)
+{
+ uint32_t count = 0;
+ int32_t err = mDispatch.getHdrCapabilities(mDevice, display, &count,
+ nullptr, outMaxLuminance, outMaxAverageLuminance,
+ outMinLuminance);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outTypes->resize(count);
+ err = mDispatch.getHdrCapabilities(mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<Hdr>::type*>(
+ outTypes->data()), outMaxLuminance,
+ outMaxAverageLuminance, outMinLuminance);
+ if (err != HWC2_ERROR_NONE) {
+ *outTypes = hidl_vec<Hdr>();
+ return static_cast<Error>(err);
+ }
+
+ return Error::NONE;
+}
+
+Error HwcHal::setActiveConfig(Display display, Config config)
+{
+ int32_t err = mDispatch.setActiveConfig(mDevice, display, config);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setColorMode(Display display, ColorMode mode)
+{
+ int32_t err = mDispatch.setColorMode(mDevice, display,
+ static_cast<int32_t>(mode));
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setPowerMode(Display display, IComposerClient::PowerMode mode)
+{
+ int32_t err = mDispatch.setPowerMode(mDevice, display,
+ static_cast<int32_t>(mode));
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setVsyncEnabled(Display display, IComposerClient::Vsync enabled)
+{
+ int32_t err = mDispatch.setVsyncEnabled(mDevice, display,
+ static_cast<int32_t>(enabled));
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setColorTransform(Display display, const float* matrix,
+ int32_t hint)
+{
+ int32_t err = mDispatch.setColorTransform(mDevice, display, matrix, hint);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setClientTarget(Display display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace,
+ const std::vector<hwc_rect_t>& damage)
+{
+ hwc_region region = { damage.size(), damage.data() };
+ int32_t err = mDispatch.setClientTarget(mDevice, display, target,
+ acquireFence, dataspace, region);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setOutputBuffer(Display display, buffer_handle_t buffer,
+ int32_t releaseFence)
+{
+ int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer,
+ releaseFence);
+ // unlike in setClientTarget, releaseFence is owned by us
+ if (err == HWC2_ERROR_NONE && releaseFence >= 0) {
+ close(releaseFence);
+ }
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::validateDisplay(Display display,
+ std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks)
+{
+ uint32_t types_count = 0;
+ uint32_t reqs_count = 0;
+ int32_t err = mDispatch.validateDisplay(mDevice, display,
+ &types_count, &reqs_count);
+ if (err != HWC2_ERROR_NONE && err != HWC2_ERROR_HAS_CHANGES) {
+ return static_cast<Error>(err);
+ }
+
+ err = mDispatch.getChangedCompositionTypes(mDevice, display,
+ &types_count, nullptr, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ outChangedLayers->resize(types_count);
+ outCompositionTypes->resize(types_count);
+ err = mDispatch.getChangedCompositionTypes(mDevice, display,
+ &types_count, outChangedLayers->data(),
+ reinterpret_cast<
+ std::underlying_type<IComposerClient::Composition>::type*>(
+ outCompositionTypes->data()));
+ if (err != HWC2_ERROR_NONE) {
+ outChangedLayers->clear();
+ outCompositionTypes->clear();
+ return static_cast<Error>(err);
+ }
+
+ int32_t display_reqs = 0;
+ err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs,
+ &reqs_count, nullptr, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ outChangedLayers->clear();
+ outCompositionTypes->clear();
+ return static_cast<Error>(err);
+ }
+
+ outRequestedLayers->resize(reqs_count);
+ outRequestMasks->resize(reqs_count);
+ err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs,
+ &reqs_count, outRequestedLayers->data(),
+ reinterpret_cast<int32_t*>(outRequestMasks->data()));
+ if (err != HWC2_ERROR_NONE) {
+ outChangedLayers->clear();
+ outCompositionTypes->clear();
+
+ outRequestedLayers->clear();
+ outRequestMasks->clear();
+ return static_cast<Error>(err);
+ }
+
+ *outDisplayRequestMask = display_reqs;
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::acceptDisplayChanges(Display display)
+{
+ int32_t err = mDispatch.acceptDisplayChanges(mDevice, display);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::presentDisplay(Display display, int32_t* outPresentFence,
+ std::vector<Layer>* outLayers, std::vector<int32_t>* outReleaseFences)
+{
+ *outPresentFence = -1;
+ int32_t err = mDispatch.presentDisplay(mDevice, display, outPresentFence);
+ if (err != HWC2_ERROR_NONE) {
+ return static_cast<Error>(err);
+ }
+
+ uint32_t count = 0;
+ err = mDispatch.getReleaseFences(mDevice, display, &count,
+ nullptr, nullptr);
+ if (err != HWC2_ERROR_NONE) {
+ ALOGW("failed to get release fences");
+ return Error::NONE;
+ }
+
+ outLayers->resize(count);
+ outReleaseFences->resize(count);
+ err = mDispatch.getReleaseFences(mDevice, display, &count,
+ outLayers->data(), outReleaseFences->data());
+ if (err != HWC2_ERROR_NONE) {
+ ALOGW("failed to get release fences");
+ outLayers->clear();
+ outReleaseFences->clear();
+ return Error::NONE;
+ }
+
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerCursorPosition(Display display, Layer layer,
+ int32_t x, int32_t y)
+{
+ int32_t err = mDispatch.setCursorPosition(mDevice, display, layer, x, y);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerBuffer(Display display, Layer layer,
+ buffer_handle_t buffer, int32_t acquireFence)
+{
+ int32_t err = mDispatch.setLayerBuffer(mDevice, display, layer,
+ buffer, acquireFence);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage)
+{
+ hwc_region region = { damage.size(), damage.data() };
+ int32_t err = mDispatch.setLayerSurfaceDamage(mDevice, display, layer,
+ region);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerBlendMode(Display display, Layer layer, int32_t mode)
+{
+ int32_t err = mDispatch.setLayerBlendMode(mDevice, display, layer, mode);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerColor(Display display, Layer layer,
+ IComposerClient::Color color)
+{
+ hwc_color_t hwc_color{color.r, color.g, color.b, color.a};
+ int32_t err = mDispatch.setLayerColor(mDevice, display, layer, hwc_color);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerCompositionType(Display display, Layer layer,
+ int32_t type)
+{
+ int32_t err = mDispatch.setLayerCompositionType(mDevice, display, layer,
+ type);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerDataspace(Display display, Layer layer,
+ int32_t dataspace)
+{
+ int32_t err = mDispatch.setLayerDataspace(mDevice, display, layer,
+ dataspace);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerDisplayFrame(Display display, Layer layer,
+ const hwc_rect_t& frame)
+{
+ int32_t err = mDispatch.setLayerDisplayFrame(mDevice, display, layer,
+ frame);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerPlaneAlpha(Display display, Layer layer, float alpha)
+{
+ int32_t err = mDispatch.setLayerPlaneAlpha(mDevice, display, layer,
+ alpha);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerSidebandStream(Display display, Layer layer,
+ buffer_handle_t stream)
+{
+ int32_t err = mDispatch.setLayerSidebandStream(mDevice, display, layer,
+ stream);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerSourceCrop(Display display, Layer layer,
+ const hwc_frect_t& crop)
+{
+ int32_t err = mDispatch.setLayerSourceCrop(mDevice, display, layer, crop);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerTransform(Display display, Layer layer,
+ int32_t transform)
+{
+ int32_t err = mDispatch.setLayerTransform(mDevice, display, layer,
+ transform);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible)
+{
+ hwc_region_t region = { visible.size(), visible.data() };
+ int32_t err = mDispatch.setLayerVisibleRegion(mDevice, display, layer,
+ region);
+ return static_cast<Error>(err);
+}
+
+Error HwcHal::setLayerZOrder(Display display, Layer layer, uint32_t z)
+{
+ int32_t err = mDispatch.setLayerZOrder(mDevice, display, layer, z);
+ return static_cast<Error>(err);
+}
+
+IComposer* HIDL_FETCH_IComposer(const char*)
+{
+ const hw_module_t* module = nullptr;
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get hwcomposer module");
+ return nullptr;
+ }
+
+ return new HwcHal(module);
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/default/Hwc.h b/graphics/composer/2.1/default/Hwc.h
new file mode 100644
index 0000000..b45389a
--- /dev/null
+++ b/graphics/composer/2.1/default/Hwc.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
+
+#include <mutex>
+#include <memory>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+#include "ComposerBase.h"
+
+namespace android {
+ class HWC2On1Adapter;
+}
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Hdr;
+
+class ComposerClient;
+
+class HwcHal : public IComposer, public ComposerBase {
+public:
+ HwcHal(const hw_module_t* module);
+ virtual ~HwcHal();
+
+ bool hasCapability(Capability capability) const;
+
+ // IComposer interface
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+
+ // ComposerBase interface
+ void removeClient() override;
+ void enableCallback(bool enable) override;
+ uint32_t getMaxVirtualDisplayCount() override;
+ Error createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat* format, Display* outDisplay) override;
+ Error destroyVirtualDisplay(Display display) override;
+
+ Error createLayer(Display display, Layer* outLayer) override;
+ Error destroyLayer(Display display, Layer layer) override;
+
+ Error getActiveConfig(Display display, Config* outConfig) override;
+ Error getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override;
+ Error getColorModes(Display display,
+ hidl_vec<ColorMode>* outModes) override;
+ Error getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) override;
+ Error getDisplayConfigs(Display display,
+ hidl_vec<Config>* outConfigs) override;
+ Error getDisplayName(Display display, hidl_string* outName) override;
+ Error getDisplayType(Display display,
+ IComposerClient::DisplayType* outType) override;
+ Error getDozeSupport(Display display, bool* outSupport) override;
+ Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) override;
+
+ Error setActiveConfig(Display display, Config config) override;
+ Error setColorMode(Display display, ColorMode mode) override;
+ Error setPowerMode(Display display,
+ IComposerClient::PowerMode mode) override;
+ Error setVsyncEnabled(Display display,
+ IComposerClient::Vsync enabled) override;
+
+ Error setColorTransform(Display display, const float* matrix,
+ int32_t hint) override;
+ Error setClientTarget(Display display, buffer_handle_t target,
+ int32_t acquireFence, int32_t dataspace,
+ const std::vector<hwc_rect_t>& damage) override;
+ Error setOutputBuffer(Display display, buffer_handle_t buffer,
+ int32_t releaseFence) override;
+ Error validateDisplay(Display display,
+ std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override;
+ Error acceptDisplayChanges(Display display) override;
+ Error presentDisplay(Display display, int32_t* outPresentFence,
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override;
+
+ Error setLayerCursorPosition(Display display, Layer layer,
+ int32_t x, int32_t y) override;
+ Error setLayerBuffer(Display display, Layer layer,
+ buffer_handle_t buffer, int32_t acquireFence) override;
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) override;
+ Error setLayerBlendMode(Display display, Layer layer,
+ int32_t mode) override;
+ Error setLayerColor(Display display, Layer layer,
+ IComposerClient::Color color) override;
+ Error setLayerCompositionType(Display display, Layer layer,
+ int32_t type) override;
+ Error setLayerDataspace(Display display, Layer layer,
+ int32_t dataspace) override;
+ Error setLayerDisplayFrame(Display display, Layer layer,
+ const hwc_rect_t& frame) override;
+ Error setLayerPlaneAlpha(Display display, Layer layer,
+ float alpha) override;
+ Error setLayerSidebandStream(Display display, Layer layer,
+ buffer_handle_t stream) override;
+ Error setLayerSourceCrop(Display display, Layer layer,
+ const hwc_frect_t& crop) override;
+ Error setLayerTransform(Display display, Layer layer,
+ int32_t transform) override;
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) override;
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+private:
+ void initCapabilities();
+
+ template<typename T>
+ void initDispatch(hwc2_function_descriptor_t desc, T* outPfn);
+ void initDispatch();
+
+ sp<ComposerClient> getClient();
+
+ static void hotplugHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connected);
+ static void refreshHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display);
+ static void vsyncHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp);
+
+ hwc2_device_t* mDevice;
+
+ std::unordered_set<Capability> mCapabilities;
+
+ struct {
+ HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges;
+ HWC2_PFN_CREATE_LAYER createLayer;
+ HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay;
+ HWC2_PFN_DESTROY_LAYER destroyLayer;
+ HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay;
+ HWC2_PFN_DUMP dump;
+ HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig;
+ HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes;
+ HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport;
+ HWC2_PFN_GET_COLOR_MODES getColorModes;
+ HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute;
+ HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs;
+ HWC2_PFN_GET_DISPLAY_NAME getDisplayName;
+ HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests;
+ HWC2_PFN_GET_DISPLAY_TYPE getDisplayType;
+ HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport;
+ HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities;
+ HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount;
+ HWC2_PFN_GET_RELEASE_FENCES getReleaseFences;
+ HWC2_PFN_PRESENT_DISPLAY presentDisplay;
+ HWC2_PFN_REGISTER_CALLBACK registerCallback;
+ HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig;
+ HWC2_PFN_SET_CLIENT_TARGET setClientTarget;
+ HWC2_PFN_SET_COLOR_MODE setColorMode;
+ HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform;
+ HWC2_PFN_SET_CURSOR_POSITION setCursorPosition;
+ HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode;
+ HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer;
+ HWC2_PFN_SET_LAYER_COLOR setLayerColor;
+ HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType;
+ HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace;
+ HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame;
+ HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha;
+ HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream;
+ HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop;
+ HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage;
+ HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform;
+ HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion;
+ HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder;
+ HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer;
+ HWC2_PFN_SET_POWER_MODE setPowerMode;
+ HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled;
+ HWC2_PFN_VALIDATE_DISPLAY validateDisplay;
+ } mDispatch;
+
+ std::mutex mClientMutex;
+ wp<ComposerClient> mClient;
+
+ // If the HWC implementation version is < 2.0, use an adapter to interface
+ // between HWC 2.0 <-> HWC 1.X.
+ std::unique_ptr<HWC2On1Adapter> mAdapter;
+};
+
+extern "C" IComposer* HIDL_FETCH_IComposer(const char* name);
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
diff --git a/graphics/composer/2.1/default/IComposerCommandBuffer.h b/graphics/composer/2.1/default/IComposerCommandBuffer.h
new file mode 100644
index 0000000..fb78ef8
--- /dev/null
+++ b/graphics/composer/2.1/default/IComposerCommandBuffer.h
@@ -0,0 +1,849 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
+
+#ifndef LOG_TAG
+#warn "IComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <log/log.h>
+#include <sync/sync.h>
+#include <fmq/MessageQueue.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::MessageQueue;
+
+using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase {
+public:
+ CommandWriterBase(uint32_t initialMaxSize)
+ : mDataMaxSize(initialMaxSize)
+ {
+ mData = std::make_unique<uint32_t[]>(mDataMaxSize);
+ reset();
+ }
+
+ virtual ~CommandWriterBase()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ mDataWritten = 0;
+ mCommandEnd = 0;
+
+ // handles in mDataHandles are owned by the caller
+ mDataHandles.clear();
+
+ // handles in mTemporaryHandles are owned by the writer
+ for (auto handle : mTemporaryHandles) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ mTemporaryHandles.clear();
+ }
+
+ IComposerClient::Command getCommand(uint32_t offset)
+ {
+ uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
+ return static_cast<IComposerClient::Command>(val &
+ static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK));
+ }
+
+ bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength,
+ hidl_vec<hidl_handle>* outCommandHandles)
+ {
+ // write data to queue, optionally resizing it
+ if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
+ if (!mQueue->write(mData.get(), mDataWritten)) {
+ ALOGE("failed to write commands to message queue");
+ return false;
+ }
+
+ *outQueueChanged = false;
+ } else {
+ auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
+ if (!newQueue->isValid() ||
+ !newQueue->write(mData.get(), mDataWritten)) {
+ ALOGE("failed to prepare a new message queue ");
+ return false;
+ }
+
+ mQueue = std::move(newQueue);
+ *outQueueChanged = true;
+ }
+
+ *outCommandLength = mDataWritten;
+ outCommandHandles->setToExternal(
+ const_cast<hidl_handle*>(mDataHandles.data()),
+ mDataHandles.size());
+
+ return true;
+ }
+
+ const MQDescriptorSync<uint32_t>* getMQDescriptor() const
+ {
+ return (mQueue) ? mQueue->getDesc() : nullptr;
+ }
+
+ static constexpr uint16_t kSelectDisplayLength = 2;
+ void selectDisplay(Display display)
+ {
+ beginCommand(IComposerClient::Command::SELECT_DISPLAY,
+ kSelectDisplayLength);
+ write64(display);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSelectLayerLength = 2;
+ void selectLayer(Layer layer)
+ {
+ beginCommand(IComposerClient::Command::SELECT_LAYER,
+ kSelectLayerLength);
+ write64(layer);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetErrorLength = 2;
+ void setError(uint32_t location, Error error)
+ {
+ beginCommand(IComposerClient::Command::SET_ERROR, kSetErrorLength);
+ write(location);
+ writeSigned(static_cast<int32_t>(error));
+ endCommand();
+ }
+
+ void setChangedCompositionTypes(const std::vector<Layer>& layers,
+ const std::vector<IComposerClient::Composition>& types)
+ {
+ size_t totalLayers = std::min(layers.size(), types.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count = std::min(totalLayers - currentLayer,
+ static_cast<size_t>(kMaxLength) / 3);
+
+ beginCommand(
+ IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES,
+ count * 3);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ writeSigned(static_cast<int32_t>(types[currentLayer + i]));
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ void setDisplayRequests(uint32_t displayRequestMask,
+ const std::vector<Layer>& layers,
+ const std::vector<uint32_t>& layerRequestMasks)
+ {
+ size_t totalLayers = std::min(layers.size(),
+ layerRequestMasks.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count = std::min(totalLayers - currentLayer,
+ static_cast<size_t>(kMaxLength - 1) / 3);
+
+ beginCommand(IComposerClient::Command::SET_DISPLAY_REQUESTS,
+ 1 + count * 3);
+ write(displayRequestMask);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ static constexpr uint16_t kSetPresentFenceLength = 1;
+ void setPresentFence(int presentFence)
+ {
+ beginCommand(IComposerClient::Command::SET_PRESENT_FENCE,
+ kSetPresentFenceLength);
+ writeFence(presentFence);
+ endCommand();
+ }
+
+ void setReleaseFences(const std::vector<Layer>& layers,
+ const std::vector<int>& releaseFences)
+ {
+ size_t totalLayers = std::min(layers.size(), releaseFences.size());
+ size_t currentLayer = 0;
+
+ while (currentLayer < totalLayers) {
+ size_t count = std::min(totalLayers - currentLayer,
+ static_cast<size_t>(kMaxLength) / 3);
+
+ beginCommand(IComposerClient::Command::SET_RELEASE_FENCES,
+ count * 3);
+ for (size_t i = 0; i < count; i++) {
+ write64(layers[currentLayer + i]);
+ writeFence(releaseFences[currentLayer + i]);
+ }
+ endCommand();
+
+ currentLayer += count;
+ }
+ }
+
+ static constexpr uint16_t kSetColorTransformLength = 17;
+ void setColorTransform(const float* matrix, ColorTransform hint)
+ {
+ beginCommand(IComposerClient::Command::SET_COLOR_TRANSFORM,
+ kSetColorTransformLength);
+ for (int i = 0; i < 16; i++) {
+ writeFloat(matrix[i]);
+ }
+ writeSigned(static_cast<int32_t>(hint));
+ endCommand();
+ }
+
+ void setClientTarget(uint32_t slot, const native_handle_t* target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposerClient::Rect>& damage)
+ {
+ bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
+ size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
+
+ beginCommand(IComposerClient::Command::SET_CLIENT_TARGET, length);
+ write(slot);
+ writeHandle(target, true);
+ writeFence(acquireFence);
+ writeSigned(static_cast<int32_t>(dataspace));
+ // When there are too many rectangles in the damage region and doWrite
+ // is false, we write no rectangle at all which means the entire
+ // client target is damaged.
+ if (doWrite) {
+ writeRegion(damage);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetOutputBufferLength = 3;
+ void setOutputBuffer(uint32_t slot, const native_handle_t* buffer,
+ int releaseFence)
+ {
+ beginCommand(IComposerClient::Command::SET_OUTPUT_BUFFER,
+ kSetOutputBufferLength);
+ write(slot);
+ writeHandle(buffer, true);
+ writeFence(releaseFence);
+ endCommand();
+ }
+
+ static constexpr uint16_t kValidateDisplayLength = 0;
+ void validateDisplay()
+ {
+ beginCommand(IComposerClient::Command::VALIDATE_DISPLAY,
+ kValidateDisplayLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kAcceptDisplayChangesLength = 0;
+ void acceptDisplayChanges()
+ {
+ beginCommand(IComposerClient::Command::ACCEPT_DISPLAY_CHANGES,
+ kAcceptDisplayChangesLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kPresentDisplayLength = 0;
+ void presentDisplay()
+ {
+ beginCommand(IComposerClient::Command::PRESENT_DISPLAY,
+ kPresentDisplayLength);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerCursorPositionLength = 2;
+ void setLayerCursorPosition(int32_t x, int32_t y)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_CURSOR_POSITION,
+ kSetLayerCursorPositionLength);
+ writeSigned(x);
+ writeSigned(y);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerBufferLength = 3;
+ void setLayerBuffer(uint32_t slot, const native_handle_t* buffer,
+ int acquireFence)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_BUFFER,
+ kSetLayerBufferLength);
+ write(slot);
+ writeHandle(buffer, true);
+ writeFence(acquireFence);
+ endCommand();
+ }
+
+ void setLayerSurfaceDamage(
+ const std::vector<IComposerClient::Rect>& damage)
+ {
+ bool doWrite = (damage.size() <= kMaxLength / 4);
+ size_t length = (doWrite) ? damage.size() * 4 : 0;
+
+ beginCommand(IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE,
+ length);
+ // When there are too many rectangles in the damage region and doWrite
+ // is false, we write no rectangle at all which means the entire
+ // layer is damaged.
+ if (doWrite) {
+ writeRegion(damage);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerBlendModeLength = 1;
+ void setLayerBlendMode(IComposerClient::BlendMode mode)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_BLEND_MODE,
+ kSetLayerBlendModeLength);
+ writeSigned(static_cast<int32_t>(mode));
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerColorLength = 1;
+ void setLayerColor(IComposerClient::Color color)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_COLOR,
+ kSetLayerColorLength);
+ writeColor(color);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
+ void setLayerCompositionType(IComposerClient::Composition type)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE,
+ kSetLayerCompositionTypeLength);
+ writeSigned(static_cast<int32_t>(type));
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerDataspaceLength = 1;
+ void setLayerDataspace(Dataspace dataspace)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_DATASPACE,
+ kSetLayerDataspaceLength);
+ writeSigned(static_cast<int32_t>(dataspace));
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
+ void setLayerDisplayFrame(const IComposerClient::Rect& frame)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_DISPLAY_FRAME,
+ kSetLayerDisplayFrameLength);
+ writeRect(frame);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
+ void setLayerPlaneAlpha(float alpha)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_PLANE_ALPHA,
+ kSetLayerPlaneAlphaLength);
+ writeFloat(alpha);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
+ void setLayerSidebandStream(const native_handle_t* stream)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM,
+ kSetLayerSidebandStreamLength);
+ writeHandle(stream);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerSourceCropLength = 4;
+ void setLayerSourceCrop(const IComposerClient::FRect& crop)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_SOURCE_CROP,
+ kSetLayerSourceCropLength);
+ writeFRect(crop);
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerTransformLength = 1;
+ void setLayerTransform(Transform transform)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_TRANSFORM,
+ kSetLayerTransformLength);
+ writeSigned(static_cast<int32_t>(transform));
+ endCommand();
+ }
+
+ void setLayerVisibleRegion(
+ const std::vector<IComposerClient::Rect>& visible)
+ {
+ bool doWrite = (visible.size() <= kMaxLength / 4);
+ size_t length = (doWrite) ? visible.size() * 4 : 0;
+
+ beginCommand(IComposerClient::Command::SET_LAYER_VISIBLE_REGION,
+ length);
+ // When there are too many rectangles in the visible region and
+ // doWrite is false, we write no rectangle at all which means the
+ // entire layer is visible.
+ if (doWrite) {
+ writeRegion(visible);
+ }
+ endCommand();
+ }
+
+ static constexpr uint16_t kSetLayerZOrderLength = 1;
+ void setLayerZOrder(uint32_t z)
+ {
+ beginCommand(IComposerClient::Command::SET_LAYER_Z_ORDER,
+ kSetLayerZOrderLength);
+ write(z);
+ endCommand();
+ }
+
+protected:
+ void beginCommand(IComposerClient::Command command, uint16_t length)
+ {
+ if (mCommandEnd) {
+ LOG_FATAL("endCommand was not called before command 0x%x",
+ command);
+ }
+
+ growData(1 + length);
+ write(static_cast<uint32_t>(command) | length);
+
+ mCommandEnd = mDataWritten + length;
+ }
+
+ void endCommand()
+ {
+ if (!mCommandEnd) {
+ LOG_FATAL("beginCommand was not called");
+ } else if (mDataWritten > mCommandEnd) {
+ LOG_FATAL("too much data written");
+ mDataWritten = mCommandEnd;
+ } else if (mDataWritten < mCommandEnd) {
+ LOG_FATAL("too little data written");
+ while (mDataWritten < mCommandEnd) {
+ write(0);
+ }
+ }
+
+ mCommandEnd = 0;
+ }
+
+ void write(uint32_t val)
+ {
+ mData[mDataWritten++] = val;
+ }
+
+ void writeSigned(int32_t val)
+ {
+ memcpy(&mData[mDataWritten++], &val, sizeof(val));
+ }
+
+ void writeFloat(float val)
+ {
+ memcpy(&mData[mDataWritten++], &val, sizeof(val));
+ }
+
+ void write64(uint64_t val)
+ {
+ uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
+ uint32_t hi = static_cast<uint32_t>(val >> 32);
+ write(lo);
+ write(hi);
+ }
+
+ void writeRect(const IComposerClient::Rect& rect)
+ {
+ writeSigned(rect.left);
+ writeSigned(rect.top);
+ writeSigned(rect.right);
+ writeSigned(rect.bottom);
+ }
+
+ void writeRegion(const std::vector<IComposerClient::Rect>& region)
+ {
+ for (const auto& rect : region) {
+ writeRect(rect);
+ }
+ }
+
+ void writeFRect(const IComposerClient::FRect& rect)
+ {
+ writeFloat(rect.left);
+ writeFloat(rect.top);
+ writeFloat(rect.right);
+ writeFloat(rect.bottom);
+ }
+
+ void writeColor(const IComposerClient::Color& color)
+ {
+ write((color.r << 0) |
+ (color.g << 8) |
+ (color.b << 16) |
+ (color.a << 24));
+ }
+
+ // ownership of handle is not transferred
+ void writeHandle(const native_handle_t* handle, bool useCache)
+ {
+ if (!handle) {
+ writeSigned(static_cast<int32_t>((useCache) ?
+ IComposerClient::HandleIndex::CACHED :
+ IComposerClient::HandleIndex::EMPTY));
+ return;
+ }
+
+ mDataHandles.push_back(handle);
+ writeSigned(mDataHandles.size() - 1);
+ }
+
+ void writeHandle(const native_handle_t* handle)
+ {
+ writeHandle(handle, false);
+ }
+
+ // ownership of fence is transferred
+ void writeFence(int fence)
+ {
+ native_handle_t* handle = nullptr;
+ if (fence >= 0) {
+ handle = getTemporaryHandle(1, 0);
+ if (handle) {
+ handle->data[0] = fence;
+ } else {
+ ALOGW("failed to get temporary handle for fence %d", fence);
+ sync_wait(fence, -1);
+ close(fence);
+ }
+ }
+
+ writeHandle(handle);
+ }
+
+ native_handle_t* getTemporaryHandle(int numFds, int numInts)
+ {
+ native_handle_t* handle = native_handle_create(numFds, numInts);
+ if (handle) {
+ mTemporaryHandles.push_back(handle);
+ }
+ return handle;
+ }
+
+ static constexpr uint16_t kMaxLength =
+ std::numeric_limits<uint16_t>::max();
+
+private:
+ void growData(uint32_t grow)
+ {
+ uint32_t newWritten = mDataWritten + grow;
+ if (newWritten < mDataWritten) {
+ LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32
+ ", growing by %" PRIu32, mDataWritten, grow);
+ }
+
+ if (newWritten <= mDataMaxSize) {
+ return;
+ }
+
+ uint32_t newMaxSize = mDataMaxSize << 1;
+ if (newMaxSize < newWritten) {
+ newMaxSize = newWritten;
+ }
+
+ auto newData = std::make_unique<uint32_t[]>(newMaxSize);
+ std::copy_n(mData.get(), mDataWritten, newData.get());
+ mDataMaxSize = newMaxSize;
+ mData = std::move(newData);
+ }
+
+ uint32_t mDataMaxSize;
+ std::unique_ptr<uint32_t[]> mData;
+
+ uint32_t mDataWritten;
+ // end offset of the current command
+ uint32_t mCommandEnd;
+
+ std::vector<hidl_handle> mDataHandles;
+ std::vector<native_handle_t *> mTemporaryHandles;
+
+ std::unique_ptr<CommandQueueType> mQueue;
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase {
+public:
+ CommandReaderBase() : mDataMaxSize(0)
+ {
+ reset();
+ }
+
+ bool setMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor)
+ {
+ mQueue = std::make_unique<CommandQueueType>(descriptor, false);
+ if (mQueue->isValid()) {
+ return true;
+ } else {
+ mQueue = nullptr;
+ return false;
+ }
+ }
+
+ bool readQueue(uint32_t commandLength,
+ const hidl_vec<hidl_handle>& commandHandles)
+ {
+ if (!mQueue) {
+ return false;
+ }
+
+ auto quantumCount = mQueue->getQuantumCount();
+ if (mDataMaxSize < quantumCount) {
+ mDataMaxSize = quantumCount;
+ mData = std::make_unique<uint32_t[]>(mDataMaxSize);
+ }
+
+ if (commandLength > mDataMaxSize ||
+ !mQueue->read(mData.get(), commandLength)) {
+ ALOGE("failed to read commands from message queue");
+ return false;
+ }
+
+ mDataSize = commandLength;
+ mDataRead = 0;
+ mCommandBegin = 0;
+ mCommandEnd = 0;
+ mDataHandles.setToExternal(
+ const_cast<hidl_handle*>(commandHandles.data()),
+ commandHandles.size());
+
+ return true;
+ }
+
+ void reset()
+ {
+ mDataSize = 0;
+ mDataRead = 0;
+ mCommandBegin = 0;
+ mCommandEnd = 0;
+ mDataHandles.setToExternal(nullptr, 0);
+ }
+
+protected:
+ bool isEmpty() const
+ {
+ return (mDataRead >= mDataSize);
+ }
+
+ bool beginCommand(IComposerClient::Command* outCommand,
+ uint16_t* outLength)
+ {
+ if (mCommandEnd) {
+ LOG_FATAL("endCommand was not called for last command");
+ }
+
+ constexpr uint32_t opcode_mask =
+ static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK);
+ constexpr uint32_t length_mask =
+ static_cast<uint32_t>(IComposerClient::Command::LENGTH_MASK);
+
+ uint32_t val = read();
+ *outCommand = static_cast<IComposerClient::Command>(
+ val & opcode_mask);
+ *outLength = static_cast<uint16_t>(val & length_mask);
+
+ if (mDataRead + *outLength > mDataSize) {
+ ALOGE("command 0x%x has invalid command length %" PRIu16,
+ *outCommand, *outLength);
+ // undo the read() above
+ mDataRead--;
+ return false;
+ }
+
+ mCommandEnd = mDataRead + *outLength;
+
+ return true;
+ }
+
+ void endCommand()
+ {
+ if (!mCommandEnd) {
+ LOG_FATAL("beginCommand was not called");
+ } else if (mDataRead > mCommandEnd) {
+ LOG_FATAL("too much data read");
+ mDataRead = mCommandEnd;
+ } else if (mDataRead < mCommandEnd) {
+ LOG_FATAL("too little data read");
+ mDataRead = mCommandEnd;
+ }
+
+ mCommandBegin = mCommandEnd;
+ mCommandEnd = 0;
+ }
+
+ uint32_t getCommandLoc() const
+ {
+ return mCommandBegin;
+ }
+
+ uint32_t read()
+ {
+ return mData[mDataRead++];
+ }
+
+ int32_t readSigned()
+ {
+ int32_t val;
+ memcpy(&val, &mData[mDataRead++], sizeof(val));
+ return val;
+ }
+
+ float readFloat()
+ {
+ float val;
+ memcpy(&val, &mData[mDataRead++], sizeof(val));
+ return val;
+ }
+
+ uint64_t read64()
+ {
+ uint32_t lo = read();
+ uint32_t hi = read();
+ return (static_cast<uint64_t>(hi) << 32) | lo;
+ }
+
+ IComposerClient::Color readColor()
+ {
+ uint32_t val = read();
+ return IComposerClient::Color{
+ static_cast<uint8_t>((val >> 0) & 0xff),
+ static_cast<uint8_t>((val >> 8) & 0xff),
+ static_cast<uint8_t>((val >> 16) & 0xff),
+ static_cast<uint8_t>((val >> 24) & 0xff),
+ };
+ }
+
+ // ownership of handle is not transferred
+ const native_handle_t* readHandle(bool* outUseCache)
+ {
+ const native_handle_t* handle = nullptr;
+
+ int32_t index = readSigned();
+ switch (index) {
+ case static_cast<int32_t>(IComposerClient::HandleIndex::EMPTY):
+ *outUseCache = false;
+ break;
+ case static_cast<int32_t>(IComposerClient::HandleIndex::CACHED):
+ *outUseCache = true;
+ break;
+ default:
+ if (static_cast<size_t>(index) < mDataHandles.size()) {
+ handle = mDataHandles[index].getNativeHandle();
+ } else {
+ ALOGE("invalid handle index %zu", static_cast<size_t>(index));
+ }
+ *outUseCache = false;
+ break;
+ }
+
+ return handle;
+ }
+
+ const native_handle_t* readHandle()
+ {
+ bool useCache;
+ return readHandle(&useCache);
+ }
+
+ // ownership of fence is transferred
+ int readFence()
+ {
+ auto handle = readHandle();
+ if (!handle || handle->numFds == 0) {
+ return -1;
+ }
+
+ if (handle->numFds != 1) {
+ ALOGE("invalid fence handle with %d fds", handle->numFds);
+ return -1;
+ }
+
+ int fd = dup(handle->data[0]);
+ if (fd < 0) {
+ ALOGW("failed to dup fence %d", handle->data[0]);
+ sync_wait(handle->data[0], -1);
+ fd = -1;
+ }
+
+ return fd;
+ }
+
+private:
+ std::unique_ptr<CommandQueueType> mQueue;
+ uint32_t mDataMaxSize;
+ std::unique_ptr<uint32_t[]> mData;
+
+ uint32_t mDataSize;
+ uint32_t mDataRead;
+
+ // begin/end offsets of the current command
+ uint32_t mCommandBegin;
+ uint32_t mCommandEnd;
+
+ hidl_vec<hidl_handle> mDataHandles;
+};
+
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
new file mode 100644
index 0000000..4f01bd9
--- /dev/null
+++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -0,0 +1,6 @@
+service hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
+ class hal
+ user system
+ group graphics drmrpc readproc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
diff --git a/graphics/composer/2.1/default/service.cpp b/graphics/composer/2.1/default/service.cpp
new file mode 100644
index 0000000..712dac1
--- /dev/null
+++ b/graphics/composer/2.1/default/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.graphics.composer@2.1-service"
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+
+#include <binder/ProcessState.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::graphics::composer::V2_1::IComposer;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ // the conventional HAL might start binder services
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ android::ProcessState::self()->startThreadPool();
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK,
+ ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ return defaultPassthroughServiceImplementation<IComposer>();
+}
diff --git a/graphics/composer/2.1/types.hal b/graphics/composer/2.1/types.hal
new file mode 100644
index 0000000..e54031e
--- /dev/null
+++ b/graphics/composer/2.1/types.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.graphics.composer@2.1;
+
+/* Return codes from all functions. */
+enum Error : int32_t {
+ NONE = 0, /* no error */
+ BAD_CONFIG = 1, /* invalid Config */
+ BAD_DISPLAY = 2, /* invalid Display */
+ BAD_LAYER = 3, /* invalid Layer */
+ BAD_PARAMETER = 4, /* invalid width, height, etc. */
+ /* 5 is reserved */
+ NO_RESOURCES = 6, /* temporary failure due to resource contention */
+ NOT_VALIDATED = 7, /* validateDisplay has not been called */
+ UNSUPPORTED = 8, /* permanent failure */
+};
+
+typedef uint32_t Config;
+typedef uint64_t Display;
+typedef uint64_t Layer;
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..8e1f925
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_library_static {
+ name: "libVtsHalGraphicsComposerTestUtils",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsComposerTestUtils.cpp"],
+ shared_libs: ["android.hardware.graphics.composer@2.1"],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_test {
+ name: "VtsHalGraphicsComposerV2_1TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libnativehelper",
+ "libsync",
+ "libutils",
+ ],
+ static_libs: [
+ "libhwcomposer-command-buffer",
+ "libVtsHalGraphicsAllocatorTestUtils",
+ "libVtsHalGraphicsComposerTestUtils",
+ "libVtsHalGraphicsMapperTestUtils",
+ "VtsHalHidlTargetTestBase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
new file mode 100644
index 0000000..33cf84c
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "VtsHalGraphicsComposerTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace tests {
+
+Composer::Composer() { init(); }
+
+void Composer::init() {
+ mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>();
+ ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
+
+ std::vector<IComposer::Capability> capabilities = getCapabilities();
+ mCapabilities.insert(capabilities.begin(), capabilities.end());
+}
+
+sp<IComposer> Composer::getRaw() const { return mComposer; }
+
+bool Composer::hasCapability(IComposer::Capability capability) const {
+ return mCapabilities.count(capability) > 0;
+}
+
+std::vector<IComposer::Capability> Composer::getCapabilities() {
+ std::vector<IComposer::Capability> capabilities;
+ mComposer->getCapabilities(
+ [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+
+ return capabilities;
+}
+
+std::string Composer::dumpDebugInfo() {
+ std::string debugInfo;
+ mComposer->dumpDebugInfo(
+ [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+ std::unique_ptr<ComposerClient> client;
+ mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<ComposerClient>(tmpClient);
+ });
+
+ return client;
+}
+
+ComposerClient::ComposerClient(const sp<IComposerClient>& client)
+ : mClient(client) {}
+
+ComposerClient::~ComposerClient() {
+ for (auto it : mDisplayResources) {
+ Display display = it.first;
+ DisplayResource& resource = it.second;
+
+ for (auto layer : resource.layers) {
+ EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer))
+ << "failed to destroy layer " << layer;
+ }
+
+ if (resource.isVirtual) {
+ EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display))
+ << "failed to destroy virtual display " << display;
+ }
+ }
+ mDisplayResources.clear();
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const { return mClient; }
+
+void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) {
+ mClient->registerCallback(callback);
+}
+
+uint32_t ComposerClient::getMaxVirtualDisplayCount() {
+ return mClient->getMaxVirtualDisplayCount();
+}
+
+Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint,
+ uint32_t outputBufferSlotCount,
+ PixelFormat* outFormat) {
+ Display display = 0;
+ mClient->createVirtualDisplay(
+ width, height, formatHint, outputBufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
+ display = tmpDisplay;
+ *outFormat = tmpFormat;
+
+ ASSERT_TRUE(
+ mDisplayResources.insert({display, DisplayResource(true)}).second)
+ << "duplicated virtual display id " << display;
+ });
+
+ return display;
+}
+
+void ComposerClient::destroyVirtualDisplay(Display display) {
+ Error error = mClient->destroyVirtualDisplay(display);
+ ASSERT_EQ(Error::NONE, error)
+ << "failed to destroy virtual display " << display;
+
+ mDisplayResources.erase(display);
+}
+
+Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) {
+ Layer layer = 0;
+ mClient->createLayer(
+ display, bufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpLayer) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer";
+ layer = tmpLayer;
+
+ auto resourceIt = mDisplayResources.find(display);
+ if (resourceIt == mDisplayResources.end()) {
+ resourceIt =
+ mDisplayResources.insert({display, DisplayResource(false)}).first;
+ }
+
+ ASSERT_TRUE(resourceIt->second.layers.insert(layer).second)
+ << "duplicated layer id " << layer;
+ });
+
+ return layer;
+}
+
+void ComposerClient::destroyLayer(Display display, Layer layer) {
+ Error error = mClient->destroyLayer(display, layer);
+ ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer;
+
+ auto resourceIt = mDisplayResources.find(display);
+ ASSERT_NE(mDisplayResources.end(), resourceIt);
+ resourceIt->second.layers.erase(layer);
+}
+
+Config ComposerClient::getActiveConfig(Display display) {
+ Config config = 0;
+ mClient->getActiveConfig(
+ display, [&](const auto& tmpError, const auto& tmpConfig) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config";
+ config = tmpConfig;
+ });
+
+ return config;
+}
+
+bool ComposerClient::getClientTargetSupport(Display display, uint32_t width,
+ uint32_t height, PixelFormat format,
+ Dataspace dataspace) {
+ Error error = mClient->getClientTargetSupport(display, width, height, format,
+ dataspace);
+ return error == Error::NONE;
+}
+
+std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
+ std::vector<ColorMode> modes;
+ mClient->getColorModes(
+ display, [&](const auto& tmpError, const auto& tmpMode) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode";
+ modes = tmpMode;
+ });
+
+ return modes;
+}
+
+int32_t ComposerClient::getDisplayAttribute(
+ Display display, Config config, IComposerClient::Attribute attribute) {
+ int32_t value = 0;
+ mClient->getDisplayAttribute(display, config, attribute,
+ [&](const auto& tmpError, const auto& tmpValue) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get display attribute";
+ value = tmpValue;
+ });
+
+ return value;
+}
+
+std::vector<Config> ComposerClient::getDisplayConfigs(Display display) {
+ std::vector<Config> configs;
+ mClient->getDisplayConfigs(
+ display, [&](const auto& tmpError, const auto& tmpConfigs) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs";
+ configs = tmpConfigs;
+ });
+
+ return configs;
+}
+
+std::string ComposerClient::getDisplayName(Display display) {
+ std::string name;
+ mClient->getDisplayName(
+ display, [&](const auto& tmpError, const auto& tmpName) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name";
+ name = tmpName.c_str();
+ });
+
+ return name;
+}
+
+IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) {
+ IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID;
+ mClient->getDisplayType(
+ display, [&](const auto& tmpError, const auto& tmpType) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type";
+ type = tmpType;
+ });
+
+ return type;
+}
+
+bool ComposerClient::getDozeSupport(Display display) {
+ bool support = false;
+ mClient->getDozeSupport(
+ display, [&](const auto& tmpError, const auto& tmpSupport) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support";
+ support = tmpSupport;
+ });
+
+ return support;
+}
+
+std::vector<Hdr> ComposerClient::getHdrCapabilities(
+ Display display, float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ std::vector<Hdr> types;
+ mClient->getHdrCapabilities(
+ display,
+ [&](const auto& tmpError, const auto& tmpTypes,
+ const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance,
+ const auto& tmpMinLuminance) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
+ types = tmpTypes;
+ *outMaxLuminance = tmpMaxLuminance;
+ *outMaxAverageLuminance = tmpMaxAverageLuminance;
+ *outMinLuminance = tmpMinLuminance;
+ });
+
+ return types;
+}
+
+void ComposerClient::setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount) {
+ Error error =
+ mClient->setClientTargetSlotCount(display, clientTargetSlotCount);
+ ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count";
+}
+
+void ComposerClient::setActiveConfig(Display display, Config config) {
+ Error error = mClient->setActiveConfig(display, config);
+ ASSERT_EQ(Error::NONE, error) << "failed to set active config";
+}
+
+void ComposerClient::setColorMode(Display display, ColorMode mode) {
+ Error error = mClient->setColorMode(display, mode);
+ ASSERT_EQ(Error::NONE, error) << "failed to set color mode";
+}
+
+void ComposerClient::setPowerMode(Display display,
+ IComposerClient::PowerMode mode) {
+ Error error = mClient->setPowerMode(display, mode);
+ ASSERT_EQ(Error::NONE, error) << "failed to set power mode";
+}
+
+void ComposerClient::setVsyncEnabled(Display display, bool enabled) {
+ IComposerClient::Vsync vsync = (enabled) ? IComposerClient::Vsync::ENABLE
+ : IComposerClient::Vsync::DISABLE;
+ Error error = mClient->setVsyncEnabled(display, vsync);
+ ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode";
+}
+
+} // namespace tests
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
new file mode 100644
index 0000000..4b57264
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_COMPOSER_UTILS
+#define VTS_HAL_GRAPHICS_COMPOSER_UTILS
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer {
+ public:
+ Composer();
+
+ sp<IComposer> getRaw() const;
+
+ // Returns true when the composer supports the specified capability.
+ bool hasCapability(IComposer::Capability capability) const;
+
+ std::vector<IComposer::Capability> getCapabilities();
+ std::string dumpDebugInfo();
+ std::unique_ptr<ComposerClient> createClient();
+
+ private:
+ void init();
+
+ sp<IComposer> mComposer;
+ std::unordered_set<IComposer::Capability> mCapabilities;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient {
+ public:
+ ComposerClient(const sp<IComposerClient>& client);
+ ~ComposerClient();
+
+ sp<IComposerClient> getRaw() const;
+
+ void registerCallback(const sp<IComposerCallback>& callback);
+ uint32_t getMaxVirtualDisplayCount();
+
+ Display createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint,
+ uint32_t outputBufferSlotCount,
+ PixelFormat* outFormat);
+ void destroyVirtualDisplay(Display display);
+
+ Layer createLayer(Display display, uint32_t bufferSlotCount);
+ void destroyLayer(Display display, Layer layer);
+
+ Config getActiveConfig(Display display);
+ bool getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace);
+ std::vector<ColorMode> getColorModes(Display display);
+ int32_t getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute);
+ std::vector<Config> getDisplayConfigs(Display display);
+ std::string getDisplayName(Display display);
+ IComposerClient::DisplayType getDisplayType(Display display);
+ bool getDozeSupport(Display display);
+ std::vector<Hdr> getHdrCapabilities(Display display, float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance);
+
+ void setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount);
+ void setActiveConfig(Display display, Config config);
+ void setColorMode(Display display, ColorMode mode);
+ void setPowerMode(Display display, IComposerClient::PowerMode mode);
+ void setVsyncEnabled(Display display, bool enabled);
+
+ private:
+ sp<IComposerClient> mClient;
+
+ // Keep track of all virtual displays and layers. When a test fails with
+ // ASSERT_*, the destructor will clean up the resources for the test.
+ struct DisplayResource {
+ DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {}
+
+ bool isVirtual;
+ std::unordered_set<Layer> layers;
+ };
+ std::unordered_map<Display, DisplayResource> mDisplayResources;
+};
+
+} // namespace tests
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_GRAPHICS_COMPOSER_UTILS
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
new file mode 100644
index 0000000..0da3a33
--- /dev/null
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -0,0 +1,845 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_test"
+
+#include <IComposerCommandBuffer.h>
+#include <android-base/logging.h>
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+#include "VtsHalGraphicsComposerTestUtils.h"
+#include "VtsHalGraphicsMapperTestUtils.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::allocator::V2_0::Buffer;
+using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
+using android::hardware::graphics::allocator::V2_0::ConsumerUsage;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
+using android::hardware::graphics::allocator::V2_0::ProducerUsage;
+using android::hardware::graphics::allocator::V2_0::tests::Allocator;
+using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::tests::Mapper;
+using GrallocError = android::hardware::graphics::allocator::V2_0::Error;
+
+// IComposerCallback to be installed with IComposerClient::registerCallback.
+class GraphicsComposerCallback : public IComposerCallback {
+ public:
+ void setVsyncAllowed(bool allowed) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mVsyncAllowed = allowed;
+ }
+
+ std::vector<Display> getDisplays() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+ }
+
+ int getInvalidHotplugCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidHotplugCount;
+ }
+
+ int getInvalidRefreshCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidRefreshCount;
+ }
+
+ int getInvalidVsyncCount() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mInvalidVsyncCount;
+ }
+
+ private:
+ Return<void> onHotplug(Display display, Connection connection) override {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (connection == Connection::CONNECTED) {
+ if (!mDisplays.insert(display).second) {
+ mInvalidHotplugCount++;
+ }
+ } else if (connection == Connection::DISCONNECTED) {
+ if (!mDisplays.erase(display)) {
+ mInvalidHotplugCount++;
+ }
+ }
+
+ return Void();
+ }
+
+ Return<void> onRefresh(Display display) override {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mDisplays.count(display) == 0) {
+ mInvalidRefreshCount++;
+ }
+
+ return Void();
+ }
+
+ Return<void> onVsync(Display display, int64_t) override {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+ mInvalidVsyncCount++;
+ }
+
+ return Void();
+ }
+
+ mutable std::mutex mMutex;
+ // the set of all currently connected displays
+ std::unordered_set<Display> mDisplays;
+ // true only when vsync is enabled
+ bool mVsyncAllowed = false;
+
+ // track invalid callbacks
+ int mInvalidHotplugCount = 0;
+ int mInvalidRefreshCount = 0;
+ int mInvalidVsyncCount = 0;
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(mComposer = std::make_unique<Composer>());
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+ mComposerCallback = new GraphicsComposerCallback;
+ mComposerClient->registerCallback(mComposerCallback);
+
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
+ }
+
+ void TearDown() override {
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ }
+ }
+
+ // use the slot count usually set by SF
+ static constexpr uint32_t kBufferSlotCount = 64;
+
+ std::unique_ptr<Composer> mComposer;
+ std::unique_ptr<ComposerClient> mComposerClient;
+ sp<GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+
+ return displays[0];
+ }
+ }
+};
+
+/**
+ * Test IComposer::getCapabilities.
+ *
+ * Test that IComposer::getCapabilities returns no invalid capabilities.
+ */
+TEST_F(GraphicsComposerHidlTest, GetCapabilities) {
+ auto capabilities = mComposer->getCapabilities();
+ ASSERT_EQ(capabilities.end(),
+ std::find(capabilities.begin(), capabilities.end(),
+ IComposer::Capability::INVALID));
+}
+
+/**
+ * Test IComposer::dumpDebugInfo.
+ */
+TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { mComposer->dumpDebugInfo(); }
+
+/**
+ * Test IComposer::createClient.
+ *
+ * Test that IComposerClient is a singleton.
+ */
+TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) {
+ mComposer->getRaw()->createClient([&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::NO_RESOURCES, tmpError);
+ });
+}
+
+/**
+ * Test IComposerClient::createVirtualDisplay and
+ * IComposerClient::destroyVirtualDisplay.
+ *
+ * Test that virtual displays can be created and has the correct display type.
+ */
+TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) {
+ if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
+ GTEST_SUCCEED() << "no virtual display support";
+ return;
+ }
+
+ Display display;
+ PixelFormat format;
+ ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
+ 64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+ kBufferSlotCount, &format));
+
+ // test display type
+ IComposerClient::DisplayType type = mComposerClient->getDisplayType(display);
+ EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type);
+
+ mComposerClient->destroyVirtualDisplay(display);
+}
+
+/**
+ * Test IComposerClient::createLayer and IComposerClient::destroyLayer.
+ *
+ * Test that layers can be created and destroyed.
+ */
+TEST_F(GraphicsComposerHidlTest, CreateLayer) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mComposerClient->destroyLayer(mPrimaryDisplay, layer);
+}
+
+/**
+ * Test IComposerClient::getDisplayName.
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
+ mComposerClient->getDisplayName(mPrimaryDisplay);
+}
+
+/**
+ * Test IComposerClient::getDisplayType.
+ *
+ * Test that IComposerClient::getDisplayType returns the correct display type
+ * for the primary display.
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayType) {
+ ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
+ mComposerClient->getDisplayType(mPrimaryDisplay));
+}
+
+/**
+ * Test IComposerClient::getClientTargetSupport.
+ *
+ * Test that IComposerClient::getClientTargetSupport returns true for the
+ * required client targets.
+ */
+TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) {
+ std::vector<Config> configs =
+ mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ int32_t width = mComposerClient->getDisplayAttribute(
+ mPrimaryDisplay, config, IComposerClient::Attribute::WIDTH);
+ int32_t height = mComposerClient->getDisplayAttribute(
+ mPrimaryDisplay, config, IComposerClient::Attribute::HEIGHT);
+ ASSERT_LT(0, width);
+ ASSERT_LT(0, height);
+
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+
+ ASSERT_TRUE(mComposerClient->getClientTargetSupport(
+ mPrimaryDisplay, width, height, PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN));
+ }
+}
+
+/**
+ * Test IComposerClient::getDisplayAttribute.
+ *
+ * Test that IComposerClient::getDisplayAttribute succeeds for the required
+ * formats, and succeeds or fails correctly for optional attributes.
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) {
+ std::vector<Config> configs =
+ mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
+ IComposerClient::Attribute::WIDTH, IComposerClient::Attribute::HEIGHT,
+ IComposerClient::Attribute::VSYNC_PERIOD,
+ }};
+ for (auto attribute : requiredAttributes) {
+ mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, attribute);
+ }
+
+ const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
+ IComposerClient::Attribute::DPI_X, IComposerClient::Attribute::DPI_Y,
+ }};
+ for (auto attribute : optionalAttributes) {
+ mComposerClient->getRaw()->getDisplayAttribute(
+ mPrimaryDisplay, config, attribute,
+ [&](const auto& tmpError, const auto&) {
+ EXPECT_TRUE(tmpError == Error::NONE ||
+ tmpError == Error::UNSUPPORTED);
+ });
+ }
+ }
+}
+
+/**
+ * Test IComposerClient::getHdrCapabilities.
+ */
+TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) {
+ float maxLuminance;
+ float maxAverageLuminance;
+ float minLuminance;
+ mComposerClient->getHdrCapabilities(mPrimaryDisplay, &maxLuminance,
+ &maxAverageLuminance, &minLuminance);
+}
+
+/**
+ * Test IComposerClient::setClientTargetSlotCount.
+ */
+TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
+}
+
+/**
+ * Test IComposerClient::setActiveConfig.
+ *
+ * Test that IComposerClient::setActiveConfig succeeds for all display
+ * configs.
+ */
+TEST_F(GraphicsComposerHidlTest, SetActiveConfig) {
+ std::vector<Config> configs =
+ mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+ for (auto config : configs) {
+ mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+ ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
+ }
+}
+
+/**
+ * Test IComposerClient::setColorMode.
+ *
+ * Test that IComposerClient::setColorMode succeeds for all color modes.
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode) {
+ std::vector<ColorMode> modes =
+ mComposerClient->getColorModes(mPrimaryDisplay);
+ for (auto mode : modes) {
+ mComposerClient->setColorMode(mPrimaryDisplay, mode);
+ }
+}
+
+/**
+ * Test IComposerClient::setPowerMode.
+ *
+ * Test that IComposerClient::setPowerMode succeeds for all power modes.
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerMode) {
+ std::vector<IComposerClient::PowerMode> modes;
+ modes.push_back(IComposerClient::PowerMode::OFF);
+
+ if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+ modes.push_back(IComposerClient::PowerMode::DOZE);
+ modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+ }
+
+ // push ON last
+ modes.push_back(IComposerClient::PowerMode::ON);
+
+ for (auto mode : modes) {
+ mComposerClient->setPowerMode(mPrimaryDisplay, mode);
+ }
+}
+
+/**
+ * Test IComposerClient::setVsyncEnabled.
+ *
+ * Test that IComposerClient::setVsyncEnabled succeeds and there is no
+ * spurious vsync events.
+ */
+TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) {
+ mComposerCallback->setVsyncAllowed(true);
+
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
+ usleep(60 * 1000);
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+
+ mComposerCallback->setVsyncAllowed(false);
+}
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+ ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+ ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
+ ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<CommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+ }
+
+ const native_handle_t* allocate() {
+ IAllocatorClient::BufferDescriptorInfo info{};
+ info.width = 64;
+ info.height = 64;
+ info.layerCount = 1;
+ info.format = PixelFormat::RGBA_8888;
+ info.producerUsageMask = static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
+ info.consumerUsageMask = static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+
+ return mMapper->allocate(mAllocatorClient, info);
+ }
+
+ void execute() {
+ bool queueChanged = false;
+ uint32_t commandLength = 0;
+ hidl_vec<hidl_handle> commandHandles;
+ ASSERT_TRUE(
+ mWriter->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+ if (queueChanged) {
+ auto ret = mComposerClient->getRaw()->setInputCommandQueue(
+ *mWriter->getMQDescriptor());
+ ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+ return;
+ }
+
+ mComposerClient->getRaw()->executeCommands(
+ commandLength, commandHandles,
+ [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+ const auto& tmpOutLength, const auto& tmpOutHandles) {
+ ASSERT_EQ(Error::NONE, tmpError);
+
+ if (tmpOutQueueChanged) {
+ mComposerClient->getRaw()->getOutputCommandQueue(
+ [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ mReader->setMQDescriptor(tmpDescriptor);
+ });
+ }
+
+ ASSERT_TRUE(mReader->readQueue(tmpOutLength, tmpOutHandles));
+ mReader->parse();
+ });
+ }
+
+ // A command parser that checks that no error nor unexpected commands are
+ // returned.
+ class CommandReader : public CommandReaderBase {
+ public:
+ // Parse all commands in the return command queue. Call GTEST_FAIL() for
+ // unexpected errors or commands.
+ void parse() {
+ while (!isEmpty()) {
+ IComposerClient::Command command;
+ uint16_t length;
+ ASSERT_TRUE(beginCommand(&command, &length));
+
+ switch (command) {
+ case IComposerClient::Command::SET_ERROR: {
+ ASSERT_EQ(2, length);
+ auto loc = read();
+ auto err = readSigned();
+ GTEST_FAIL() << "unexpected error " << err << " at location "
+ << loc;
+ } break;
+ case IComposerClient::Command::SELECT_DISPLAY:
+ case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+ case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+ case IComposerClient::Command::SET_PRESENT_FENCE:
+ case IComposerClient::Command::SET_RELEASE_FENCES:
+ break;
+ default:
+ GTEST_FAIL() << "unexpected return command " << std::hex
+ << static_cast<int>(command);
+ break;
+ }
+
+ endCommand();
+ }
+ }
+ };
+
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<CommandReader> mReader;
+
+ private:
+ std::unique_ptr<Allocator> mAllocator;
+ std::unique_ptr<AllocatorClient> mAllocatorClient;
+ std::unique_ptr<Mapper> mMapper;
+};
+
+/**
+ * Test IComposerClient::Command::SET_COLOR_TRANSFORM.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
+ const std::array<float, 16> identity = {{
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ }};
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->setColorTransform(identity.data(), ColorTransform::IDENTITY);
+
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_CLIENT_TARGET.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
+ mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->setClientTarget(0, nullptr, -1, Dataspace::UNKNOWN,
+ std::vector<IComposerClient::Rect>());
+
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_OUTPUT_BUFFER.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
+ if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
+ GTEST_SUCCEED() << "no virtual display support";
+ return;
+ }
+
+ Display display;
+ PixelFormat format;
+ ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay(
+ 64, 64, PixelFormat::IMPLEMENTATION_DEFINED,
+ kBufferSlotCount, &format));
+
+ const native_handle_t* handle;
+ ASSERT_NO_FATAL_FAILURE(handle = allocate());
+
+ mWriter->selectDisplay(display);
+ mWriter->setOutputBuffer(0, handle, -1);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::VALIDATE_DISPLAY.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ mWriter->acceptDisplayChanges();
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::PRESENT_DISPLAY.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->validateDisplay();
+ mWriter->presentDisplay();
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCursorPosition(1, 1);
+ mWriter->setLayerCursorPosition(0, 0);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_BUFFER.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
+
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(0, handle, -1);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ IComposerClient::Rect empty{0, 0, 0, 0};
+ IComposerClient::Rect unit{0, 0, 1, 1};
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, empty));
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, unit));
+ mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>());
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_BLEND_MODE.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+ mWriter->setLayerBlendMode(IComposerClient::BlendMode::COVERAGE);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_COLOR.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerColor(IComposerClient::Color{0xff, 0xff, 0xff, 0xff});
+ mWriter->setLayerColor(IComposerClient::Color{0, 0, 0, 0});
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_DATASPACE.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDisplayFrame(IComposerClient::Rect{0, 0, 1, 1});
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerPlaneAlpha(0.0f);
+ mWriter->setLayerPlaneAlpha(1.0f);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
+ if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
+ GTEST_SUCCEED() << "no sideband stream support";
+ return;
+ }
+
+ auto handle = allocate();
+ ASSERT_NE(nullptr, handle);
+
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSidebandStream(handle);
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_SOURCE_CROP.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerSourceCrop(IComposerClient::FRect{0.0f, 0.0f, 1.0f, 1.0f});
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_TRANSFORM.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerTransform(static_cast<Transform>(0));
+ mWriter->setLayerTransform(Transform::FLIP_H);
+ mWriter->setLayerTransform(Transform::FLIP_V);
+ mWriter->setLayerTransform(Transform::ROT_90);
+ mWriter->setLayerTransform(Transform::ROT_180);
+ mWriter->setLayerTransform(Transform::ROT_270);
+ mWriter->setLayerTransform(
+ static_cast<Transform>(Transform::FLIP_H | Transform::ROT_90));
+ mWriter->setLayerTransform(
+ static_cast<Transform>(Transform::FLIP_V | Transform::ROT_90));
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ IComposerClient::Rect empty{0, 0, 0, 0};
+ IComposerClient::Rect unit{0, 0, 1, 1};
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, empty));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, unit));
+ mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>());
+ execute();
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_Z_ORDER.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerZOrder(10);
+ mWriter->setLayerZOrder(0);
+ execute();
+}
+
+} // namespace anonymous
+} // namespace tests
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+
+ return status;
+}
diff --git a/graphics/composer/Android.mk b/graphics/composer/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/composer/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp
new file mode 100644
index 0000000..b835b4a
--- /dev/null
+++ b/graphics/mapper/2.0/Android.bp
@@ -0,0 +1,66 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.mapper@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IMapper.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.mapper@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.mapper@2.0",
+ srcs: [
+ ":android.hardware.graphics.mapper@2.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/mapper/2.0/types.cpp",
+ "android/hardware/graphics/mapper/2.0/MapperAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.mapper@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.mapper@2.0",
+ srcs: [
+ ":android.hardware.graphics.mapper@2.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/mapper/2.0/types.h",
+ "android/hardware/graphics/mapper/2.0/IMapper.h",
+ "android/hardware/graphics/mapper/2.0/IHwMapper.h",
+ "android/hardware/graphics/mapper/2.0/BnHwMapper.h",
+ "android/hardware/graphics/mapper/2.0/BpHwMapper.h",
+ "android/hardware/graphics/mapper/2.0/BsMapper.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.mapper@2.0",
+ generated_sources: ["android.hardware.graphics.mapper@2.0_genc++"],
+ generated_headers: ["android.hardware.graphics.mapper@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.mapper@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/graphics/mapper/2.0/Android.mk b/graphics/mapper/2.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/mapper/2.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/IMapper.hal b/graphics/mapper/2.0/IMapper.hal
new file mode 100644
index 0000000..21a6dfa
--- /dev/null
+++ b/graphics/mapper/2.0/IMapper.hal
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2016 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.graphics.mapper@2.0;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+import android.hardware.graphics.allocator@2.0;
+
+interface IMapper {
+ struct Rect {
+ int32_t left;
+ int32_t top;
+ int32_t width;
+ int32_t height;
+ };
+
+ /*
+ * Adds a reference to the given buffer handle.
+ *
+ * A buffer handle received from a remote process or exported by
+ * IAllocator::exportHandle is unknown to the mapper. There is also no
+ * guarantee that the buffer's backing store will stay alive. This
+ * function must be called at least once in both cases to intrdouce the
+ * buffer handle to the mapper and to secure the backing store. It may
+ * also be called more than once to increase the reference count if two
+ * components in the same process want to interact with the buffer
+ * independently.
+ *
+ * @param bufferHandle is the buffer to which a reference must be added.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid
+ * NO_RESOURCES when it is not possible to add a
+ * reference to this buffer at this time
+ */
+ @entry
+ @callflow(next="*")
+ retain(handle bufferHandle) generates (Error error);
+
+ /*
+ * Removes a reference from the given buffer buffer.
+ *
+ * If no references remain, the buffer handle must be freed with
+ * native_handle_close/native_handle_delete by the mapper. When the last
+ * buffer handle referring to a particular backing store is freed, that
+ * backing store must also be freed.
+ *
+ * @param bufferHandle is the buffer from which a reference must be
+ * removed.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ */
+ @exit
+ release(handle bufferHandle) generates (Error error);
+
+ /*
+ * Gets the width and height of the buffer in pixels.
+ *
+ * See IAllocator::BufferDescriptorInfo for more information.
+ *
+ * @param bufferHandle is the buffer from which to get the dimensions.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return width is the width of the buffer in pixels.
+ * @return height is the height of the buffer in pixels.
+ */
+ @callflow(next="*")
+ getDimensions(handle bufferHandle)
+ generates (Error error,
+ uint32_t width,
+ uint32_t height);
+
+ /*
+ * Gets the format of the buffer.
+ *
+ * See IAllocator::BufferDescriptorInfo for more information.
+ *
+ * @param bufferHandle is the buffer from which to get format.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return format is the format of the buffer.
+ */
+ @callflow(next="*")
+ getFormat(handle bufferHandle)
+ generates (Error error,
+ PixelFormat format);
+
+ /*
+ * Gets the number of layers of the buffer.
+ *
+ * See IAllocator::BufferDescriptorInfo for more information.
+ *
+ * @param bufferHandle is the buffer from which to get format.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return layerCount is the number of layers of the buffer.
+ */
+ @callflow(next="*")
+ getLayerCount(handle bufferHandle)
+ generates (Error error,
+ uint32_t layerCount);
+
+ /*
+ * Gets the producer usage flags which were used to allocate this buffer.
+ *
+ * See IAllocator::BufferDescriptorInfo for more information.
+ *
+ * @param bufferHandle is the buffer from which to get the producer usage
+ * flags.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return usageMask contains the producer usage flags of the buffer.
+ */
+ @callflow(next="*")
+ getProducerUsageMask(handle bufferHandle)
+ generates (Error error,
+ uint64_t usageMask);
+
+ /*
+ * Gets the consumer usage flags which were used to allocate this buffer.
+ *
+ * See IAllocator::BufferDescriptorInfo for more information.
+ *
+ * @param bufferHandle is the buffer from which to get the consumer usage
+ * flags.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return usageMask contains the consumer usage flags of the buffer.
+ */
+ @callflow(next="*")
+ getConsumerUsageMask(handle bufferHandle)
+ generates (Error error,
+ uint64_t usageMask);
+
+ /*
+ * Gets a value that uniquely identifies the backing store of the given
+ * buffer.
+ *
+ * Buffers which share a backing store should return the same value from
+ * this function. If the buffer is present in more than one process, the
+ * backing store value for that buffer is not required to be the same in
+ * every process.
+ *
+ * @param device is the mapper device.
+ * @param bufferHandle is the buffer from which to get the backing store
+ * identifier.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return store is the backing store identifier for this buffer.
+ */
+ @callflow(next="*")
+ getBackingStore(handle bufferHandle)
+ generates (Error error,
+ BackingStore store);
+
+ /*
+ * Gets the stride of the buffer in pixels.
+ *
+ * The stride is the offset in pixel-sized elements between the same
+ * column in two adjacent rows of pixels. This may not be equal to the
+ * width of the buffer.
+ *
+ * @param device is the mapper device.
+ * @param bufferHandle is the buffer from which to get the stride.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * UNDEFINED when the notion of a stride is not
+ * meaningful for the buffer format.
+ * @return store is the stride in pixels.
+ */
+ @callflow(next="*")
+ getStride(handle bufferHandle)
+ generates (Error error,
+ uint32_t stride);
+
+ /*
+ * Locks the given buffer for the specified CPU usage.
+ *
+ * Exactly one of producerUsageMask and consumerUsageMask must be 0. The
+ * usage which is not 0 must be one of the *Usage::CPU* values, as
+ * applicable. Locking a buffer for a non-CPU usage is not supported.
+ *
+ * Locking the same buffer simultaneously from multiple threads is
+ * permitted, but if any of the threads attempt to lock the buffer for
+ * writing, the behavior is undefined, except that it must not cause
+ * process termination or block the client indefinitely. Leaving the
+ * buffer content in an indeterminate state or returning an error are both
+ * acceptable.
+ *
+ * The client must not modify the content of the buffer outside of
+ * accessRegion, and the device need not guarantee that content outside of
+ * accessRegion is valid for reading. The result of reading or writing
+ * outside of accessRegion is undefined, except that it must not cause
+ * process termination.
+ *
+ * data will be filled with a pointer to the locked buffer memory. This
+ * address will represent the top-left corner of the entire buffer, even
+ * if accessRegion does not begin at the top-left corner.
+ *
+ * acquireFence is a file descriptor referring to a acquire sync fence
+ * object, which will be signaled when it is safe for the device to access
+ * the contents of the buffer (prior to locking). If it is already safe to
+ * access the buffer contents, -1 may be passed instead.
+ *
+ * @param bufferHandle is the buffer to lock.
+ * @param producerUsageMask contains the producer usage flags to request;
+ * either this or consumerUsagemask must be 0, and the other must
+ * be a CPU usage.
+ * @param consumerUsageMask contains the consumer usage flags to request;
+ * either this or producerUsageMask must be 0, and the other must
+ * be a CPU usage.
+ * @param accessRegion is the portion of the buffer that the client
+ * intends to access.
+ * @param acquireFence is a sync fence file descriptor as described above.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * BAD_VALUE when neither or both of producerUsageMask
+ * and consumerUsageMask were 0, or the usage
+ * which was not 0 was not a CPU usage.
+ * NO_RESOURCES when the buffer cannot be locked at this
+ * time, but locking may succeed at a future
+ * time.
+ * UNSUPPORTED when the buffer cannot be locked with the
+ * given usage, and any future attempts at
+ * locking will also fail.
+ * @return data will be filled with a CPU-accessible pointer to the buffer
+ * data.
+ */
+ @callflow(next="unlock")
+ lock(handle bufferHandle,
+ uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ Rect accessRegion,
+ handle acquireFence)
+ generates (Error error,
+ pointer data);
+
+ /*
+ * This is largely the same as lock(), except that instead of returning a
+ * pointer directly to the buffer data, it returns an FlexLayout struct
+ * describing how to access the data planes.
+ *
+ * This function must work on buffers with PixelFormat::YCbCr_*_888 if
+ * supported by the device, as well as with any other formats requested by
+ * multimedia codecs when they are configured with a
+ * flexible-YUV-compatible color format.
+ *
+ * This function may also be called on buffers of other formats, including
+ * non-YUV formats, but if the buffer format is not compatible with a
+ * flexible representation, it may return UNSUPPORTED.
+ *
+ * @param device is the mapper device.
+ * @param bufferHandle is the buffer to lock.
+ * @param producerUsageMask contains the producer usage flags to request;
+ * either this or consumerUsagemask must be 0, and the other must
+ * be a CPU usage.
+ * @param consumerUsageMask contains the consumer usage flags to request;
+ * either this or producerUsageMask must be 0, and the other must
+ * be a CPU usage.
+ * @param accessRegion is the portion of the buffer that the client
+ * intends to access.
+ * @param acquireFence is a sync fence file descriptor as described in
+ * lock().
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * BAD_VALUE when neither or both of producerUsageMask
+ * and consumerUsageMask were 0, or the usage
+ * which was not 0 was not a CPU usage.
+ * NO_RESOURCES when the buffer cannot be locked at this
+ * time, but locking may succeed at a future
+ * time.
+ * UNSUPPORTED when the buffer cannot be locked with the
+ * given usage, and any future attempts at
+ * locking will also fail.
+ * @return flexLayout will be filled with the description of the planes in
+ * the buffer.
+ */
+ @callflow(next="unlock")
+ lockFlex(handle bufferHandle,
+ uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ Rect accessRegion,
+ handle acquireFence)
+ generates (Error error,
+ FlexLayout layout);
+
+ /*
+ * This function indicates to the device that the client will be done with
+ * the buffer when releaseFence signals.
+ *
+ * releaseFence will be filled with a file descriptor referring to a
+ * release sync fence object, which will be signaled when it is safe to
+ * access the contents of the buffer (after the buffer has been unlocked).
+ * If it is already safe to access the buffer contents, then -1 may be
+ * returned instead.
+ *
+ * This function is used to unlock both buffers locked by lock() and those
+ * locked by lockFlex().
+ *
+ * @param device is the mapper device.
+ * @param bufferHandle is the buffer to unlock.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer handle is invalid.
+ * @return releaseFence is a sync fence file descriptor as described
+ * above.
+ */
+ @callflow(next="*")
+ unlock(handle bufferHandle)
+ generates (Error error,
+ handle releaseFence);
+};
diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp
new file mode 100644
index 0000000..1dc5aea
--- /dev/null
+++ b/graphics/mapper/2.0/default/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2016 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.
+
+cc_library_shared {
+ name: "android.hardware.graphics.mapper@2.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["GrallocMapper.cpp"],
+ cppflags: ["-Wall", "-Wextra"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp
new file mode 100644
index 0000000..526aca2
--- /dev/null
+++ b/graphics/mapper/2.0/default/GrallocMapper.cpp
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "GrallocMapperPassthrough"
+
+#include "GrallocMapper.h"
+
+#include <mutex>
+#include <vector>
+#include <unordered_map>
+
+#include <string.h>
+
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+namespace {
+
+using android::hardware::graphics::allocator::V2_0::Error;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+class GrallocMapperHal : public IMapper {
+public:
+ GrallocMapperHal(const hw_module_t* module);
+ ~GrallocMapperHal();
+
+ // IMapper interface
+ Return<Error> retain(const hidl_handle& bufferHandle) override;
+ Return<Error> release(const hidl_handle& bufferHandle) override;
+ Return<void> getDimensions(const hidl_handle& bufferHandle,
+ getDimensions_cb hidl_cb) override;
+ Return<void> getFormat(const hidl_handle& bufferHandle,
+ getFormat_cb hidl_cb) override;
+ Return<void> getLayerCount(const hidl_handle& bufferHandle,
+ getLayerCount_cb hidl_cb) override;
+ Return<void> getProducerUsageMask(const hidl_handle& bufferHandle,
+ getProducerUsageMask_cb hidl_cb) override;
+ Return<void> getConsumerUsageMask(const hidl_handle& bufferHandle,
+ getConsumerUsageMask_cb hidl_cb) override;
+ Return<void> getBackingStore(const hidl_handle& bufferHandle,
+ getBackingStore_cb hidl_cb) override;
+ Return<void> getStride(const hidl_handle& bufferHandle,
+ getStride_cb hidl_cb) override;
+ Return<void> lock(const hidl_handle& bufferHandle,
+ uint64_t producerUsageMask, uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
+ lock_cb hidl_cb) override;
+ Return<void> lockFlex(const hidl_handle& bufferHandle,
+ uint64_t producerUsageMask, uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
+ lockFlex_cb hidl_cb) override;
+ Return<void> unlock(const hidl_handle& bufferHandle,
+ unlock_cb hidl_cb) override;
+
+private:
+ void initCapabilities();
+
+ template<typename T>
+ void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
+ void initDispatch();
+
+ static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
+ static bool dupFence(const hidl_handle& fenceHandle, int* outFd);
+
+ gralloc1_device_t* mDevice;
+
+ struct {
+ bool layeredBuffers;
+ } mCapabilities;
+
+ struct {
+ GRALLOC1_PFN_RETAIN retain;
+ GRALLOC1_PFN_RELEASE release;
+ GRALLOC1_PFN_GET_DIMENSIONS getDimensions;
+ GRALLOC1_PFN_GET_FORMAT getFormat;
+ GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount;
+ GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage;
+ GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage;
+ GRALLOC1_PFN_GET_BACKING_STORE getBackingStore;
+ GRALLOC1_PFN_GET_STRIDE getStride;
+ GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
+ GRALLOC1_PFN_LOCK lock;
+ GRALLOC1_PFN_LOCK_FLEX lockFlex;
+ GRALLOC1_PFN_UNLOCK unlock;
+ } mDispatch;
+
+ std::mutex mMutex;
+ std::unordered_map<buffer_handle_t, size_t> mBufferReferenceCounts;
+};
+
+GrallocMapperHal::GrallocMapperHal(const hw_module_t* module)
+ : mDevice(nullptr), mCapabilities(), mDispatch()
+{
+ int status = gralloc1_open(module, &mDevice);
+ if (status) {
+ LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
+ strerror(-status));
+ }
+
+ initCapabilities();
+ initDispatch();
+}
+
+GrallocMapperHal::~GrallocMapperHal()
+{
+ gralloc1_close(mDevice);
+}
+
+void GrallocMapperHal::initCapabilities()
+{
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<int32_t> caps(count);
+ mDevice->getCapabilities(mDevice, &count, caps.data());
+ caps.resize(count);
+
+ for (auto cap : caps) {
+ switch (cap) {
+ case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
+ mCapabilities.layeredBuffers = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+template<typename T>
+void GrallocMapperHal::initDispatch(gralloc1_function_descriptor_t desc,
+ T* outPfn)
+{
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
+ }
+
+ *outPfn = reinterpret_cast<T>(pfn);
+}
+
+void GrallocMapperHal::initDispatch()
+{
+ initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
+ initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
+ initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions);
+ initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat);
+ if (mCapabilities.layeredBuffers) {
+ initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT,
+ &mDispatch.getLayerCount);
+ }
+ initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE,
+ &mDispatch.getProducerUsage);
+ initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE,
+ &mDispatch.getConsumerUsage);
+ initDispatch(GRALLOC1_FUNCTION_GET_BACKING_STORE,
+ &mDispatch.getBackingStore);
+ initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
+ initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
+ &mDispatch.getNumFlexPlanes);
+ initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
+ initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
+ initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
+}
+
+gralloc1_rect_t GrallocMapperHal::asGralloc1Rect(const IMapper::Rect& rect)
+{
+ return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
+}
+
+bool GrallocMapperHal::dupFence(const hidl_handle& fenceHandle, int* outFd)
+{
+ auto handle = fenceHandle.getNativeHandle();
+ if (!handle || handle->numFds == 0) {
+ *outFd = -1;
+ return true;
+ }
+
+ if (handle->numFds > 1) {
+ ALOGE("invalid fence handle with %d fds", handle->numFds);
+ return false;
+ }
+
+ *outFd = dup(handle->data[0]);
+ return (*outFd >= 0);
+}
+
+Return<Error> GrallocMapperHal::retain(const hidl_handle& bufferHandle)
+{
+ int32_t err = mDispatch.retain(mDevice, bufferHandle);
+ if (err == GRALLOC1_ERROR_NONE) {
+ auto nativeHandle = bufferHandle.getNativeHandle();
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ ++mBufferReferenceCounts[nativeHandle];
+ }
+ return static_cast<Error>(err);
+}
+
+Return<Error> GrallocMapperHal::release(const hidl_handle& bufferHandle)
+{
+ int32_t err = mDispatch.release(mDevice, bufferHandle);
+ if (err == GRALLOC1_ERROR_NONE) {
+ auto nativeHandle = bufferHandle.getNativeHandle();
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto iter = mBufferReferenceCounts.find(bufferHandle);
+ if (iter == mBufferReferenceCounts.end()) {
+ // this should never happen
+ err = GRALLOC1_ERROR_BAD_HANDLE;
+ } else if (--iter->second == 0) {
+ native_handle_close(nativeHandle);
+ native_handle_delete(const_cast<native_handle_t*>(nativeHandle));
+
+ mBufferReferenceCounts.erase(iter);
+ }
+ }
+
+ return static_cast<Error>(err);
+}
+
+Return<void> GrallocMapperHal::getDimensions(const hidl_handle& bufferHandle,
+ getDimensions_cb hidl_cb)
+{
+ uint32_t width = 0;
+ uint32_t height = 0;
+ int32_t err = mDispatch.getDimensions(mDevice, bufferHandle,
+ &width, &height);
+
+ hidl_cb(static_cast<Error>(err), width, height);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getFormat(const hidl_handle& bufferHandle,
+ getFormat_cb hidl_cb)
+{
+ int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ int32_t err = mDispatch.getFormat(mDevice, bufferHandle, &format);
+
+ hidl_cb(static_cast<Error>(err), static_cast<PixelFormat>(format));
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getLayerCount(const hidl_handle& bufferHandle,
+ getLayerCount_cb hidl_cb)
+{
+ int32_t err = GRALLOC1_ERROR_NONE;
+ uint32_t count = 1;
+ if (mCapabilities.layeredBuffers) {
+ err = mDispatch.getLayerCount(mDevice, bufferHandle, &count);
+ }
+
+ hidl_cb(static_cast<Error>(err), count);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getProducerUsageMask(
+ const hidl_handle& bufferHandle, getProducerUsageMask_cb hidl_cb)
+{
+ uint64_t mask = 0x0;
+ int32_t err = mDispatch.getProducerUsage(mDevice, bufferHandle, &mask);
+
+ hidl_cb(static_cast<Error>(err), mask);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getConsumerUsageMask(
+ const hidl_handle& bufferHandle, getConsumerUsageMask_cb hidl_cb)
+{
+ uint64_t mask = 0x0;
+ int32_t err = mDispatch.getConsumerUsage(mDevice, bufferHandle, &mask);
+
+ hidl_cb(static_cast<Error>(err), mask);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getBackingStore(
+ const hidl_handle& bufferHandle, getBackingStore_cb hidl_cb)
+{
+ uint64_t store = 0;
+ int32_t err = mDispatch.getBackingStore(mDevice, bufferHandle, &store);
+
+ hidl_cb(static_cast<Error>(err), store);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::getStride(const hidl_handle& bufferHandle,
+ getStride_cb hidl_cb)
+{
+ uint32_t stride = 0;
+ int32_t err = mDispatch.getStride(mDevice, bufferHandle, &stride);
+
+ hidl_cb(static_cast<Error>(err), stride);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::lock(const hidl_handle& bufferHandle,
+ uint64_t producerUsageMask, uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
+ lock_cb hidl_cb)
+{
+ gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
+
+ int fence = -1;
+ if (!dupFence(acquireFence, &fence)) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ void* data = nullptr;
+ int32_t err = mDispatch.lock(mDevice, bufferHandle, producerUsageMask,
+ consumerUsageMask, &rect, &data, fence);
+ if (err != GRALLOC1_ERROR_NONE) {
+ close(fence);
+ }
+
+ hidl_cb(static_cast<Error>(err), data);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::lockFlex(const hidl_handle& bufferHandle,
+ uint64_t producerUsageMask, uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
+ lockFlex_cb hidl_cb)
+{
+ FlexLayout layout_reply{};
+
+ uint32_t planeCount = 0;
+ int32_t err = mDispatch.getNumFlexPlanes(mDevice, bufferHandle,
+ &planeCount);
+ if (err != GRALLOC1_ERROR_NONE) {
+ hidl_cb(static_cast<Error>(err), layout_reply);
+ return Void();
+ }
+
+ gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
+
+ int fence = -1;
+ if (!dupFence(acquireFence, &fence)) {
+ hidl_cb(Error::NO_RESOURCES, layout_reply);
+ return Void();
+ }
+
+ std::vector<android_flex_plane_t> planes(planeCount);
+ android_flex_layout_t layout{};
+ layout.num_planes = planes.size();
+ layout.planes = planes.data();
+
+ err = mDispatch.lockFlex(mDevice, bufferHandle, producerUsageMask,
+ consumerUsageMask, &rect, &layout, fence);
+ if (err == GRALLOC1_ERROR_NONE) {
+ layout_reply.format = static_cast<FlexFormat>(layout.format);
+
+ planes.resize(layout.num_planes);
+ layout_reply.planes.setToExternal(
+ reinterpret_cast<FlexPlane*>(planes.data()), planes.size());
+ } else {
+ close(fence);
+ }
+
+ hidl_cb(static_cast<Error>(err), layout_reply);
+ return Void();
+}
+
+Return<void> GrallocMapperHal::unlock(const hidl_handle& bufferHandle,
+ unlock_cb hidl_cb)
+{
+ int32_t fence = -1;
+ int32_t err = mDispatch.unlock(mDevice, bufferHandle, &fence);
+
+ NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
+ hidl_handle fenceHandle;
+ if (err == GRALLOC1_ERROR_NONE && fence >= 0) {
+ auto nativeHandle = native_handle_init(fenceStorage, 1, 0);
+ nativeHandle->data[0] = fence;
+
+ fenceHandle = nativeHandle;
+ }
+
+ hidl_cb(static_cast<Error>(err), fenceHandle);
+ return Void();
+}
+
+} // anonymous namespace
+
+IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
+ const hw_module_t* module = nullptr;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return nullptr;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major != 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return nullptr;
+ }
+
+ return new GrallocMapperHal(module);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/2.0/default/GrallocMapper.h b/graphics/mapper/2.0/default/GrallocMapper.h
new file mode 100644
index 0000000..a2f89d1
--- /dev/null
+++ b/graphics/mapper/2.0/default/GrallocMapper.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
+#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+extern "C" IMapper* HIDL_FETCH_IMapper(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
diff --git a/graphics/mapper/2.0/types.hal b/graphics/mapper/2.0/types.hal
new file mode 100644
index 0000000..aa33141
--- /dev/null
+++ b/graphics/mapper/2.0/types.hal
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 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.graphics.mapper@2.0;
+
+/*
+ * Structures for describing flexible YUVA/RGBA formats for consumption by
+ * applications. Such flexible formats contain a plane for each component (e.g.
+ * red, green, blue), where each plane is laid out in a grid-like pattern
+ * occupying unique byte addresses and with consistent byte offsets between
+ * neighboring pixels.
+ *
+ * The FlexLayout structure is used with any pixel format that can be
+ * represented by it, such as:
+ * - PixelFormat::YCBCR_*_888
+ * - PixelFormat::FLEX_RGB*_888
+ * - PixelFormat::RGB[AX]_888[8],BGRA_8888,RGB_888
+ * - PixelFormat::YV12,Y8,Y16,YCBCR_422_SP/I,YCRCB_420_SP
+ * - even implementation defined formats that can be represented by
+ * the structures
+ *
+ * Vertical increment (aka. row increment or stride) describes the distance in
+ * bytes from the first pixel of one row to the first pixel of the next row
+ * (below) for the component plane. This can be negative.
+ *
+ * Horizontal increment (aka. column or pixel increment) describes the distance
+ * in bytes from one pixel to the next pixel (to the right) on the same row for
+ * the component plane. This can be negative.
+ *
+ * Each plane can be subsampled either vertically or horizontally by
+ * a power-of-two factor.
+ *
+ * The bit-depth of each component can be arbitrary, as long as the pixels are
+ * laid out on whole bytes, in native byte-order, using the most significant
+ * bits of each unit.
+ */
+
+enum FlexComponent : int32_t {
+ Y = 1 << 0, /* luma */
+ CB = 1 << 1, /* chroma blue */
+ CR = 1 << 2, /* chroma red */
+
+ R = 1 << 10, /* red */
+ G = 1 << 11, /* green */
+ B = 1 << 12, /* blue */
+
+ A = 1 << 30, /* alpha */
+};
+
+enum FlexFormat : int32_t {
+ /* not a flexible format */
+ INVALID = 0x0,
+
+ Y = FlexComponent:Y,
+ YCBCR = Y | FlexComponent:CB | FlexComponent:CR,
+ YCBCRA = YCBCR | FlexComponent:A,
+
+ RGB = FlexComponent:R | FlexComponent:G | FlexComponent:B,
+ RGBA = RGB | FlexComponent:A,
+};
+
+struct FlexPlane {
+ /* Pointer to the first byte of the top-left pixel of the plane. */
+ pointer topLeft;
+
+ FlexComponent component;
+
+ /*
+ * Bits allocated for the component in each pixel. Must be a positive
+ * multiple of 8.
+ */
+ int32_t bitsPerComponent;
+
+ /*
+ * Number of the most significant bits used in the format for this
+ * component. Must be between 1 and bitsPerComponent, inclusive.
+ */
+ int32_t bitsUsed;
+
+ /* Horizontal increment. */
+ int32_t hIncrement;
+ /* Vertical increment. */
+ int32_t vIncrement;
+ /* Horizontal subsampling. Must be a positive power of 2. */
+ int32_t hSubsampling;
+ /* Vertical subsampling. Must be a positive power of 2. */
+ int32_t vSubsampling;
+};
+
+struct FlexLayout {
+ /* The kind of flexible format. */
+ FlexFormat format;
+
+ /*
+ * A plane for each component; ordered in increasing component value
+ * order. E.g. FlexFormat::RGBA maps 0 -> R, 1 -> G, etc. Can have size 0
+ * for FlexFormat::INVALID.
+ */
+ vec<FlexPlane> planes;
+};
+
+/* Backing store ID of a buffer. See IMapper::getBackingStore. */
+typedef uint64_t BackingStore;
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..e26f087
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_library_static {
+ name: "libVtsHalGraphicsMapperTestUtils",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsMapperTestUtils.cpp"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "libVtsHalGraphicsAllocatorTestUtils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_test {
+ name: "VtsHalGraphicsMapperV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libsync",
+ "libutils",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.common@1.0",
+ ],
+ static_libs: [
+ "libVtsHalGraphicsAllocatorTestUtils",
+ "libVtsHalGraphicsMapperTestUtils",
+ "VtsHalHidlTargetTestBase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
new file mode 100644
index 0000000..f6a26ac
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "VtsHalGraphicsMapperTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+
+using android::hardware::graphics::allocator::V2_0::Buffer;
+using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
+using android::hardware::graphics::allocator::V2_0::Error;
+
+Mapper::Mapper() { init(); }
+
+void Mapper::init() {
+ mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>();
+ ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+Mapper::~Mapper() {
+ for (auto it : mHandles) {
+ while (it.second) {
+ EXPECT_EQ(Error::NONE, mMapper->release(it.first))
+ << "failed to release handle " << it.first;
+ it.second--;
+ }
+ }
+ mHandles.clear();
+}
+
+sp<IMapper> Mapper::getRaw() const { return mMapper; }
+
+void Mapper::retain(const native_handle_t* handle) {
+ Error error = mMapper->retain(handle);
+ ASSERT_EQ(Error::NONE, error) << "failed to retain handle " << handle;
+
+ mHandles[handle]++;
+}
+
+void Mapper::release(const native_handle_t* handle) {
+ Error error = mMapper->release(handle);
+ ASSERT_EQ(Error::NONE, error) << "failed to release handle " << handle;
+
+ if (--mHandles[handle] == 0) {
+ mHandles.erase(handle);
+ }
+}
+
+Mapper::Dimensions Mapper::getDimensions(const native_handle_t* handle) {
+ Dimensions dimensions = {};
+ mMapper->getDimensions(handle, [&](const auto& tmpError, const auto& tmpWidth,
+ const auto& tmpHeight) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get dimensions for handle " << handle;
+ dimensions.width = tmpWidth;
+ dimensions.height = tmpHeight;
+ });
+
+ return dimensions;
+}
+
+PixelFormat Mapper::getFormat(const native_handle_t* handle) {
+ PixelFormat format = static_cast<PixelFormat>(0);
+ mMapper->getFormat(handle, [&](const auto& tmpError, const auto& tmpFormat) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get format for handle " << handle;
+ format = tmpFormat;
+ });
+
+ return format;
+}
+
+uint32_t Mapper::getLayerCount(const native_handle_t* handle) {
+ uint32_t count = 0;
+ mMapper->getLayerCount(
+ handle, [&](const auto& tmpError, const auto& tmpCount) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get layer count for handle " << handle;
+ count = tmpCount;
+ });
+
+ return count;
+}
+
+uint64_t Mapper::getProducerUsageMask(const native_handle_t* handle) {
+ uint64_t usageMask = 0;
+ mMapper->getProducerUsageMask(
+ handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get producer usage mask for handle " << handle;
+ usageMask = tmpUsageMask;
+ });
+
+ return usageMask;
+}
+
+uint64_t Mapper::getConsumerUsageMask(const native_handle_t* handle) {
+ uint64_t usageMask = 0;
+ mMapper->getConsumerUsageMask(
+ handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get consumer usage mask for handle " << handle;
+ usageMask = tmpUsageMask;
+ });
+
+ return usageMask;
+}
+
+BackingStore Mapper::getBackingStore(const native_handle_t* handle) {
+ BackingStore backingStore = 0;
+ mMapper->getBackingStore(
+ handle, [&](const auto& tmpError, const auto& tmpBackingStore) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get backing store for handle " << handle;
+ backingStore = tmpBackingStore;
+ });
+
+ return backingStore;
+}
+
+uint32_t Mapper::getStride(const native_handle_t* handle) {
+ uint32_t stride = 0;
+ mMapper->getStride(handle, [&](const auto& tmpError, const auto& tmpStride) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to get stride for handle " << handle;
+ stride = tmpStride;
+ });
+
+ return stride;
+}
+
+void* Mapper::lock(const native_handle_t* handle, uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, int acquireFence) {
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
+ native_handle_t* acquireFenceHandle = nullptr;
+ if (acquireFence >= 0) {
+ acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
+ acquireFenceHandle->data[0] = acquireFence;
+ }
+
+ void* data = nullptr;
+ mMapper->lock(
+ handle, producerUsageMask, consumerUsageMask, accessRegion,
+ acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to lock handle " << handle;
+ data = tmpData;
+ });
+
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return data;
+}
+
+FlexLayout Mapper::lockFlex(const native_handle_t* handle,
+ uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion,
+ int acquireFence) {
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
+ native_handle_t* acquireFenceHandle = nullptr;
+ if (acquireFence >= 0) {
+ acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
+ acquireFenceHandle->data[0] = acquireFence;
+ }
+
+ FlexLayout layout = {};
+ mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask, accessRegion,
+ acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to lockFlex handle " << handle;
+ layout = tmpLayout;
+ });
+
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return layout;
+}
+
+int Mapper::unlock(const native_handle_t* handle) {
+ int releaseFence = -1;
+ mMapper->unlock(handle, [&](const auto& tmpError,
+ const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock handle " << handle;
+
+ auto handle = tmpReleaseFence.getNativeHandle();
+ if (handle) {
+ ASSERT_EQ(0, handle->numInts) << "invalid fence handle " << handle;
+ if (handle->numFds == 1) {
+ releaseFence = dup(handle->data[0]);
+ ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+ } else {
+ ASSERT_EQ(0, handle->numFds) << " invalid fence handle " << handle;
+ }
+ }
+ });
+
+ return releaseFence;
+}
+
+const native_handle_t* Mapper::allocate(
+ std::unique_ptr<AllocatorClient>& allocatorClient,
+ const IAllocatorClient::BufferDescriptorInfo& info) {
+ BufferDescriptor descriptor = allocatorClient->createDescriptor(info);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ Buffer buffer = allocatorClient->allocate(descriptor);
+ if (::testing::Test::HasFatalFailure()) {
+ allocatorClient->destroyDescriptor(descriptor);
+ return nullptr;
+ }
+
+ const native_handle_t* handle =
+ allocatorClient->exportHandle(descriptor, buffer);
+ if (handle) {
+ retain(handle);
+ }
+
+ allocatorClient->free(buffer);
+ allocatorClient->destroyDescriptor(descriptor);
+
+ return handle;
+}
+
+} // namespace tests
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
new file mode 100644
index 0000000..c186b00
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
+#define VTS_HAL_GRAPHICS_MAPPER_UTILS
+
+#include <memory>
+#include <unordered_map>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <utils/StrongPointer.h>
+
+#include "VtsHalGraphicsAllocatorTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
+using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
+
+// A wrapper to IMapper.
+class Mapper {
+ public:
+ Mapper();
+ ~Mapper();
+
+ sp<IMapper> getRaw() const;
+
+ void retain(const native_handle_t* handle);
+ void release(const native_handle_t* handle);
+
+ struct Dimensions {
+ uint32_t width;
+ uint32_t height;
+ };
+ Dimensions getDimensions(const native_handle_t* handle);
+
+ PixelFormat getFormat(const native_handle_t* handle);
+ uint32_t getLayerCount(const native_handle_t* handle);
+ uint64_t getProducerUsageMask(const native_handle_t* handle);
+ uint64_t getConsumerUsageMask(const native_handle_t* handle);
+ BackingStore getBackingStore(const native_handle_t* handle);
+ uint32_t getStride(const native_handle_t* handle);
+
+ // We use fd instead of hidl_handle in these functions to pass fences
+ // in and out of the mapper. The ownership of the fd is always transferred
+ // with each of these functions.
+ void* lock(const native_handle_t* handle, uint64_t producerUsageMask,
+ uint64_t consumerUsageMask, const IMapper::Rect& accessRegion,
+ int acquireFence);
+ FlexLayout lockFlex(const native_handle_t* handle, uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ const IMapper::Rect& accessRegion, int acquireFence);
+ int unlock(const native_handle_t* handle);
+
+ // Requests AllocatorClient to allocate a buffer, export the handle, and
+ // register the handle with mapper.
+ const native_handle_t* allocate(
+ std::unique_ptr<AllocatorClient>& allocatorClient,
+ const IAllocatorClient::BufferDescriptorInfo& info);
+
+ private:
+ void init();
+
+ sp<IMapper> mMapper;
+
+ // Keep track of all registered (retained) handles. When a test fails with
+ // ASSERT_*, the destructor will release the handles for the test.
+ std::unordered_map<const native_handle_t*, uint64_t> mHandles;
+};
+
+} // namespace tests
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // VTS_HAL_GRAPHICS_MAPPER_UTILS
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
new file mode 100644
index 0000000..92d74d5
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "graphics_mapper_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <sync/sync.h>
+#include "VtsHalGraphicsMapperTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+namespace {
+
+using namespace android::hardware::graphics::allocator::V2_0;
+using namespace android::hardware::graphics::allocator::V2_0::tests;
+
+class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
+ ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
+ ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
+
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+ mDummyDescriptorInfo.producerUsageMask =
+ static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
+ mDummyDescriptorInfo.consumerUsageMask =
+ static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+ }
+
+ void TearDown() override {}
+
+ std::unique_ptr<Allocator> mAllocator;
+ std::unique_ptr<AllocatorClient> mAllocatorClient;
+ std::unique_ptr<Mapper> mMapper;
+ IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
+};
+
+/**
+ * Test IMapper::retain and IMapper::release.
+ */
+TEST_F(GraphicsMapperHidlTest, RetainRelease) {
+ const native_handle_t* buffer;
+ ASSERT_NO_FATAL_FAILURE(
+ buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+
+ const int maxRefs = 10;
+ for (int i = 0; i < maxRefs; i++) {
+ ASSERT_NO_FATAL_FAILURE(mMapper->retain(buffer));
+ }
+ for (int i = 0; i < maxRefs; i++) {
+ ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
+}
+
+/**
+ * Test IMapper::get* getters.
+ */
+TEST_F(GraphicsMapperHidlTest, Getters) {
+ const native_handle_t* buffer;
+ ASSERT_NO_FATAL_FAILURE(
+ buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+
+ IAllocatorClient::BufferDescriptorInfo info = {};
+
+ Mapper::Dimensions dimensions;
+ ASSERT_NO_FATAL_FAILURE(dimensions = mMapper->getDimensions(buffer));
+ info.width = dimensions.width;
+ info.height = dimensions.height;
+
+ ASSERT_NO_FATAL_FAILURE(info.format = mMapper->getFormat(buffer));
+ ASSERT_NO_FATAL_FAILURE(info.producerUsageMask =
+ mMapper->getProducerUsageMask(buffer));
+ ASSERT_NO_FATAL_FAILURE(info.consumerUsageMask =
+ mMapper->getConsumerUsageMask(buffer));
+
+ EXPECT_EQ(mDummyDescriptorInfo.width, info.width);
+ EXPECT_EQ(mDummyDescriptorInfo.height, info.height);
+ EXPECT_EQ(mDummyDescriptorInfo.format, info.format);
+ EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask);
+ EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask);
+
+ ASSERT_NO_FATAL_FAILURE(mMapper->getBackingStore(buffer));
+
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
+ EXPECT_LE(info.width, stride);
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_F(GraphicsMapperHidlTest, LockBasic) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* buffer;
+ ASSERT_NO_FATAL_FAILURE(
+ buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ uint32_t* data;
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint32_t*>(
+ mMapper->lock(buffer, info.producerUsageMask, 0, region, fence)));
+
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ data[stride * y + x] = info.height * y + x;
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+
+ // lock buffer for reading
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint32_t*>(
+ mMapper->lock(buffer, 0, info.consumerUsageMask, region, fence)));
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ EXPECT_EQ(info.height * y + x, data[stride * y + x]);
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::lockFlex. This locks a YV12 buffer, and makes sure we can
+ * write to and read from it.
+ */
+TEST_F(GraphicsMapperHidlTest, LockFlexBasic) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YV12;
+
+ const native_handle_t* buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = mMapper->allocate(mAllocatorClient, info));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ FlexLayout layout;
+ ASSERT_NO_FATAL_FAILURE(
+ layout =
+ mMapper->lockFlex(buffer, info.producerUsageMask, 0, region, fence));
+ ASSERT_EQ(FlexFormat::YCBCR, layout.format);
+ ASSERT_EQ(3u, layout.planes.size());
+
+ const auto y_stride = layout.planes[0].vIncrement;
+ const auto c_stride = layout.planes[1].vIncrement;
+ auto y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
+ auto cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
+ auto cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
+
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ y_data[y_stride * y + x] = val;
+ if (y % 2 == 0 && x % 2 == 0) {
+ cb_data[c_stride * y / 2 + x / 2] = val;
+ cr_data[c_stride * y / 2 + x / 2] = val;
+ }
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+
+ // lock buffer for reading
+ ASSERT_NO_FATAL_FAILURE(
+ layout =
+ mMapper->lockFlex(buffer, 0, info.consumerUsageMask, region, fence));
+
+ y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
+ cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
+ cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ EXPECT_EQ(val, y_data[y_stride * y + x]);
+ if (y % 2 == 0 && x % 2 == 0) {
+ EXPECT_EQ(val, cb_data[c_stride * y / 2 + x / 2]);
+ EXPECT_EQ(val, cr_data[c_stride * y / 2 + x / 2]);
+ }
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+} // namespace anonymous
+} // namespace tests
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+
+ return status;
+}
diff --git a/graphics/mapper/Android.mk b/graphics/mapper/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/mapper/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/health/1.0/Android.bp b/health/1.0/Android.bp
new file mode 100644
index 0000000..a428c7d
--- /dev/null
+++ b/health/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.health@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IHealth.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.health@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.health@1.0",
+ srcs: [
+ ":android.hardware.health@1.0_hal",
+ ],
+ out: [
+ "android/hardware/health/1.0/types.cpp",
+ "android/hardware/health/1.0/HealthAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.health@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.health@1.0",
+ srcs: [
+ ":android.hardware.health@1.0_hal",
+ ],
+ out: [
+ "android/hardware/health/1.0/types.h",
+ "android/hardware/health/1.0/IHealth.h",
+ "android/hardware/health/1.0/IHwHealth.h",
+ "android/hardware/health/1.0/BnHwHealth.h",
+ "android/hardware/health/1.0/BpHwHealth.h",
+ "android/hardware/health/1.0/BsHealth.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.health@1.0",
+ generated_sources: ["android.hardware.health@1.0_genc++"],
+ generated_headers: ["android.hardware.health@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.health@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/health/1.0/Android.mk b/health/1.0/Android.mk
new file mode 100644
index 0000000..ebb89a7
--- /dev/null
+++ b/health/1.0/Android.mk
@@ -0,0 +1,304 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.health@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (BatteryHealth)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/BatteryHealth.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.BatteryHealth
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (BatteryStatus)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/BatteryStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.BatteryStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HealthConfig)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/HealthConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.HealthConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HealthInfo)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/HealthInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.HealthInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHealth.hal
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/IHealth.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHealth.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::IHealth
+
+$(GEN): $(LOCAL_PATH)/IHealth.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.health@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (BatteryHealth)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/BatteryHealth.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.BatteryHealth
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (BatteryStatus)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/BatteryStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.BatteryStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HealthConfig)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/HealthConfig.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.HealthConfig
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HealthInfo)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/HealthInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.HealthInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHealth.hal
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/IHealth.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHealth.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0::IHealth
+
+$(GEN): $(LOCAL_PATH)/IHealth.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.health@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/health/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IHealth.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.health@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/IHealth.hal b/health/1.0/IHealth.hal
new file mode 100644
index 0000000..3828589
--- /dev/null
+++ b/health/1.0/IHealth.hal
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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.health@1.0;
+
+interface IHealth {
+ /**
+ * This function lets you change healthd configuration from default if
+ * desired. It must be called exactly once at startup time.
+ *
+ * The configuration values are described in 'struct HealthConfig'.
+ * To use default configuration, simply return without modifying the
+ * fields of the config parameter.
+ *
+ * @param default healthd configuration.
+ */
+ init(HealthConfig config) generates (HealthConfig configOut);
+
+ /**
+ * This function is a hook to update/change device's HealthInfo (as described
+ * in 'struct HealthInfo').
+ *
+ * 'HealthInfo' describes device's battery and charging status, typically
+ * read from kernel. These values may be modified in this call.
+ *
+ * @param Device Health info as described in 'struct HealthInfo'.
+ * @return skipLogging Indication to the caller to add 'or' skip logging the health
+ * information. Return 'true' to skip logging the update.
+ * @return infoOut HealthInfo to be sent to client code. (May or may
+ * not be modified).
+ */
+ update(HealthInfo info) generates (bool skipLogging, HealthInfo infoOut);
+
+ /**
+ * This function is called by healthd when framework queries for remaining
+ * energy in the Battery through BatteryManager APIs.
+ *
+ * @return result Result of querying enery counter for the battery.
+ * @return energy Battery remaining energy in nanowatt-hours.
+ * Must be '0' if result is anything other than Result::SUCCESS.
+ */
+ energyCounter() generates (Result result, int64_t energy);
+};
diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk
new file mode 100644
index 0000000..96ff91f
--- /dev/null
+++ b/health/1.0/default/Android.mk
@@ -0,0 +1,59 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.health@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include
+LOCAL_SRC_FILES := \
+ Health.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ android.hardware.health@1.0 \
+
+LOCAL_STATIC_LIBRARIES := android.hardware.health@1.0-convert
+
+LOCAL_HAL_STATIC_LIBRARIES := libhealthd
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.health@1.0-convert
+LOCAL_SRC_FILES := convert.cpp
+LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ android.hardware.health@1.0 \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE := android.hardware.health@1.0-service
+LOCAL_INIT_RC := android.hardware.health@1.0-service.rc
+LOCAL_SRC_FILES := \
+ HealthService.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.health@1.0 \
+
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/default/Health.cpp b/health/1.0/default/Health.cpp
new file mode 100644
index 0000000..1a02956
--- /dev/null
+++ b/health/1.0/default/Health.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "health-hal"
+
+#include <Health.h>
+#include <include/hal_conversion.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+
+// Methods from ::android::hardware::health::V1_0::IHealth follow.
+Return<void> Health::init(const HealthConfig& config, init_cb _hidl_cb) {
+ struct healthd_config healthd_config = {};
+ HealthConfig configOut;
+
+ // To keep working with existing healthd static HALs,
+ // convert the new HealthConfig to the old healthd_config
+ // and back.
+
+ convertFromHealthConfig(config, &healthd_config);
+ healthd_board_init(&healthd_config);
+ mGetEnergyCounter = healthd_config.energyCounter;
+ convertToHealthConfig(&healthd_config, configOut);
+
+ _hidl_cb(configOut);
+
+ return Void();
+}
+
+Return<void> Health::update(const HealthInfo& info, update_cb _hidl_cb) {
+ struct android::BatteryProperties p = {};
+ HealthInfo infoOut;
+
+ // To keep working with existing healthd static HALs,
+ // convert the new HealthInfo to android::Batteryproperties
+ // and back.
+
+ convertFromHealthInfo(info, &p);
+ int skipLogging = healthd_board_battery_update(&p);
+ convertToHealthInfo(&p, infoOut);
+
+ _hidl_cb(!!skipLogging, infoOut);
+
+ return Void();
+}
+
+Return<void> Health::energyCounter(energyCounter_cb _hidl_cb) {
+ int64_t energy = 0;
+ Result result = Result::NOT_SUPPORTED;
+
+ if (mGetEnergyCounter) {
+ int status = mGetEnergyCounter(&energy);
+ if (status == 0) {
+ result = Result::SUCCESS;
+ }
+ }
+
+ _hidl_cb(result, energy);
+
+ return Void();
+}
+
+IHealth* HIDL_FETCH_IHealth(const char* /* name */) {
+ return new Health();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/1.0/default/Health.h b/health/1.0/default/Health.h
new file mode 100644
index 0000000..ed364c1
--- /dev/null
+++ b/health/1.0/default/Health.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H
+#define ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include <healthd/healthd.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::health::V1_0::HealthInfo;
+using ::android::hardware::health::V1_0::HealthConfig;
+using ::android::hardware::health::V1_0::IHealth;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Health : public IHealth {
+ // Methods from ::android::hardware::health::V1_0::IHealth follow.
+ Return<void> init(const HealthConfig& config, init_cb _hidl_cb) override;
+ Return<void> update(const HealthInfo& info, update_cb _hidl_cb) override;
+ Return<void> energyCounter(energyCounter_cb _hidl_cb) override;
+private:
+ std::function<int(int64_t *)> mGetEnergyCounter;
+};
+
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H
diff --git a/health/1.0/default/HealthService.cpp b/health/1.0/default/HealthService.cpp
new file mode 100644
index 0000000..55848d2
--- /dev/null
+++ b/health/1.0/default/HealthService.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.health@1.0-service"
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::health::V1_0::IHealth;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IHealth>();
+}
diff --git a/health/1.0/default/android.hardware.health@1.0-service.rc b/health/1.0/default/android.hardware.health@1.0-service.rc
new file mode 100644
index 0000000..13cd7a5
--- /dev/null
+++ b/health/1.0/default/android.hardware.health@1.0-service.rc
@@ -0,0 +1,4 @@
+service health-hal-1-0 /vendor/bin/hw/android.hardware.health@1.0-service
+ class hal
+ user system
+ group system
diff --git a/health/1.0/default/convert.cpp b/health/1.0/default/convert.cpp
new file mode 100644
index 0000000..7f1e3c4
--- /dev/null
+++ b/health/1.0/default/convert.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "include/hal_conversion.h"
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V1_0 {
+namespace hal_conversion {
+
+void convertToHealthConfig(const struct healthd_config *hc, HealthConfig& config) {
+ config.periodicChoresIntervalFast = hc->periodic_chores_interval_fast;
+ config.periodicChoresIntervalSlow = hc->periodic_chores_interval_slow;
+
+ config.batteryStatusPath = hc->batteryStatusPath.string();
+ config.batteryHealthPath = hc->batteryHealthPath.string();
+ config.batteryPresentPath = hc->batteryPresentPath.string();
+ config.batteryCapacityPath = hc->batteryCapacityPath.string();
+ config.batteryVoltagePath = hc->batteryVoltagePath.string();
+ config.batteryTemperaturePath = hc->batteryTemperaturePath.string();
+ config.batteryTechnologyPath = hc->batteryTechnologyPath.string();
+ config.batteryCurrentNowPath = hc->batteryCurrentNowPath.string();
+ config.batteryCurrentAvgPath = hc->batteryCurrentAvgPath.string();
+ config.batteryChargeCounterPath = hc->batteryChargeCounterPath.string();
+ config.batteryFullChargePath = hc->batteryFullChargePath.string();
+ config.batteryCycleCountPath = hc->batteryCycleCountPath.string();
+
+}
+
+void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc) {
+ hc->periodic_chores_interval_fast = c.periodicChoresIntervalFast;
+ hc->periodic_chores_interval_slow = c.periodicChoresIntervalSlow;
+
+ hc->batteryStatusPath =
+ android::String8(c.batteryStatusPath.c_str(),
+ c.batteryStatusPath.size());
+
+ hc->batteryHealthPath =
+ android::String8(c.batteryHealthPath.c_str(),
+ c.batteryHealthPath.size());
+
+ hc->batteryPresentPath =
+ android::String8(c.batteryPresentPath.c_str(),
+ c.batteryPresentPath.size());
+
+ hc->batteryCapacityPath =
+ android::String8(c.batteryCapacityPath.c_str(),
+ c.batteryCapacityPath.size());
+
+ hc->batteryVoltagePath =
+ android::String8(c.batteryVoltagePath.c_str(),
+ c.batteryVoltagePath.size());
+
+ hc->batteryTemperaturePath =
+ android::String8(c.batteryTemperaturePath.c_str(),
+ c.batteryTemperaturePath.size());
+
+ hc->batteryTechnologyPath =
+ android::String8(c.batteryTechnologyPath.c_str(),
+ c.batteryTechnologyPath.size());
+
+ hc->batteryCurrentNowPath =
+ android::String8(c.batteryCurrentNowPath.c_str(),
+ c.batteryCurrentNowPath.size());
+
+ hc->batteryCurrentAvgPath =
+ android::String8(c.batteryCurrentAvgPath.c_str(),
+ c.batteryCurrentNowPath.size());
+
+ hc->batteryChargeCounterPath =
+ android::String8(c.batteryChargeCounterPath.c_str(),
+ c.batteryChargeCounterPath.size());
+
+ hc->batteryFullChargePath =
+ android::String8(c.batteryFullChargePath.c_str(),
+ c.batteryFullChargePath.size());
+
+ hc->batteryCycleCountPath =
+ android::String8(c.batteryCycleCountPath.c_str(),
+ c.batteryCycleCountPath.size());
+
+ // energyCounter is handled through special means so all calls to
+ // the function go across the HALs
+
+ // boot_min_cap - never used in Android (only in charger-mode).
+
+ // screen_on - never used in Android (only in charger mode).
+}
+
+void convertToHealthInfo(const struct android::BatteryProperties *p,
+ HealthInfo& info) {
+ info.chargerAcOnline = p->chargerAcOnline;
+ info.chargerUsbOnline = p->chargerUsbOnline;
+ info.chargerWirelessOnline = p->chargerWirelessOnline;
+ info.maxChargingCurrent = p->maxChargingCurrent;
+ info.maxChargingVoltage = p->maxChargingVoltage;
+ info.batteryStatus = static_cast<BatteryStatus>(p->batteryStatus);
+ info.batteryHealth = static_cast<BatteryHealth>(p->batteryHealth);
+ info.batteryPresent = p->batteryPresent;
+ info.batteryLevel = p->batteryLevel;
+ info.batteryVoltage = p->batteryVoltage;
+ info.batteryTemperature = p->batteryTemperature;
+ info.batteryCurrent = p->batteryCurrent;
+ info.batteryCycleCount = p->batteryCycleCount;
+ info.batteryFullCharge = p->batteryFullCharge;
+ info.batteryChargeCounter = p->batteryChargeCounter;
+ info.batteryTechnology = p->batteryTechnology;
+}
+
+void convertFromHealthInfo(const HealthInfo& info,
+ struct android::BatteryProperties *p) {
+ p->chargerAcOnline = info.chargerAcOnline;
+ p->chargerUsbOnline = info.chargerUsbOnline;
+ p->chargerWirelessOnline = info.chargerWirelessOnline;
+ p->maxChargingCurrent = info.maxChargingCurrent;
+ p->maxChargingVoltage = info.maxChargingVoltage;
+ p->batteryStatus = static_cast<int>(info.batteryStatus);
+ p->batteryHealth = static_cast<int>(info.batteryHealth);
+ p->batteryPresent = info.batteryPresent;
+ p->batteryLevel = info.batteryLevel;
+ p->batteryVoltage = info.batteryVoltage;
+ p->batteryTemperature = info.batteryTemperature;
+ p->batteryCurrent = info.batteryCurrent;
+ p->batteryCycleCount = info.batteryCycleCount;
+ p->batteryFullCharge = info.batteryFullCharge;
+ p->batteryChargeCounter = info.batteryChargeCounter;
+ p->batteryTechnology = android::String8(info.batteryTechnology.c_str());
+}
+
+} // namespace hal_conversion
+} // namespace V1_0
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/1.0/default/include/hal_conversion.h b/health/1.0/default/include/hal_conversion.h
new file mode 100644
index 0000000..a92b208
--- /dev/null
+++ b/health/1.0/default/include/hal_conversion.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_
+#define HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <healthd/healthd.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V1_0 {
+namespace hal_conversion {
+
+void convertToHealthConfig(const struct healthd_config *hc,
+ HealthConfig& config);
+void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc);
+
+void convertToHealthInfo(const struct android::BatteryProperties *p,
+ HealthInfo& info);
+void convertFromHealthInfo(const HealthInfo& info,
+ struct android::BatteryProperties *p);
+
+} // namespace hal_conversion
+} // namespace V1_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_
diff --git a/health/1.0/default/libhealthd/Android.mk b/health/1.0/default/libhealthd/Android.mk
new file mode 100644
index 0000000..a5f4445
--- /dev/null
+++ b/health/1.0/default/libhealthd/Android.mk
@@ -0,0 +1,10 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := healthd_board_default.cpp
+LOCAL_MODULE := libhealthd.default
+LOCAL_CFLAGS := -Werror
+LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include
+include $(BUILD_STATIC_LIBRARY)
diff --git a/health/1.0/default/libhealthd/healthd_board_default.cpp b/health/1.0/default/libhealthd/healthd_board_default.cpp
new file mode 100644
index 0000000..127f98e
--- /dev/null
+++ b/health/1.0/default/libhealthd/healthd_board_default.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <healthd/healthd.h>
+
+void healthd_board_init(struct healthd_config*)
+{
+ // use defaults
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties*)
+{
+ // return 0 to log periodic polled battery status to kernel log
+ return 0;
+}
diff --git a/health/1.0/types.hal b/health/1.0/types.hal
new file mode 100644
index 0000000..c5b5cc1
--- /dev/null
+++ b/health/1.0/types.hal
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2016 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.health@1.0;
+
+/*
+ * Possible return values for optional HAL method(s) like
+ * IHealth::energyCounter()
+ */
+enum Result : int32_t {
+ SUCCESS,
+ NOT_SUPPORTED,
+ UNKNOWN,
+};
+
+/*
+ * Possible values for Battery Status.
+ * Note: These are currently in sync with BatteryManager and must not
+ * be extended / altered.
+ */
+@export(name="", value_prefix="BATTERY_STATUS_")
+enum BatteryStatus : int32_t {
+ UNKNOWN = 1,
+ CHARGING = 2,
+ DISCHARGING = 3,
+ /*
+ * Battery is *not* charging - special case when charger is present
+ * but battery isn't charging
+ */
+ NOT_CHARGING = 4,
+ FULL = 5,
+};
+
+/*
+ * Possible values for Battery Health.
+ * Note: These are currently in sync with BatteryManager and must not
+ * be extended / altered.
+ */
+@export(name="", value_prefix="BATTERY_HEALTH_")
+enum BatteryHealth : int32_t {
+ UNKNOWN = 1,
+ GOOD = 2,
+ OVERHEAT = 3,
+ DEAD = 4,
+ OVER_VOLTAGE = 5,
+ /*
+ * Battery experienced an unknown/unspecifid failure.
+ */
+ UNSPECIFIED_FAILURE = 6,
+ COLD = 7,
+};
+
+struct HealthConfig {
+
+ /*
+ * periodicChoresIntervalFast is used while the device is not in
+ * suspend, or in suspend and connected to a charger (to watch for battery
+ * overheat due to charging)
+ */
+ int32_t periodicChoresIntervalFast;
+
+ /*
+ * periodicChoresIntervalSlow is used when the device is in suspend and
+ * not connected to a charger (to watch for a battery drained to zero
+ * remaining capacity).
+ */
+ int32_t periodicChoresIntervalSlow;
+
+ /*
+ * power_supply sysfs attribute file paths. Set these to specific paths
+ * to use for the associated battery parameters. Clients must search
+ * for appropriate power_supply attribute files to use, for any paths
+ * left empty after the HAL is initialized.
+ */
+
+ /*
+ * batteryStatusPath - file path to read battery charging status.
+ * (POWER_SUPPLY_PROP_STATUS)
+ */
+ string batteryStatusPath;
+
+
+ /*
+ * batteryHealthPath - file path to read battery health.
+ * (POWER_SUPPLY_PROP_HEALTH)
+ */
+ string batteryHealthPath;
+
+ /*
+ * batteryPresentPath - file path to read battery present status.
+ * (POWER_SUPPLY_PROP_PRESENT)
+ */
+ string batteryPresentPath;
+
+
+ /*
+ * batteryCapacityPath - file path to read remaining battery capacity.
+ * (POWER_SUPPLY_PROP_CAPACITY)
+ */
+ string batteryCapacityPath;
+
+ /*
+ * batteryVoltagePath - file path to read battery voltage.
+ * (POWER_SUPPLY_PROP_VOLTAGE_NOW)
+ */
+ string batteryVoltagePath;
+
+ /*
+ * batteryTemperaturePath - file path to read battery temperature in tenths
+ * of degree celcius. (POWER_SUPPLY_PROP_TEMP)
+ */
+ string batteryTemperaturePath;
+
+ /*
+ * batteryTechnologyPath - file path to read battery technology.
+ * (POWER_SUPPLY_PROP_TECHNOLOGY)
+ */
+ string batteryTechnologyPath;
+
+ /*
+ * batteryCurrentNowPath - file path to read battery instantaneous current.
+ * (POWER_SUPPLY_PROP_CURRENT_NOW)
+ */
+ string batteryCurrentNowPath;
+
+ /*
+ * batteryCurrentAvgPath - file path to read battery average current.
+ * (POWER_SUPPLY_PROP_CURRENT_AVG)
+ */
+ string batteryCurrentAvgPath;
+
+ /*
+ * batteryChargeCounterPath - file path to read battery accumulated charge.
+ * (POWER_SUPPLY_PROP_CHARGE_COUNTER)
+ */
+ string batteryChargeCounterPath;
+
+ /*
+ * batteryFullChargerPath - file path to read battery charge value when it
+ * is considered to be full. (POWER_SUPPLY_PROP_CHARGE_FULL)
+ */
+ string batteryFullChargePath;
+
+ /*
+ * batteryCycleCountPath - file path to read battery charge cycle count.
+ * (POWER_SUPPLY_PROP_CYCLE_COUNT)
+ */
+ string batteryCycleCountPath;
+};
+
+/*
+ * The parameter to healthd mainloop update calls
+ */
+struct HealthInfo {
+ /* AC charger state - 'true' if online */
+ bool chargerAcOnline;
+
+ /* USB charger state - 'true' if online */
+ bool chargerUsbOnline;
+
+ /* Wireless charger state - 'true' if online */
+ bool chargerWirelessOnline;
+
+ /* Maximum charging current supported by charger in uA */
+ int32_t maxChargingCurrent;
+
+ /* Maximum charging voltage supported by charger in uV */
+ int32_t maxChargingVoltage;
+
+ BatteryStatus batteryStatus;
+
+ BatteryHealth batteryHealth;
+
+ /* 'true' if battery is present */
+ bool batteryPresent;
+
+ /* Remaining battery capacity in percent */
+ int32_t batteryLevel;
+
+ /* Instantaneous battery voltage in uV */
+ int32_t batteryVoltage;
+
+ /* Instantaneous battery temperature in tenths of degree celcius */
+ int32_t batteryTemperature;
+
+ /* Instantaneous battery current in uA */
+ int32_t batteryCurrent;
+
+ /* Battery charge cycle count */
+ int32_t batteryCycleCount;
+
+ /* Battery charge value when it is considered to be "full" in uA-h */
+ int32_t batteryFullCharge;
+
+ /* Instantaneous battery capacity in uA-h */
+ int32_t batteryChargeCounter;
+
+ /* Battery technology, e.g. "Li-ion, Li-Poly" etc. */
+ string batteryTechnology;
+};
diff --git a/health/Android.bp b/health/Android.bp
new file mode 100644
index 0000000..bbb3e4b
--- /dev/null
+++ b/health/Android.bp
@@ -0,0 +1,4 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+]
diff --git a/keymaster/3.0/Android.bp b/keymaster/3.0/Android.bp
new file mode 100644
index 0000000..074bb68
--- /dev/null
+++ b/keymaster/3.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.keymaster@3.0_hal",
+ srcs: [
+ "types.hal",
+ "IKeymasterDevice.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.keymaster@3.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.keymaster@3.0",
+ srcs: [
+ ":android.hardware.keymaster@3.0_hal",
+ ],
+ out: [
+ "android/hardware/keymaster/3.0/types.cpp",
+ "android/hardware/keymaster/3.0/KeymasterDeviceAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.keymaster@3.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.keymaster@3.0",
+ srcs: [
+ ":android.hardware.keymaster@3.0_hal",
+ ],
+ out: [
+ "android/hardware/keymaster/3.0/types.h",
+ "android/hardware/keymaster/3.0/IKeymasterDevice.h",
+ "android/hardware/keymaster/3.0/IHwKeymasterDevice.h",
+ "android/hardware/keymaster/3.0/BnHwKeymasterDevice.h",
+ "android/hardware/keymaster/3.0/BpHwKeymasterDevice.h",
+ "android/hardware/keymaster/3.0/BsKeymasterDevice.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.keymaster@3.0",
+ generated_sources: ["android.hardware.keymaster@3.0_genc++"],
+ generated_headers: ["android.hardware.keymaster@3.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.keymaster@3.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/keymaster/3.0/IKeymasterDevice.hal b/keymaster/3.0/IKeymasterDevice.hal
new file mode 100644
index 0000000..50a41ec
--- /dev/null
+++ b/keymaster/3.0/IKeymasterDevice.hal
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2016 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.keymaster@3.0;
+
+/**
+ * Keymaster device definition. For thorough documentation see the implementer's reference, at
+ * https://source.android.com/security/keystore/implementer-ref.html
+ */
+interface IKeymasterDevice {
+
+ /**
+ * Returns information about the underlying keymaster hardware.
+ *
+ * @return isSecure is true if keys are stored and never leave secure hardware (Trusted
+ * Execution Environment or similar). CDD requires that all devices initially
+ * launched with Marshmallow or later must have secure hardware.
+ *
+ * @return supportsEllipticCurve is true if the hardware supports Elliptic Curve cryptography
+ * with the NIST curves (P-224, P-256, P-384, and P-521). CDD requires that all
+ * devices initially launched with Nougat or later must support Elliptic Curve
+ * cryptography.
+ *
+ * @return supportsSymmetricCryptography is true if the hardware supports symmetric
+ * cryptography, including AES and HMAC. CDD requires that all devices initially
+ * launched with Nougat or later must support hardware enforcement of Keymaster
+ * authorizations.
+ *
+ * @return supportsAttestation is true if the hardware supports generation of Keymaster public
+ * key attestation certificates, signed with a key injected in a secure
+ * environment. CDD requires that all devices initially launched with Android O or
+ * later must support hardware attestation.
+ */
+ getHardwareFeatures()
+ generates(bool isSecure, bool supportsEllipticCurve,
+ bool supportsSymmetricCryptography, bool supportsAttestation);
+
+ /**
+ * Adds entropy to the RNG used by keymaster. Entropy added through this method is guaranteed
+ * not to be the only source of entropy used, and the mixing function is required to be secure,
+ * in the sense that if the RNG is seeded (from any source) with any data the attacker cannot
+ * predict (or control), then the RNG output is indistinguishable from random. Thus, if the
+ * entropy from any source is good, the output must be good.
+ *
+ * @param data Bytes to be mixed into the RNG.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ */
+ addRngEntropy(vec<uint8_t> data) generates(ErrorCode error);
+
+ /**
+ * Generates a key, or key pair, returning a key blob and/or a description of the key.
+ *
+ * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+ * in params. See Tag in types.hal for the full list.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyBlob Opaque, encrypted descriptor of the generated key, which generally contains a
+ * copy of the key material, wrapped in a key unavailable outside secure hardware.
+ *
+ * @return keyCharacteristics Description of the generated key. See KeyCharacteristis in
+ * types.hal.
+ */
+ generateKey(vec<KeyParameter> keyParams)
+ generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Imports a key, or key pair, returning a key blob and/or a description of the key.
+ *
+ * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+ * in params. See Tag for the full list.
+ *
+ * @param keyFormat The format of the key material to import. See KeyFormat in types.hal.
+ *
+ * @pram keyData The key material to import, in the format specifed in keyFormat.
+ *
+ * @return error See the ErrorCode enum.
+ *
+ * @return keyBlob Opaque, encrypted descriptor of the generated key, which will generally
+ * contain a copy of the key material, wrapped in a key unavailable outside secure
+ * hardware.
+ *
+ * @return keyCharacteristics Decription of the generated key. See KeyCharacteristis.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ importKey(vec<KeyParameter> params, KeyFormat keyFormat, vec<uint8_t> keyData)
+ generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Returns the characteristics of the specified key, if the keyBlob is valid (implementations
+ * must fully validate the integrity of the key).
+ *
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @param clientId An opaque byte string identifying the client. This value must match the
+ * Tag::APPLICATION_ID data provided during key generation/import. Without the
+ * correct value it must be cryptographically impossible for the secure hardware to
+ * obtain the key material.
+ *
+ * @param appData An opaque byte string provided by the application. This value must match the
+ * Tag::APPLICATION_DATA data provided during key generation/import. Without the
+ * correct value it must be cryptographically impossible for the secure hardware to
+ * obtain the key material.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyCharacteristics Decription of the generated key. See KeyCharacteristis in
+ * types.hal.
+ */
+ getKeyCharacteristics(vec<uint8_t> keyBlob, vec<uint8_t> clientId, vec<uint8_t> appData)
+ generates(ErrorCode error, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Exports a public key, returning the key in the specified format.
+ *
+ * @parm keyFormat The format used for export. See KeyFormat in types.hal.
+ *
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey(). The
+ * referenced key must be asymmetric.
+ *
+ * @param clientId An opaque byte string identifying the client. This value must match the
+ * Tag::APPLICATION_ID data provided during key generation/import. Without the
+ * correct value it must be cryptographically impossible for the secure hardware to
+ * obtain the key material.
+ *
+ * @param appData An opaque byte string provided by the application. This value must match the
+ * Tag::APPLICATION_DATA data provided during key generation/import. Without the
+ * correct value it must be cryptographically impossible for the secure hardware to
+ * obtain the key material.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyMaterial The public key material in PKCS#8 format.
+ */
+ exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId,
+ vec<uint8_t> appData) generates(ErrorCode error, vec<uint8_t> keyMaterial);
+
+ /**
+ * Generates a signed X.509 certificate chain attesting to the presence of keyToAttest in
+ * keymaster. The certificate will contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and
+ * value defined in:
+ *
+ * https://developer.android.com/training/articles/security-key-attestation.html.
+ *
+ * @param keyToAttest The opaque descriptor returned by generateKey() or importKey(). The
+ * referenced key must be asymmetric.
+ *
+ * @param attestParams Parameters for the attestation, notably Tag::ATTESTATION_CHALLENGE.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ */
+ attestKey(vec<uint8_t> keyToAttest, vec<KeyParameter> attestParams)
+ generates(ErrorCode error, vec<vec<uint8_t>> certChain);
+
+ /**
+ * Upgrades an old key. Keys can become "old" in two ways: Keymaster can be upgraded to a new
+ * version, or the system can be updated to invalidate the OS version and/or patch level. In
+ * either case, attempts to use an old key with getKeyCharacteristics(), exportKey(),
+ * attestKey() or begin() will result in keymaster returning
+ * ErrorCode::KEY_REQUIRES_UPGRADE. This method must then be called to upgrade the key.
+ *
+ * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @param upgradeParams A parameter list containing any parameters needed to complete the
+ * upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ upgradeKey(vec<uint8_t> keyBlobToUpgrade, vec<KeyParameter> upgradeParams)
+ generates(ErrorCode error, vec<uint8_t> upgradedKeyBlob);
+
+ /**
+ * Deletes the key, or key pair, associated with the key blob. After calling this function it
+ * will be impossible to use the key for any other operations. May be applied to keys from
+ * foreign roots of trust (keys not usable under the current root of trust).
+ *
+ * This is a NOP for keys that don't have rollback protection.
+ *
+ * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @return error See the ErrorCode enum.
+ */
+ deleteKey(vec<uint8_t> keyBlob) generates(ErrorCode error);
+
+ /**
+ * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
+ * calling this function it will be impossible to use any previously generated or imported key
+ * blobs for any operations.
+ *
+ * This is a NOP if keys don't have rollback protection.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ deleteAllKeys() generates(ErrorCode error);
+
+ /**
+ * Destroys knowledge of the device's ids. This prevents all device id attestation in the
+ * future. The destruction must be permanent so that not even a factory reset will restore the
+ * device ids.
+ *
+ * Device id attestation may be provided only if this method is fully implemented, allowing the
+ * user to permanently disable device id attestation. If this cannot be guaranteed, the device
+ * must never attest any device ids.
+ *
+ * This is a NOP if device id attestation is not supported.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ destroyAttestationIds() generates(ErrorCode error);
+
+ /**
+ * Begins a cryptographic operation using the specified key. If all is well, begin() will return
+ * ErrorCode::OK and create an operation handle which must be passed to subsequent calls to
+ * update(), finish() or abort().
+ *
+ * It is critical that each call to begin() be paired with a subsequent call to finish() or
+ * abort(), to allow the keymaster implementation to clean up any internal operation state.
+ * Failure to do this may leak internal state space or other internal resources and may
+ * eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space
+ * for operations. Any result other than ErrorCode::OK from begin(), update() or finish()
+ * implicitly aborts the operation, in which case abort() need not be called (and will return
+ * ErrorCode::INVALID_OPERATION_HANDLE if called).
+ *
+ * @param purpose The purpose of the operation, one of KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT,
+ * KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD modes, encryption and
+ * decryption imply signing and verification, respectively, but must be specified as
+ * KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+ *
+ * @param keyBlob The opaque key descriptor returned by generateKey() or importKey(). The key
+ * must have a purpose compatible with purpose and all of its usage requirements
+ * must be satisfied, or begin() will return an appropriate error code.
+ *
+ * @param inParams Additional parameters for the operation. This is typically used to provide
+ * authentication data, with Tag::AUTH_TOKEN. If Tag::APPLICATION_ID or
+ * Tag::APPLICATION_DATA were provided during generation, they must be provided
+ * here, or the operation will fail with ErrorCode::INVALID_KEY_BLOB. For operations
+ * that require a nonce or IV, on keys that were generated with Tag::CALLER_NONCE,
+ * inParams may contain a tag Tag::NONCE.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return outParams Output parameters. Used to return additional data from the operation
+ * initialization, notably to return the IV or nonce from operations that generate
+ * an IV or nonce.
+ *
+ * @return operationHandle The newly-created operation handle which must be passed to update(),
+ * finish() or abort().
+ */
+ begin(KeyPurpose purpose, vec<uint8_t> key, vec<KeyParameter> inParams)
+ generates(ErrorCode error, vec<KeyParameter> outParams, OperationHandle operationHandle);
+
+ /**
+ * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
+ * with begin().
+ *
+ * If operationHandle is invalid, update() will return ErrorCode::INVALID_OPERATION_HANDLE.
+ *
+ * update() may not consume all of the data provided in the data buffer. update() will return
+ * the amount consumed in inputConsumed. The caller may provide the unconsumed data in a
+ * subsequent call.
+ *
+ * @param operationHandle The operation handle returned by begin().
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA. Note that additional data may be provided in
+ * multiple calls to update(), but only until input data has been provided.
+ *
+ * @param input Data to be processed, per the parameters established in the call to begin().
+ * Note that update() may or may not consume all of the data provided. See
+ * inputConsumed.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return inputConsumed Amount of data that was consumed by update(). If this is less than the
+ * amount provided, the caller may provide the remainder in a subsequent call to
+ * update() or finish().
+ *
+ * @return outParams Output parameters, used to return additional data from the operation The
+ * caller takes ownership of the output parameters array and must free it with
+ * keymaster_free_param_set().
+ *
+ * @return output The output data, if any.
+ */
+ update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input)
+ generates(ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams,
+ vec<uint8_t> output);
+
+ /**
+ * Finalizes a cryptographic operation begun with begin() and invalidates operationHandle.
+ *
+ * @param operationHandle The operation handle returned by begin(). This handle will be
+ * invalid when finish() returns.
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update().
+ *
+ * @param input Data to be processed, per the parameters established in the call to
+ * begin(). finish() must consume all provided data or return
+ * ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * @param signature The signature to be verified if the purpose specified in the begin() call
+ * was KeyPurpose::VERIFY.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return outParams Any output parameters generated by finish().
+ *
+ * @return output The output data, if any.
+ */
+ finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
+ vec<uint8_t> signature)
+ generates(ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output);
+
+ /**
+ * Aborts a cryptographic operation begun with begin(), freeing all internal resources and
+ * invalidating operationHandle.
+ *
+ * @param operationHandle The operation handle returned by begin(). This handle will be
+ * invalid when abort() returns.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ */
+ abort(OperationHandle operationHandle) generates(ErrorCode error);
+};
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
new file mode 100644
index 0000000..c537346
--- /dev/null
+++ b/keymaster/3.0/default/Android.mk
@@ -0,0 +1,43 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.keymaster@3.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ KeymasterDevice.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libsoftkeymasterdevice \
+ libcrypto \
+ libkeymaster1 \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ libhardware \
+ android.hardware.keymaster@3.0
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.keymaster@3.0-service
+LOCAL_INIT_RC := android.hardware.keymaster@3.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.keymaster@3.0
+
+include $(BUILD_EXECUTABLE)
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
new file mode 100644
index 0000000..01f0795
--- /dev/null
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -0,0 +1,722 @@
+/*
+ **
+ ** Copyright 2016, 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.
+ */
+
+#define LOG_TAG "android.hardware.keymaster@3.0-impl"
+
+#include "KeymasterDevice.h"
+
+#include <cutils/log.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_configuration.h>
+#include <keymaster/soft_keymaster_device.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+namespace implementation {
+
+using ::keymaster::SoftKeymasterDevice;
+
+class SoftwareOnlyHidlKeymasterEnforcement : public ::keymaster::KeymasterEnforcement {
+ public:
+ SoftwareOnlyHidlKeymasterEnforcement() : KeymasterEnforcement(64, 64) {}
+
+ uint32_t get_current_time() const override {
+ struct timespec tp;
+ int err = clock_gettime(CLOCK_MONOTONIC, &tp);
+ if (err || tp.tv_sec < 0) return 0;
+ return static_cast<uint32_t>(tp.tv_sec);
+ }
+
+ bool activation_date_valid(uint64_t) const override { return true; }
+ bool expiration_date_passed(uint64_t) const override { return false; }
+ bool auth_token_timed_out(const hw_auth_token_t&, uint32_t) const override { return false; }
+ bool ValidateTokenSignature(const hw_auth_token_t&) const override { return true; }
+};
+
+class SoftwareOnlyHidlKeymasterContext : public ::keymaster::SoftKeymasterContext {
+ public:
+ SoftwareOnlyHidlKeymasterContext() : enforcement_(new SoftwareOnlyHidlKeymasterEnforcement) {}
+
+ ::keymaster::KeymasterEnforcement* enforcement_policy() override { return enforcement_.get(); }
+
+ private:
+ std::unique_ptr<::keymaster::KeymasterEnforcement> enforcement_;
+};
+
+static int keymaster0_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
+ assert(mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0);
+ ALOGI("Found keymaster0 module %s, version %x", mod->name, mod->module_api_version);
+
+ UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
+ keymaster0_device_t* km0_device = NULL;
+ keymaster_error_t error = KM_ERROR_OK;
+
+ int rc = keymaster0_open(mod, &km0_device);
+ if (rc) {
+ ALOGE("Error opening keystore keymaster0 device.");
+ goto err;
+ }
+
+ if (km0_device->flags & KEYMASTER_SOFTWARE_ONLY) {
+ ALOGI("Keymaster0 module is software-only. Using SoftKeymasterDevice instead.");
+ km0_device->common.close(&km0_device->common);
+ km0_device = NULL;
+ // SoftKeymasterDevice will be deleted by keymaster_device_release()
+ *dev = soft_keymaster.release()->keymaster2_device();
+ return 0;
+ }
+
+ ALOGD("Wrapping keymaster0 module %s with SoftKeymasterDevice", mod->name);
+ error = soft_keymaster->SetHardwareDevice(km0_device);
+ km0_device = NULL; // SoftKeymasterDevice has taken ownership.
+ if (error != KM_ERROR_OK) {
+ ALOGE("Got error %d from SetHardwareDevice", error);
+ rc = error;
+ goto err;
+ }
+
+ // SoftKeymasterDevice will be deleted by keymaster_device_release()
+ *dev = soft_keymaster.release()->keymaster2_device();
+ return 0;
+
+err:
+ if (km0_device) km0_device->common.close(&km0_device->common);
+ *dev = NULL;
+ return rc;
+}
+
+static int keymaster1_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
+ assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0);
+ ALOGI("Found keymaster1 module %s, version %x", mod->name, mod->module_api_version);
+
+ UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
+ keymaster1_device_t* km1_device = nullptr;
+ keymaster_error_t error = KM_ERROR_OK;
+
+ int rc = keymaster1_open(mod, &km1_device);
+ if (rc) {
+ ALOGE("Error %d opening keystore keymaster1 device", rc);
+ goto err;
+ }
+
+ ALOGD("Wrapping keymaster1 module %s with SofKeymasterDevice", mod->name);
+ error = soft_keymaster->SetHardwareDevice(km1_device);
+ km1_device = nullptr; // SoftKeymasterDevice has taken ownership.
+ if (error != KM_ERROR_OK) {
+ ALOGE("Got error %d from SetHardwareDevice", error);
+ rc = error;
+ goto err;
+ }
+
+ // SoftKeymasterDevice will be deleted by keymaster_device_release()
+ *dev = soft_keymaster.release()->keymaster2_device();
+ return 0;
+
+err:
+ if (km1_device) km1_device->common.close(&km1_device->common);
+ *dev = NULL;
+ return rc;
+}
+
+static int keymaster2_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
+ assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0);
+ ALOGI("Found keymaster2 module %s, version %x", mod->name, mod->module_api_version);
+
+ keymaster2_device_t* km2_device = nullptr;
+
+ int rc = keymaster2_open(mod, &km2_device);
+ if (rc) {
+ ALOGE("Error %d opening keystore keymaster2 device", rc);
+ goto err;
+ }
+
+ *dev = km2_device;
+ return 0;
+
+err:
+ if (km2_device) km2_device->common.close(&km2_device->common);
+ *dev = nullptr;
+ return rc;
+}
+
+static int keymaster_device_initialize(keymaster2_device_t** dev, uint32_t* version,
+ bool* supports_ec) {
+ const hw_module_t* mod;
+
+ *supports_ec = true;
+
+ int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
+ if (rc) {
+ ALOGI("Could not find any keystore module, using software-only implementation.");
+ // SoftKeymasterDevice will be deleted by keymaster_device_release()
+ *dev = (new SoftKeymasterDevice(new SoftwareOnlyHidlKeymasterContext))->keymaster2_device();
+ *version = -1;
+ return 0;
+ }
+
+ if (mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0) {
+ *version = 0;
+ int rc = keymaster0_device_initialize(mod, dev);
+ if (rc == 0 && ((*dev)->flags & KEYMASTER_SUPPORTS_EC) == 0) {
+ *supports_ec = false;
+ }
+ return rc;
+ } else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
+ *version = 1;
+ return keymaster1_device_initialize(mod, dev);
+ } else {
+ *version = 2;
+ return keymaster2_device_initialize(mod, dev);
+ }
+}
+
+KeymasterDevice::~KeymasterDevice() {
+ if (keymaster_device_) keymaster_device_->common.close(&keymaster_device_->common);
+}
+
+static inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+ return keymaster_tag_get_type(tag);
+}
+
+/**
+ * legacy_enum_conversion converts enums from hidl to keymaster and back. Currently, this is just a
+ * cast to make the compiler happy. One of two thigs should happen though:
+ * TODO The keymaster enums should become aliases for the hidl generated enums so that we have a
+ * single point of truth. Then this cast function can go away.
+ */
+inline static keymaster_tag_t legacy_enum_conversion(const Tag value) {
+ return keymaster_tag_t(value);
+}
+inline static Tag legacy_enum_conversion(const keymaster_tag_t value) {
+ return Tag(value);
+}
+inline static keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+ return keymaster_purpose_t(value);
+}
+inline static keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+ return keymaster_key_format_t(value);
+}
+inline static ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+ return ErrorCode(value);
+}
+
+class KmParamSet : public keymaster_key_param_set_t {
+ public:
+ KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+ params = new keymaster_key_param_t[keyParams.size()];
+ length = keyParams.size();
+ for (size_t i = 0; i < keyParams.size(); ++i) {
+ auto tag = legacy_enum_conversion(keyParams[i].tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+ break;
+ case KM_DATE:
+ params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+ break;
+ case KM_BOOL:
+ if (keyParams[i].f.boolValue)
+ params[i] = keymaster_param_bool(tag);
+ else
+ params[i].tag = KM_TAG_INVALID;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ params[i] =
+ keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size());
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ }
+ KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+ other.length = 0;
+ other.params = nullptr;
+ }
+ KmParamSet(const KmParamSet&) = delete;
+ ~KmParamSet() { delete[] params; }
+};
+
+inline static KmParamSet hidlParams2KmParamSet(const hidl_vec<KeyParameter>& params) {
+ return KmParamSet(params);
+}
+
+inline static keymaster_blob_t hidlVec2KmBlob(const hidl_vec<uint8_t>& blob) {
+ /* hidl unmarshals funny pointers if the the blob is empty */
+ if (blob.size()) return {&blob[0], blob.size()};
+ return {nullptr, 0};
+}
+
+inline static keymaster_key_blob_t hidlVec2KmKeyBlob(const hidl_vec<uint8_t>& blob) {
+ /* hidl unmarshals funny pointers if the the blob is empty */
+ if (blob.size()) return {&blob[0], blob.size()};
+ return {nullptr, 0};
+}
+
+inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
+ return result;
+}
+inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
+ return result;
+}
+
+inline static hidl_vec<hidl_vec<uint8_t>>
+kmCertChain2Hidl(const keymaster_cert_chain_t* cert_chain) {
+ hidl_vec<hidl_vec<uint8_t>> result;
+ if (!cert_chain || cert_chain->entry_count == 0 || !cert_chain->entries) return result;
+
+ result.resize(cert_chain->entry_count);
+ for (size_t i = 0; i < cert_chain->entry_count; ++i) {
+ auto& entry = cert_chain->entries[i];
+ result[i] = kmBlob2hidlVec(entry);
+ }
+
+ return result;
+}
+
+static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
+ hidl_vec<KeyParameter> result;
+ if (set.length == 0 || set.params == nullptr) return result;
+
+ result.resize(set.length);
+ keymaster_key_param_t* params = set.params;
+ for (size_t i = 0; i < set.length; ++i) {
+ auto tag = params[i].tag;
+ result[i].tag = legacy_enum_conversion(tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ result[i].f.integer = params[i].enumerated;
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ result[i].f.integer = params[i].integer;
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ result[i].f.longInteger = params[i].long_integer;
+ break;
+ case KM_DATE:
+ result[i].f.dateTime = params[i].date_time;
+ break;
+ case KM_BOOL:
+ result[i].f.boolValue = params[i].boolean;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
+ params[i].blob.data_length);
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ return result;
+}
+
+// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
+Return<void> KeymasterDevice::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) {
+ bool is_secure = false;
+ bool supports_symmetric_cryptography = false;
+ bool supports_attestation = false;
+
+ switch (hardware_version_) {
+ case 2:
+ supports_attestation = true;
+ /* Falls through */
+ case 1:
+ supports_symmetric_cryptography = true;
+ /* Falls through */
+ case 0:
+ is_secure = true;
+ break;
+ };
+
+ _hidl_cb(is_secure, hardware_supports_ec_, supports_symmetric_cryptography,
+ supports_attestation);
+ return Void();
+}
+
+Return<ErrorCode> KeymasterDevice::addRngEntropy(const hidl_vec<uint8_t>& data) {
+ if (!data.size()) return ErrorCode::OK;
+ return legacy_enum_conversion(
+ keymaster_device_->add_rng_entropy(keymaster_device_, &data[0], data.size()));
+}
+
+Return<void> KeymasterDevice::generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob{nullptr, 0};
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ // convert the parameter set to something our backend understands
+ auto kmParams = hidlParams2KmParamSet(keyParams);
+
+ auto rc = keymaster_device_->generate_key(keymaster_device_, &kmParams, &key_blob,
+ &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ // send results off to the client
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
+
+ // free buffers that we are responsible for
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+
+ // result variables the backend understands
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ auto kmClientId = hidlVec2KmBlob(clientId);
+ auto kmAppData = hidlVec2KmBlob(appData);
+
+ auto rc = keymaster_device_->get_key_characteristics(
+ keymaster_device_, keyBlob.size() ? &kmKeyBlob : nullptr,
+ clientId.size() ? &kmClientId : nullptr, appData.size() ? &kmAppData : nullptr,
+ &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultCharacteristics);
+
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob{nullptr, 0};
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ auto kmParams = hidlParams2KmParamSet(params);
+ auto kmKeyData = hidlVec2KmBlob(keyData);
+
+ auto rc = keymaster_device_->import_key(keymaster_device_, &kmParams,
+ legacy_enum_conversion(keyFormat), &kmKeyData,
+ &key_blob, &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?)
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
+
+ // free buffers that we are responsible for
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_blob_t out_blob{nullptr, 0};
+
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ auto kmClientId = hidlVec2KmBlob(clientId);
+ auto kmAppData = hidlVec2KmBlob(appData);
+
+ auto rc = keymaster_device_->export_key(keymaster_device_, legacy_enum_conversion(exportFormat),
+ keyBlob.size() ? &kmKeyBlob : nullptr,
+ clientId.size() ? &kmClientId : nullptr,
+ appData.size() ? &kmAppData : nullptr, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?)
+ resultKeyBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
+
+ // free buffers that we are responsible for
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) {
+
+ hidl_vec<hidl_vec<uint8_t>> resultCertChain;
+
+ for (size_t i = 0; i < attestParams.size(); ++i) {
+ switch (attestParams[i].tag) {
+ case Tag::ATTESTATION_ID_BRAND:
+ case Tag::ATTESTATION_ID_DEVICE:
+ case Tag::ATTESTATION_ID_PRODUCT:
+ case Tag::ATTESTATION_ID_SERIAL:
+ case Tag::ATTESTATION_ID_IMEI:
+ case Tag::ATTESTATION_ID_MEID:
+ case Tag::ATTESTATION_ID_MANUFACTURER:
+ case Tag::ATTESTATION_ID_MODEL:
+ // Device id attestation may only be supported if the device is able to permanently
+ // destroy its knowledge of the ids. This device is unable to do this, so it must
+ // never perform any device id attestation.
+ _hidl_cb(ErrorCode::CANNOT_ATTEST_IDS, resultCertChain);
+ return Void();
+ default:
+ break;
+ }
+ }
+
+ keymaster_cert_chain_t cert_chain{nullptr, 0};
+
+ auto kmKeyToAttest = hidlVec2KmKeyBlob(keyToAttest);
+ auto kmAttestParams = hidlParams2KmParamSet(attestParams);
+
+ auto rc = keymaster_device_->attest_key(keymaster_device_, &kmKeyToAttest, &kmAttestParams,
+ &cert_chain);
+
+ if (rc == KM_ERROR_OK) {
+ resultCertChain = kmCertChain2Hidl(&cert_chain);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultCertChain);
+
+ keymaster_free_cert_chain(&cert_chain);
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob{nullptr, 0};
+
+ auto kmKeyBlobToUpgrade = hidlVec2KmKeyBlob(keyBlobToUpgrade);
+ auto kmUpgradeParams = hidlParams2KmParamSet(upgradeParams);
+
+ auto rc = keymaster_device_->upgrade_key(keymaster_device_, &kmKeyBlobToUpgrade,
+ &kmUpgradeParams, &key_blob);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
+
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+
+ return Void();
+}
+
+Return<ErrorCode> KeymasterDevice::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+ if (keymaster_device_->delete_key == nullptr) {
+ return ErrorCode::UNIMPLEMENTED;
+ }
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ return legacy_enum_conversion(keymaster_device_->delete_key(keymaster_device_, &kmKeyBlob));
+}
+
+Return<ErrorCode> KeymasterDevice::deleteAllKeys() {
+ if (keymaster_device_->delete_all_keys == nullptr) {
+ return ErrorCode::UNIMPLEMENTED;
+ }
+ return legacy_enum_conversion(keymaster_device_->delete_all_keys(keymaster_device_));
+}
+
+Return<ErrorCode> KeymasterDevice::destroyAttestationIds() {
+ return ErrorCode::UNIMPLEMENTED;
+}
+
+Return<void> KeymasterDevice::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<KeyParameter> resultParams;
+ uint64_t resultOpHandle = 0;
+
+ // result variables the backend understands
+ keymaster_key_param_set_t out_params{nullptr, 0};
+ keymaster_operation_handle_t& operation_handle = resultOpHandle;
+
+ auto kmKey = hidlVec2KmKeyBlob(key);
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+
+ auto rc = keymaster_device_->begin(keymaster_device_, legacy_enum_conversion(purpose), &kmKey,
+ &kmInParams, &out_params, &operation_handle);
+
+ if (rc == KM_ERROR_OK) resultParams = kmParamSet2Hidl(out_params);
+
+ _hidl_cb(legacy_enum_conversion(rc), resultParams, resultOpHandle);
+
+ keymaster_free_param_set(&out_params);
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::update(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
+ // result variables for the wire
+ uint32_t resultConsumed = 0;
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+
+ // result variables the backend understands
+ size_t consumed = 0;
+ keymaster_key_param_set_t out_params{nullptr, 0};
+ keymaster_blob_t out_blob{nullptr, 0};
+
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+ auto kmInput = hidlVec2KmBlob(input);
+
+ auto rc = keymaster_device_->update(keymaster_device_, operationHandle, &kmInParams, &kmInput,
+ &consumed, &out_params, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ resultConsumed = consumed;
+ resultParams = kmParamSet2Hidl(out_params);
+ resultBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultConsumed, resultParams, resultBlob);
+
+ keymaster_free_param_set(&out_params);
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<void> KeymasterDevice::finish(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& signature, finish_cb _hidl_cb) {
+ // result variables for the wire
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+
+ // result variables the backend understands
+ keymaster_key_param_set_t out_params{nullptr, 0};
+ keymaster_blob_t out_blob{nullptr, 0};
+
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+ auto kmInput = hidlVec2KmBlob(input);
+ auto kmSignature = hidlVec2KmBlob(signature);
+
+ auto rc = keymaster_device_->finish(keymaster_device_, operationHandle, &kmInParams, &kmInput,
+ &kmSignature, &out_params, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ resultParams = kmParamSet2Hidl(out_params);
+ resultBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultParams, resultBlob);
+
+ keymaster_free_param_set(&out_params);
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<ErrorCode> KeymasterDevice::abort(uint64_t operationHandle) {
+ return legacy_enum_conversion(keymaster_device_->abort(keymaster_device_, operationHandle));
+}
+
+IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* /* name */) {
+ keymaster2_device_t* dev = nullptr;
+
+ uint32_t version;
+ bool supports_ec;
+ auto rc = keymaster_device_initialize(&dev, &version, &supports_ec);
+ if (rc) return nullptr;
+
+ auto kmrc = ::keymaster::ConfigureDevice(dev);
+ if (kmrc != KM_ERROR_OK) {
+ dev->common.close(&dev->common);
+ return nullptr;
+ }
+
+ return new KeymasterDevice(dev, version, supports_ec);
+}
+
+} // namespace implementation
+} // namespace V3_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/3.0/default/KeymasterDevice.h b/keymaster/3.0/default/KeymasterDevice.h
new file mode 100644
index 0000000..382f45f
--- /dev/null
+++ b/keymaster/3.0/default/KeymasterDevice.h
@@ -0,0 +1,98 @@
+/*
+ **
+ ** Copyright 2016, 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.
+ */
+
+#ifndef HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
+#define HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
+
+#include <hardware/keymaster2.h>
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V3_0 {
+namespace implementation {
+
+using ::android::hardware::keymaster::V3_0::ErrorCode;
+using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V3_0::KeyFormat;
+using ::android::hardware::keymaster::V3_0::KeyParameter;
+using ::android::hardware::keymaster::V3_0::KeyPurpose;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class KeymasterDevice : public IKeymasterDevice {
+ public:
+ KeymasterDevice(keymaster2_device_t* dev, uint32_t hardware_version, bool hardware_supports_ec)
+ : keymaster_device_(dev), hardware_version_(hardware_version),
+ hardware_supports_ec_(hardware_supports_ec) {}
+ virtual ~KeymasterDevice();
+
+ // Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
+ Return<void> getHardwareFeatures(getHardwareFeatures_cb _hidl_cb);
+ Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override;
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override;
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override;
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override;
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override;
+ Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<ErrorCode> deleteAllKeys() override;
+ Return<ErrorCode> destroyAttestationIds() override;
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) override;
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, update_cb _hidl_cb) override;
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ finish_cb _hidl_cb) override;
+ Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+ private:
+ keymaster2_device_t* keymaster_device_;
+ uint32_t hardware_version_;
+ bool hardware_supports_ec_;
+};
+
+extern "C" IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* name);
+
+} // namespace implementation
+} // namespace V3_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
diff --git a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
new file mode 100644
index 0000000..fd43178
--- /dev/null
+++ b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
@@ -0,0 +1,4 @@
+service keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service
+ class hal
+ user system
+ group system drmrpc
diff --git a/keymaster/3.0/default/service.cpp b/keymaster/3.0/default/service.cpp
new file mode 100644
index 0000000..a6a9a93
--- /dev/null
+++ b/keymaster/3.0/default/service.cpp
@@ -0,0 +1,33 @@
+/*
+**
+** Copyright 2016, 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.
+*/
+
+#define LOG_TAG "android.hardware.keymaster@3.0-service"
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+using android::hardware::keymaster::V3_0::IKeymasterDevice;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IKeymasterDevice>();
+}
diff --git a/keymaster/3.0/types.hal b/keymaster/3.0/types.hal
new file mode 100644
index 0000000..1f4a0cc
--- /dev/null
+++ b/keymaster/3.0/types.hal
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2016 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.keymaster@3.0;
+
+enum TagType : uint32_t {
+ INVALID = 0 << 28, /* Invalid type, used to designate a tag as uninitialized */
+ ENUM = 1 << 28,
+ ENUM_REP = 2 << 28, /* Repeatable enumeration value. */
+ UINT = 3 << 28,
+ UINT_REP = 4 << 28, /* Repeatable integer value */
+ ULONG = 5 << 28,
+ DATE = 6 << 28,
+ BOOL = 7 << 28,
+ BIGNUM = 8 << 28,
+ BYTES = 9 << 28,
+ ULONG_REP = 10 << 28, /* Repeatable long value */
+};
+
+enum Tag : uint32_t {
+ INVALID = TagType:INVALID | 0,
+
+ /*
+ * Tags that must be semantically enforced by hardware and software implementations.
+ */
+
+ /* Crypto parameters */
+ PURPOSE = TagType:ENUM_REP | 1, /* KeyPurpose. */
+ ALGORITHM = TagType:ENUM | 2, /* Algorithm. */
+ KEY_SIZE = TagType:UINT | 3, /* Key size in bits. */
+ BLOCK_MODE = TagType:ENUM_REP | 4, /* BlockMode. */
+ DIGEST = TagType:ENUM_REP | 5, /* Digest. */
+ PADDING = TagType:ENUM_REP | 6, /* PaddingMode. */
+ CALLER_NONCE = TagType:BOOL | 7, /* Allow caller to specify nonce or IV. */
+ MIN_MAC_LENGTH = TagType:UINT | 8, /* Minimum length of MAC or AEAD authentication tag in
+ * bits. */
+ KDF = TagType:ENUM_REP | 9, /* KeyDerivationFunction. */
+ EC_CURVE = TagType:ENUM | 10, /* EcCurve. */
+
+ /* Algorithm-specific. */
+ RSA_PUBLIC_EXPONENT = TagType:ULONG | 200,
+ ECIES_SINGLE_HASH_MODE = TagType:BOOL | 201, /* Whether the ephemeral public key is fed into the
+ * KDF. */
+ INCLUDE_UNIQUE_ID = TagType:BOOL | 202, /* If true, attestation certificates for this key
+ * will contain an application-scoped and
+ * time-bounded device-unique ID.*/
+
+ /* Other hardware-enforced. */
+ BLOB_USAGE_REQUIREMENTS = TagType:ENUM | 301, /* KeyBlobUsageRequirements. */
+ BOOTLOADER_ONLY = TagType:BOOL | 302, /* Usable only by bootloader. */
+
+ /*
+ * Tags that should be semantically enforced by hardware if possible and will otherwise be
+ * enforced by software (keystore).
+ */
+
+ /* Key validity period */
+ ACTIVE_DATETIME = TagType:DATE | 400, /* Start of validity. */
+ ORIGINATION_EXPIRE_DATETIME = TagType:DATE | 401, /* Date when new "messages" should no longer
+ * be created. */
+ USAGE_EXPIRE_DATETIME = TagType:DATE | 402, /* Date when existing "messages" should no
+ * longer be trusted. */
+ MIN_SECONDS_BETWEEN_OPS = TagType:UINT | 403, /* Minimum elapsed time between
+ * cryptographic operations with the key. */
+ MAX_USES_PER_BOOT = TagType:UINT | 404, /* Number of times the key can be used per
+ * boot. */
+
+ /* User authentication */
+ ALL_USERS = TagType:BOOL | 500, /* Reserved for future use -- ignore. */
+ USER_ID = TagType:UINT | 501, /* Reserved for future use -- ignore. */
+ USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s).
+ * Disallowed if ALL_USERS or NO_AUTH_REQUIRED is
+ * present. */
+ NO_AUTH_REQUIRED = TagType:BOOL | 503, /* If key is usable without authentication. */
+ USER_AUTH_TYPE = TagType:ENUM | 504, /* Bitmask of authenticator types allowed when
+ * USER_SECURE_ID contains a secure user ID, rather
+ * than a secure authenticator ID. Defined in
+ * HardwareAuthenticatorType. */
+ AUTH_TIMEOUT = TagType:UINT | 505, /* Required freshness of user authentication for
+ * private/secret key operations, in seconds. Public
+ * key operations require no authentication. If
+ * absent, authentication is required for every use.
+ * Authentication state is lost when the device is
+ * powered off. */
+ ALLOW_WHILE_ON_BODY = TagType:BOOL | 506, /* Allow key to be used after authentication timeout
+ * if device is still on-body (requires secure on-body
+ * sensor. */
+
+ /* Application access control */
+ ALL_APPLICATIONS = TagType:BOOL | 600, /* Specified to indicate key is usable by all
+ * applications. */
+ APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
+ EXPORTABLE = TagType:BOOL | 602, /* If true, private/secret key can be exported, but only
+ * if all access control requirements for use are
+ * met. (keymaster2) */
+
+ /*
+ * Semantically unenforceable tags, either because they have no specific meaning or because
+ * they're informational only.
+ */
+ APPLICATION_DATA = TagType:BYTES | 700, /* Data provided by authorized application. */
+ CREATION_DATETIME = TagType:DATE | 701, /* Key creation time */
+ ORIGIN = TagType:ENUM | 702, /* keymaster_key_origin_t. */
+ ROLLBACK_RESISTANT = TagType:BOOL | 703, /* Whether key is rollback-resistant. */
+ ROOT_OF_TRUST = TagType:BYTES | 704, /* Root of trust ID. */
+ OS_VERSION = TagType:UINT | 705, /* Version of system (keymaster2) */
+ OS_PATCHLEVEL = TagType:UINT | 706, /* Patch level of system (keymaster2) */
+ UNIQUE_ID = TagType:BYTES | 707, /* Used to provide unique ID in attestation */
+ ATTESTATION_CHALLENGE = TagType:BYTES | 708, /* Used to provide challenge in attestation */
+ ATTESTATION_APPLICATION_ID = TagType:BYTES | 709, /* Used to identify the set of possible
+ * applications of which one has initiated a
+ * key attestation */
+ ATTESTATION_ID_BRAND = TagType:BYTES | 710, /* Used to provide the device's brand name to be
+ included in attestation */
+ ATTESTATION_ID_DEVICE = TagType:BYTES | 711, /* Used to provide the device's device name to be
+ included in attestation */
+ ATTESTATION_ID_PRODUCT = TagType:BYTES | 712, /* Used to provide the device's product name to be
+ included in attestation */
+ ATTESTATION_ID_SERIAL = TagType:BYTES | 713, /* Used to provide the device's serial number to be
+ included in attestation */
+ ATTESTATION_ID_IMEI = TagType:BYTES | 714, /* Used to provide the device's IMEI to be included
+ in attestation */
+ ATTESTATION_ID_MEID = TagType:BYTES | 715, /* Used to provide the device's MEID to be included
+ in attestation */
+ ATTESTATION_ID_MANUFACTURER = TagType:BYTES | 716, /* Used to provide the device's manufacturer
+ name to be included in attestation */
+ ATTESTATION_ID_MODEL = TagType:BYTES | 717, /* Used to provide the device's model name to be
+ included in attestation */
+
+ /* Tags used only to provide data to or receive data from operations */
+ ASSOCIATED_DATA = TagType:BYTES | 1000, /* Used to provide associated data for AEAD modes. */
+ NONCE = TagType:BYTES | 1001, /* Nonce or Initialization Vector */
+ AUTH_TOKEN = TagType:BYTES | 1002, /* Authentication token that proves secure user
+ * authentication has been performed. Structure defined
+ * in hw_auth_token_t in hw_auth_token.h. */
+ MAC_LENGTH = TagType:UINT | 1003, /* MAC or AEAD authentication tag length in bits. */
+
+ RESET_SINCE_ID_ROTATION = TagType:BOOL | 1004, /* Whether the device has beeen factory reset
+ * since the last unique ID rotation. Used for
+ * key attestation. */
+};
+
+enum Algorithm : uint32_t {
+ /* Asymmetric algorithms. */
+ RSA = 1,
+ // DSA = 2, -- Removed, do not re-use value 2.
+ EC = 3,
+
+ /* Block ciphers algorithms */
+ AES = 32,
+
+ /* MAC algorithms */
+ HMAC = 128,
+};
+
+/**
+ * Symmetric block cipher modes provided by keymaster implementations.
+ */
+enum BlockMode : uint32_t {
+ /* Unauthenticated modes, usable only for encryption/decryption and not generally recommended
+ * except for compatibility with existing other protocols. */
+ ECB = 1,
+ CBC = 2,
+ CTR = 3,
+
+ /* Authenticated modes, usable for encryption/decryption and signing/verification. Recommended
+ * over unauthenticated modes for all purposes. */
+ GCM = 32,
+};
+
+/**
+ * Padding modes that may be applied to plaintext for encryption operations. This list includes
+ * padding modes for both symmetric and asymmetric algorithms. Note that implementations should not
+ * provide all possible combinations of algorithm and padding, only the
+ * cryptographically-appropriate pairs.
+ */
+enum PaddingMode : uint32_t {
+ NONE = 1, /* deprecated */
+ RSA_OAEP = 2,
+ RSA_PSS = 3,
+ RSA_PKCS1_1_5_ENCRYPT = 4,
+ RSA_PKCS1_1_5_SIGN = 5,
+ PKCS7 = 64,
+};
+
+/**
+ * Digests provided by keymaster implementations.
+ */
+enum Digest : uint32_t {
+ NONE = 0,
+ MD5 = 1, /* Optional, may not be implemented in hardware, will be handled in software if
+ * needed. */
+ SHA1 = 2,
+ SHA_2_224 = 3,
+ SHA_2_256 = 4,
+ SHA_2_384 = 5,
+ SHA_2_512 = 6,
+};
+
+/**
+ * Supported EC curves, used in ECDSA
+ */
+enum EcCurve : uint32_t {
+ P_224 = 0,
+ P_256 = 1,
+ P_384 = 2,
+ P_521 = 3,
+};
+
+/**
+ * The origin of a key (or pair), i.e. where it was generated. Note that ORIGIN can be found in
+ * either the hardware-enforced or software-enforced list for a key, indicating whether the key is
+ * hardware or software-based. Specifically, a key with GENERATED in the hardware-enforced list is
+ * guaranteed never to have existed outide the secure hardware.
+ */
+enum KeyOrigin : uint32_t {
+ GENERATED = 0, /* Generated in keymaster. Should not exist outside the TEE. */
+ DERIVED = 1, /* Derived inside keymaster. Likely exists off-device. */
+ IMPORTED = 2, /* Imported into keymaster. Existed as cleartext in Android. */
+ UNKNOWN = 3, /* Keymaster did not record origin. This value can only be seen on keys in a
+ * keymaster0 implementation. The keymaster0 adapter uses this value to document
+ * the fact that it is unkown whether the key was generated inside or imported
+ * into keymaster. */
+};
+
+/**
+ * Usability requirements of key blobs. This defines what system functionality must be available
+ * for the key to function. For example, key "blobs" which are actually handles referencing
+ * encrypted key material stored in the file system cannot be used until the file system is
+ * available, and should have BLOB_REQUIRES_FILE_SYSTEM. Other requirements entries will be added
+ * as needed for implementations.
+ */
+enum KeyBlobUsageRequirements : uint32_t {
+ STANDALONE = 0,
+ REQUIRES_FILE_SYSTEM = 1,
+};
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+enum KeyPurpose : uint32_t {
+ ENCRYPT = 0, /* Usable with RSA, EC and AES keys. */
+ DECRYPT = 1, /* Usable with RSA, EC and AES keys. */
+ SIGN = 2, /* Usable with RSA, EC and HMAC keys. */
+ VERIFY = 3, /* Usable with RSA, EC and HMAC keys. */
+ DERIVE_KEY = 4, /* Usable with EC keys. */
+ WRAP_KEY = 5, /* Usable with wrapping keys. */
+};
+
+/**
+ * Keymaster error codes.
+ */
+enum ErrorCode : uint32_t {
+ OK = 0,
+ ROOT_OF_TRUST_ALREADY_SET = -1,
+ UNSUPPORTED_PURPOSE = -2,
+ INCOMPATIBLE_PURPOSE = -3,
+ UNSUPPORTED_ALGORITHM = -4,
+ INCOMPATIBLE_ALGORITHM = -5,
+ UNSUPPORTED_KEY_SIZE = -6,
+ UNSUPPORTED_BLOCK_MODE = -7,
+ INCOMPATIBLE_BLOCK_MODE = -8,
+ UNSUPPORTED_MAC_LENGTH = -9,
+ UNSUPPORTED_PADDING_MODE = -10,
+ INCOMPATIBLE_PADDING_MODE = -11,
+ UNSUPPORTED_DIGEST = -12,
+ INCOMPATIBLE_DIGEST = -13,
+ INVALID_EXPIRATION_TIME = -14,
+ INVALID_USER_ID = -15,
+ INVALID_AUTHORIZATION_TIMEOUT = -16,
+ UNSUPPORTED_KEY_FORMAT = -17,
+ INCOMPATIBLE_KEY_FORMAT = -18,
+ UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, /* For PKCS8 & PKCS12 */
+ UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /* For PKCS8 & PKCS12 */
+ INVALID_INPUT_LENGTH = -21,
+ KEY_EXPORT_OPTIONS_INVALID = -22,
+ DELEGATION_NOT_ALLOWED = -23,
+ KEY_NOT_YET_VALID = -24,
+ KEY_EXPIRED = -25,
+ KEY_USER_NOT_AUTHENTICATED = -26,
+ OUTPUT_PARAMETER_NULL = -27,
+ INVALID_OPERATION_HANDLE = -28,
+ INSUFFICIENT_BUFFER_SPACE = -29,
+ VERIFICATION_FAILED = -30,
+ TOO_MANY_OPERATIONS = -31,
+ UNEXPECTED_NULL_POINTER = -32,
+ INVALID_KEY_BLOB = -33,
+ IMPORTED_KEY_NOT_ENCRYPTED = -34,
+ IMPORTED_KEY_DECRYPTION_FAILED = -35,
+ IMPORTED_KEY_NOT_SIGNED = -36,
+ IMPORTED_KEY_VERIFICATION_FAILED = -37,
+ INVALID_ARGUMENT = -38,
+ UNSUPPORTED_TAG = -39,
+ INVALID_TAG = -40,
+ MEMORY_ALLOCATION_FAILED = -41,
+ IMPORT_PARAMETER_MISMATCH = -44,
+ SECURE_HW_ACCESS_DENIED = -45,
+ OPERATION_CANCELLED = -46,
+ CONCURRENT_ACCESS_CONFLICT = -47,
+ SECURE_HW_BUSY = -48,
+ SECURE_HW_COMMUNICATION_FAILED = -49,
+ UNSUPPORTED_EC_FIELD = -50,
+ MISSING_NONCE = -51,
+ INVALID_NONCE = -52,
+ MISSING_MAC_LENGTH = -53,
+ KEY_RATE_LIMIT_EXCEEDED = -54,
+ CALLER_NONCE_PROHIBITED = -55,
+ KEY_MAX_OPS_EXCEEDED = -56,
+ INVALID_MAC_LENGTH = -57,
+ MISSING_MIN_MAC_LENGTH = -58,
+ UNSUPPORTED_MIN_MAC_LENGTH = -59,
+ UNSUPPORTED_KDF = -60,
+ UNSUPPORTED_EC_CURVE = -61,
+ KEY_REQUIRES_UPGRADE = -62,
+ ATTESTATION_CHALLENGE_MISSING = -63,
+ KEYMASTER_NOT_CONFIGURED = -64,
+ ATTESTATION_APPLICATION_ID_MISSING = -65,
+ CANNOT_ATTEST_IDS = -66,
+
+ UNIMPLEMENTED = -100,
+ VERSION_MISMATCH = -101,
+
+ UNKNOWN_ERROR = -1000,
+};
+
+/**
+ * Key derivation functions, mostly used in ECIES.
+ */
+enum KeyDerivationFunction : uint32_t {
+ /* Do not apply a key derivation function; use the raw agreed key */
+ NONE = 0,
+ /* HKDF defined in RFC 5869 with SHA256 */
+ RFC5869_SHA256 = 1,
+ /* KDF1 defined in ISO 18033-2 with SHA1 */
+ ISO18033_2_KDF1_SHA1 = 2,
+ /* KDF1 defined in ISO 18033-2 with SHA256 */
+ ISO18033_2_KDF1_SHA256 = 3,
+ /* KDF2 defined in ISO 18033-2 with SHA1 */
+ ISO18033_2_KDF2_SHA1 = 4,
+ /* KDF2 defined in ISO 18033-2 with SHA256 */
+ ISO18033_2_KDF2_SHA256 = 5,
+};
+
+/**
+ * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
+ * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
+ * authenticating to activate a key.
+ */
+enum HardwareAuthenticatorType : uint32_t {
+ NONE = 0,
+ PASSWORD = 1 << 0,
+ FINGERPRINT = 1 << 1,
+ // Additional entries must be powers of 2.
+ ANY = 0xFFFFFFFF,
+};
+
+struct KeyParameter {
+ /* Discriminates the uinon/blob field used. The blob cannot be coincided with the union, but
+ * only one of "f" and "blob" is ever used at a time. */
+ Tag tag;
+ union IntegerParams {
+ /* Enum types */
+ Algorithm algorithm;
+ BlockMode blockMode;
+ PaddingMode paddingMode;
+ Digest digest;
+ EcCurve ecCurve;
+ KeyOrigin origin;
+ KeyBlobUsageRequirements keyBlobUsageRequirements;
+ KeyPurpose purpose;
+ KeyDerivationFunction keyDerivationFunction;
+ HardwareAuthenticatorType hardwareAuthenticatorType;
+
+ /* Other types */
+ bool boolValue; // Always true, if a boolean tag is present.
+ uint32_t integer;
+ uint64_t longInteger;
+ uint64_t dateTime;
+ };
+ IntegerParams f; // Hidl does not support anonymous unions, so we have to name it.
+ vec<uint8_t> blob;
+};
+
+struct KeyCharacteristics {
+ vec<KeyParameter> softwareEnforced;
+ vec<KeyParameter> teeEnforced;
+};
+
+/**
+ * Data used to prove successful authentication.
+ */
+struct HardwareAuthToken {
+ uint64_t challenge;
+ uint64_t userId; // Secure User ID, not Android user ID.
+ uint64_t authenticatorId; // Secure authenticator ID.
+ uint32_t authenticatorType; // HardwareAuthenticatorType, in network order.
+ uint64_t timestamp; // In network order.
+ uint8_t[32] hmac; // HMAC is computed over 0 || challenge || user_id ||
+ // authenticator_id || authenticator_type || timestamp, with a
+ // prefixed 0 byte (which was a version field in Keymaster1 and
+ // Keymaster2) and the fields packed (no padding; so you probably
+ // can't just compute over the bytes of the struct).
+};
+
+enum SecurityLevel : uint32_t {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+};
+
+/**
+ * Formats for key import and export.
+ */
+enum KeyFormat : uint32_t {
+ X509 = 0, /* for public key export */
+ PKCS8 = 1, /* for asymmetric key pair import */
+ RAW = 3, /* for symmetric key import and export*/
+};
+
+typedef uint64_t OperationHandle;
diff --git a/keymaster/Android.bp b/keymaster/Android.bp
new file mode 100644
index 0000000..09b8cb2
--- /dev/null
+++ b/keymaster/Android.bp
@@ -0,0 +1,4 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "3.0",
+]
diff --git a/light/2.0/Android.bp b/light/2.0/Android.bp
new file mode 100644
index 0000000..093a9f3
--- /dev/null
+++ b/light/2.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.light@2.0_hal",
+ srcs: [
+ "types.hal",
+ "ILight.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.light@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.light@2.0",
+ srcs: [
+ ":android.hardware.light@2.0_hal",
+ ],
+ out: [
+ "android/hardware/light/2.0/types.cpp",
+ "android/hardware/light/2.0/LightAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.light@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.light@2.0",
+ srcs: [
+ ":android.hardware.light@2.0_hal",
+ ],
+ out: [
+ "android/hardware/light/2.0/types.h",
+ "android/hardware/light/2.0/ILight.h",
+ "android/hardware/light/2.0/IHwLight.h",
+ "android/hardware/light/2.0/BnHwLight.h",
+ "android/hardware/light/2.0/BpHwLight.h",
+ "android/hardware/light/2.0/BsLight.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.light@2.0",
+ generated_sources: ["android.hardware.light@2.0_genc++"],
+ generated_headers: ["android.hardware.light@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.light@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/light/2.0/Android.mk b/light/2.0/Android.mk
new file mode 100644
index 0000000..7bb4293
--- /dev/null
+++ b/light/2.0/Android.mk
@@ -0,0 +1,270 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.light@2.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (Brightness)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Brightness.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Brightness
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Flash)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Flash.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Flash
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (LightState)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/LightState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.LightState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Type)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Type.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Type
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build ILight.hal
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/ILight.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/ILight.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::ILight
+
+$(GEN): $(LOCAL_PATH)/ILight.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.light@2.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (Brightness)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Brightness.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Brightness
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Flash)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Flash.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Flash
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (LightState)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/LightState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.LightState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Type)
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/Type.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::types.Type
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build ILight.hal
+#
+GEN := $(intermediates)/android/hardware/light/V2_0/ILight.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/ILight.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.light@2.0::ILight
+
+$(GEN): $(LOCAL_PATH)/ILight.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/light/2.0/ILight.hal b/light/2.0/ILight.hal
new file mode 100644
index 0000000..a7cd684
--- /dev/null
+++ b/light/2.0/ILight.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 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.light@2.0;
+
+interface ILight {
+
+ /**
+ * Set the provided lights to the provided values.
+ *
+ * @param type logical light to set
+ * @param state describes what the light should look like.
+ * @return status result of applying state transformation.
+ */
+ setLight(Type type, LightState state) generates (Status status);
+
+ /**
+ * Discover what indicator lights are available.
+ *
+ * @return types list of available lights
+ */
+ getSupportedTypes() generates (vec<Type> types);
+
+};
diff --git a/light/2.0/default/Android.mk b/light/2.0/default/Android.mk
new file mode 100644
index 0000000..3439c9b
--- /dev/null
+++ b/light/2.0/default/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.light@2.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ Light.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ liblog \
+ libcutils \
+ libhardware \
+ libbase \
+ libcutils \
+ android.hardware.light@2.0 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.light@2.0-service
+LOCAL_INIT_RC := android.hardware.light@2.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.light@2.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/light/2.0/default/Light.cpp b/light/2.0/default/Light.cpp
new file mode 100644
index 0000000..cde1536
--- /dev/null
+++ b/light/2.0/default/Light.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "light"
+
+#include <log/log.h>
+
+#include "Light.h"
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+static_assert(LIGHT_FLASH_NONE == static_cast<int>(Flash::NONE),
+ "Flash::NONE must match legacy value.");
+static_assert(LIGHT_FLASH_TIMED == static_cast<int>(Flash::TIMED),
+ "Flash::TIMED must match legacy value.");
+static_assert(LIGHT_FLASH_HARDWARE == static_cast<int>(Flash::HARDWARE),
+ "Flash::HARDWARE must match legacy value.");
+
+static_assert(BRIGHTNESS_MODE_USER == static_cast<int>(Brightness::USER),
+ "Brightness::USER must match legacy value.");
+static_assert(BRIGHTNESS_MODE_SENSOR == static_cast<int>(Brightness::SENSOR),
+ "Brightness::SENSOR must match legacy value.");
+static_assert(BRIGHTNESS_MODE_LOW_PERSISTENCE ==
+ static_cast<int>(Brightness::LOW_PERSISTENCE),
+ "Brightness::LOW_PERSISTENCE must match legacy value.");
+
+Light::Light(std::map<Type, light_device_t*> &&lights)
+ : mLights(std::move(lights)) {}
+
+// Methods from ::android::hardware::light::V2_0::ILight follow.
+Return<Status> Light::setLight(Type type, const LightState& state) {
+ auto it = mLights.find(type);
+
+ if (it == mLights.end()) {
+ return Status::LIGHT_NOT_SUPPORTED;
+ }
+
+ light_device_t* hwLight = it->second;
+
+ light_state_t legacyState {
+ .color = state.color,
+ .flashMode = static_cast<int>(state.flashMode),
+ .flashOnMS = state.flashOnMs,
+ .flashOffMS = state.flashOffMs,
+ .brightnessMode = static_cast<int>(state.brightnessMode),
+ };
+
+ int ret = hwLight->set_light(hwLight, &legacyState);
+
+ switch (ret) {
+ case -ENOSYS:
+ return Status::BRIGHTNESS_NOT_SUPPORTED;
+ case 0:
+ return Status::SUCCESS;
+ default:
+ return Status::UNKNOWN;
+ }
+}
+
+Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
+ Type *types = new Type[mLights.size()];
+
+ int idx = 0;
+ for(auto const &pair : mLights) {
+ Type type = pair.first;
+
+ types[idx++] = type;
+ }
+
+ {
+ hidl_vec<Type> hidl_types{};
+ hidl_types.setToExternal(types, mLights.size());
+
+ _hidl_cb(hidl_types);
+ }
+
+ delete[] types;
+
+ return Void();
+}
+
+const static std::map<Type, const char*> kLogicalLights = {
+ {Type::BACKLIGHT, LIGHT_ID_BACKLIGHT},
+ {Type::KEYBOARD, LIGHT_ID_KEYBOARD},
+ {Type::BUTTONS, LIGHT_ID_BUTTONS},
+ {Type::BATTERY, LIGHT_ID_BATTERY},
+ {Type::NOTIFICATIONS, LIGHT_ID_NOTIFICATIONS},
+ {Type::ATTENTION, LIGHT_ID_ATTENTION},
+ {Type::BLUETOOTH, LIGHT_ID_BLUETOOTH},
+ {Type::WIFI, LIGHT_ID_WIFI}
+};
+
+light_device_t* getLightDevice(const char* name) {
+ light_device_t* lightDevice;
+ const hw_module_t* hwModule = NULL;
+
+ int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule);
+ if (ret == 0) {
+ ret = hwModule->methods->open(hwModule, name,
+ reinterpret_cast<hw_device_t**>(&lightDevice));
+ if (ret != 0) {
+ ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
+ }
+ } else {
+ ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
+ }
+
+ if (ret == 0) {
+ return lightDevice;
+ } else {
+ ALOGE("Light passthrough failed to load legacy HAL.");
+ return nullptr;
+ }
+}
+
+ILight* HIDL_FETCH_ILight(const char* /* name */) {
+ std::map<Type, light_device_t*> lights;
+
+ for(auto const &pair : kLogicalLights) {
+ Type type = pair.first;
+ const char* name = pair.second;
+
+ light_device_t* light = getLightDevice(name);
+
+ if (light != nullptr) {
+ lights[type] = light;
+ }
+ }
+
+ if (lights.size() == 0) {
+ // Log information, but still return new Light.
+ // Some devices may not have any lights.
+ ALOGI("Could not open any lights.");
+ }
+
+ return new Light(std::move(lights));
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace light
+} // namespace hardware
+} // namespace android
diff --git a/light/2.0/default/Light.h b/light/2.0/default/Light.h
new file mode 100644
index 0000000..8987036
--- /dev/null
+++ b/light/2.0/default/Light.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
+#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
+
+#include <android/hardware/light/2.0/ILight.h>
+#include <hardware/hardware.h>
+#include <hardware/lights.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include <map>
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::light::V2_0::ILight;
+using ::android::hardware::light::V2_0::LightState;
+using ::android::hardware::light::V2_0::Status;
+using ::android::hardware::light::V2_0::Type;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Light : public ILight {
+ Light(std::map<Type, light_device_t*> &&lights);
+
+ // Methods from ::android::hardware::light::V2_0::ILight follow.
+ Return<Status> setLight(Type type, const LightState& state) override;
+ Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
+
+private:
+ std::map<Type, light_device_t*> mLights;
+};
+
+extern "C" ILight* HIDL_FETCH_ILight(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace light
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
diff --git a/light/2.0/default/android.hardware.light@2.0-service.rc b/light/2.0/default/android.hardware.light@2.0-service.rc
new file mode 100644
index 0000000..c3284c6
--- /dev/null
+++ b/light/2.0/default/android.hardware.light@2.0-service.rc
@@ -0,0 +1,4 @@
+service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service
+ class hal
+ user system
+ group system
\ No newline at end of file
diff --git a/light/2.0/default/service.cpp b/light/2.0/default/service.cpp
new file mode 100644
index 0000000..70ae565
--- /dev/null
+++ b/light/2.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.light@2.0-service"
+
+#include <android/hardware/light/2.0/ILight.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::light::V2_0::ILight;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<ILight>();
+}
diff --git a/light/2.0/types.hal b/light/2.0/types.hal
new file mode 100644
index 0000000..cc2ec32
--- /dev/null
+++ b/light/2.0/types.hal
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 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.light@2.0;
+
+enum Status : int32_t {
+ SUCCESS,
+ LIGHT_NOT_SUPPORTED,
+ BRIGHTNESS_NOT_SUPPORTED,
+ UNKNOWN,
+};
+
+enum Flash : int32_t {
+ /*
+ * Keep the light steady on or off.
+ */
+ NONE,
+
+ /*
+ * Flash the light at specified rate.
+ */
+ TIMED,
+
+ /*
+ * Flash the light using hardware assist.
+ */
+ HARDWARE,
+};
+
+enum Brightness : int32_t {
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ USER,
+
+ /**
+ * Light brightness is managed by a light sensor.
+ */
+ SENSOR,
+
+ /**
+ * Use a low-persistence mode for display backlights.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in LightState may be
+ * overridden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display must meet the following
+ * criteria in this mode:
+ * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms.
+ * - The display must support low-persistence with ≤ 3.5 ms persistence.
+ * Persistence is defined as the amount of time for which a pixel is
+ * emitting light for a single frame.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ * - The display must update at 60 Hz at least, but higher refresh rates are
+ * recommended for low latency.
+ *
+ */
+ LOW_PERSISTENCE,
+};
+
+/*
+ * These light IDs correspond to logical lights, not physical.
+ * So for example, if your INDICATOR light is in line with your
+ * BUTTONS, it might make sense to also light the INDICATOR
+ * light to a reasonable color when the BUTTONS are lit.
+ */
+enum Type : int32_t {
+ BACKLIGHT,
+ KEYBOARD,
+ BUTTONS,
+ BATTERY,
+ NOTIFICATIONS,
+ ATTENTION,
+ BLUETOOTH,
+ WIFI,
+
+ COUNT,
+};
+
+/**
+ * The parameters that can be set for a given light.
+ *
+ * Not all lights must support all parameters. If you
+ * can do something backward-compatible, do it.
+ */
+struct LightState {
+ /**
+ * The color of the LED in ARGB.
+ *
+ * Do your best here.
+ * - If your light can only do red or green, if they ask for blue,
+ * you should do green.
+ * - If you can only do a brightness ramp, then use this formula:
+ * unsigned char brightness = ((77*((color>>16)&0x00ff))
+ * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+ * - If you can only do on or off, 0 is off, anything else is on.
+ *
+ * The high byte should be ignored. Callers will set it to 0xff (which
+ * would correspond to 255 alpha).
+ */
+ uint32_t color;
+
+ /**
+ * To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED,
+ * and then flashOnMS should be set to the number of milliseconds to turn
+ * the light on, followed by the number of milliseconds to turn the light
+ * off.
+ */
+ Flash flashMode;
+
+ int32_t flashOnMs;
+ int32_t flashOffMs;
+
+ Brightness brightnessMode;
+};
diff --git a/light/2.0/vts/Android.mk b/light/2.0/vts/Android.mk
new file mode 100644
index 0000000..089503b
--- /dev/null
+++ b/light/2.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..0558ff2
--- /dev/null
+++ b/light/2.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalLightV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalLightV2_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.light@2.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
+
diff --git a/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
new file mode 100644
index 0000000..3405422
--- /dev/null
+++ b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "light_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/2.0/types.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <set>
+#include <unistd.h>
+
+using ::android::hardware::light::V2_0::Brightness;
+using ::android::hardware::light::V2_0::Flash;
+using ::android::hardware::light::V2_0::ILight;
+using ::android::hardware::light::V2_0::LightState;
+using ::android::hardware::light::V2_0::Status;
+using ::android::hardware::light::V2_0::Type;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+const static LightState kWhite = {
+ .color = 0xFFFFFFFF,
+ .flashMode = Flash::TIMED,
+ .flashOnMs = 100,
+ .flashOffMs = 50,
+ .brightnessMode = Brightness::USER,
+};
+
+const static LightState kLowPersistance = {
+ .color = 0xFF123456,
+ .flashMode = Flash::TIMED,
+ .flashOnMs = 100,
+ .flashOffMs = 50,
+ .brightnessMode = Brightness::LOW_PERSISTENCE,
+};
+
+const static LightState kOff = {
+ .color = 0x00000000,
+ .flashMode = Flash::NONE,
+ .flashOnMs = 0,
+ .flashOffMs = 0,
+ .brightnessMode = Brightness::USER,
+};
+
+const static std::set<Type> kAllTypes = {
+ Type::BACKLIGHT,
+ Type::KEYBOARD,
+ Type::BUTTONS,
+ Type::BATTERY,
+ Type::NOTIFICATIONS,
+ Type::ATTENTION,
+ Type::BLUETOOTH,
+ Type::WIFI
+};
+
+class LightHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+ virtual void SetUp() override {
+ light = ::testing::VtsHalHidlTargetTestBase::getService<ILight>();
+
+ ASSERT_NE(light, nullptr);
+ LOG(INFO) << "Test is remote " << light->isRemote();
+
+ ASSERT_OK(light->getSupportedTypes([this](const hidl_vec<Type> &types) {
+ supportedTypes = types;
+ }));
+ }
+
+ sp<ILight> light;
+ std::vector<Type> supportedTypes;
+
+ virtual void TearDown() override {
+ for (const Type& type: supportedTypes) {
+ Return<Status> ret = light->setLight(type, kOff);
+ EXPECT_OK(ret);
+ EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret));
+ }
+
+ // must leave the device in a useable condition
+ if (std::find(supportedTypes.begin(),
+ supportedTypes.end(),
+ Type::BACKLIGHT) != supportedTypes.end()) {
+ Return<Status> ret = light->setLight(Type::BACKLIGHT, kWhite);
+ EXPECT_OK(ret);
+ EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret));
+ }
+ }
+
+};
+
+/**
+ * Ensure all lights which are reported as supported work.
+ */
+TEST_F(LightHidlTest, TestSupported) {
+ for (const Type& type: supportedTypes) {
+ Return<Status> ret = light->setLight(type, kWhite);
+ EXPECT_OK(ret);
+ EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret));
+ }
+}
+
+/**
+ * Ensure BRIGHTNESS_NOT_SUPPORTED is returned if LOW_PERSISTANCE is not supported.
+ */
+TEST_F(LightHidlTest, TestLowPersistance) {
+ for (const Type& type: supportedTypes) {
+ Return<Status> ret = light->setLight(type, kLowPersistance);
+ EXPECT_OK(ret);
+
+ Status status = ret;
+ EXPECT_TRUE(Status::SUCCESS == status ||
+ Status::BRIGHTNESS_NOT_SUPPORTED == status);
+ }
+}
+
+/**
+ * Ensure lights which are not supported return LIGHT_NOT_SUPPORTED
+ */
+TEST_F(LightHidlTest, TestUnsupported) {
+ std::set<Type> unsupportedTypes = kAllTypes;
+ for (const Type& type: supportedTypes) {
+ unsupportedTypes.erase(type);
+ }
+
+ for (const Type& type: unsupportedTypes) {
+ Return<Status> ret = light->setLight(type, kWhite);
+ EXPECT_OK(ret);
+ EXPECT_EQ(Status::LIGHT_NOT_SUPPORTED, static_cast<Status>(ret));
+ }
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/light/Android.bp b/light/Android.bp
new file mode 100644
index 0000000..8d2c986
--- /dev/null
+++ b/light/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "2.0",
+ "2.0/vts/functional",
+]
diff --git a/media/1.0/Android.bp b/media/1.0/Android.bp
new file mode 100644
index 0000000..7518eb3
--- /dev/null
+++ b/media/1.0/Android.bp
@@ -0,0 +1,55 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.media@1.0_hal",
+ srcs: [
+ "types.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.media@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media@1.0",
+ srcs: [
+ ":android.hardware.media@1.0_hal",
+ ],
+ out: [
+ "android/hardware/media/1.0/types.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.media@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media@1.0",
+ srcs: [
+ ":android.hardware.media@1.0_hal",
+ ],
+ out: [
+ "android/hardware/media/1.0/types.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.media@1.0",
+ generated_sources: ["android.hardware.media@1.0_genc++"],
+ generated_headers: ["android.hardware.media@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.media@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.common@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.common@1.0",
+ ],
+}
diff --git a/media/1.0/types.hal b/media/1.0/types.hal
new file mode 100644
index 0000000..1f9c4dc
--- /dev/null
+++ b/media/1.0/types.hal
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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.media@1.0;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+
+/**
+ * Aliases
+ */
+typedef handle FileDescriptor; // This must have no more than one fd.
+typedef FileDescriptor Fence;
+typedef vec<uint8_t> Bytes;
+
+/**
+ * Ref: frameworks/native/include/ui/GraphicBuffer.h
+ * Ref: system/core/include/system/window.h: ANativeWindowBuffer
+ */
+
+/**
+ * This struct contains attributes for a gralloc buffer that can be put into a
+ * union.
+ */
+struct AnwBufferAttributes {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ PixelFormat format;
+ uint32_t usage; // TODO: convert to an enum
+ uint32_t generationNumber;
+ uint64_t layerCount;
+ uint64_t id;
+};
+
+/**
+ * An AnwBuffer is simply AnwBufferAttributes plus a native handle.
+ */
+struct AnwBuffer {
+ handle nativeHandle;
+ AnwBufferAttributes attr;
+};
+
+/**
+ * Ref: frameworks/native/include/android/rect.h
+ * Ref: frameworks/native/include/ui/Rect.h
+ */
+struct Rect {
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+};
+
+/**
+ * Ref: frameworks/native/include/ui/Region.h
+ */
+typedef vec<Rect> Region;
+
diff --git a/media/Android.bp b/media/Android.bp
new file mode 100644
index 0000000..f2abc67
--- /dev/null
+++ b/media/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "omx/1.0",
+]
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp
new file mode 100644
index 0000000..81dd617
--- /dev/null
+++ b/media/omx/1.0/Android.bp
@@ -0,0 +1,96 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.media.omx@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IGraphicBufferSource.hal",
+ "IOmx.hal",
+ "IOmxBufferSource.hal",
+ "IOmxNode.hal",
+ "IOmxObserver.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.media.omx@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media.omx@1.0",
+ srcs: [
+ ":android.hardware.media.omx@1.0_hal",
+ ],
+ out: [
+ "android/hardware/media/omx/1.0/types.cpp",
+ "android/hardware/media/omx/1.0/GraphicBufferSourceAll.cpp",
+ "android/hardware/media/omx/1.0/OmxAll.cpp",
+ "android/hardware/media/omx/1.0/OmxBufferSourceAll.cpp",
+ "android/hardware/media/omx/1.0/OmxNodeAll.cpp",
+ "android/hardware/media/omx/1.0/OmxObserverAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.media.omx@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media.omx@1.0",
+ srcs: [
+ ":android.hardware.media.omx@1.0_hal",
+ ],
+ out: [
+ "android/hardware/media/omx/1.0/types.h",
+ "android/hardware/media/omx/1.0/IGraphicBufferSource.h",
+ "android/hardware/media/omx/1.0/IHwGraphicBufferSource.h",
+ "android/hardware/media/omx/1.0/BnHwGraphicBufferSource.h",
+ "android/hardware/media/omx/1.0/BpHwGraphicBufferSource.h",
+ "android/hardware/media/omx/1.0/BsGraphicBufferSource.h",
+ "android/hardware/media/omx/1.0/IOmx.h",
+ "android/hardware/media/omx/1.0/IHwOmx.h",
+ "android/hardware/media/omx/1.0/BnHwOmx.h",
+ "android/hardware/media/omx/1.0/BpHwOmx.h",
+ "android/hardware/media/omx/1.0/BsOmx.h",
+ "android/hardware/media/omx/1.0/IOmxBufferSource.h",
+ "android/hardware/media/omx/1.0/IHwOmxBufferSource.h",
+ "android/hardware/media/omx/1.0/BnHwOmxBufferSource.h",
+ "android/hardware/media/omx/1.0/BpHwOmxBufferSource.h",
+ "android/hardware/media/omx/1.0/BsOmxBufferSource.h",
+ "android/hardware/media/omx/1.0/IOmxNode.h",
+ "android/hardware/media/omx/1.0/IHwOmxNode.h",
+ "android/hardware/media/omx/1.0/BnHwOmxNode.h",
+ "android/hardware/media/omx/1.0/BpHwOmxNode.h",
+ "android/hardware/media/omx/1.0/BsOmxNode.h",
+ "android/hardware/media/omx/1.0/IOmxObserver.h",
+ "android/hardware/media/omx/1.0/IHwOmxObserver.h",
+ "android/hardware/media/omx/1.0/BnHwOmxObserver.h",
+ "android/hardware/media/omx/1.0/BpHwOmxObserver.h",
+ "android/hardware/media/omx/1.0/BsOmxObserver.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.media.omx@1.0",
+ generated_sources: ["android.hardware.media.omx@1.0_genc++"],
+ generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/media/omx/1.0/IGraphicBufferSource.hal b/media/omx/1.0/IGraphicBufferSource.hal
new file mode 100644
index 0000000..62073ad
--- /dev/null
+++ b/media/omx/1.0/IGraphicBufferSource.hal
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+import android.hardware.graphics.common@1.0::Dataspace;
+
+import android.hardware.media@1.0::types;
+
+import IOmxNode;
+
+/**
+ * Ref: frameworks/av/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+ *
+ * TODO: Add documentations.
+ */
+interface IGraphicBufferSource {
+
+ configure(IOmxNode omxNode, Dataspace dataspace) generates (Status status);
+
+ setSuspend(bool suspend, int64_t timeUs) generates (Status status);
+
+ setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) generates (Status status);
+
+ setMaxFps(float maxFps) generates (Status status);
+
+ setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) generates (Status status);
+
+ setStartTimeUs(int64_t startTimeUs) generates (Status status);
+
+ setStopTimeUs(int64_t stopTimeUs) generates (Status status);
+
+ setColorAspects(ColorAspects aspects) generates (Status status);
+
+ setTimeOffsetUs(int64_t timeOffsetUs) generates (Status status);
+
+ signalEndOfInputStream() generates (Status status);
+
+};
+
diff --git a/media/omx/1.0/IOmx.hal b/media/omx/1.0/IOmx.hal
new file mode 100644
index 0000000..78d4b32
--- /dev/null
+++ b/media/omx/1.0/IOmx.hal
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+import android.hardware.media@1.0::types;
+
+import IOmxNode;
+import IOmxObserver;
+import IGraphicBufferSource;
+
+/**
+ * Ref: frameworks/av/include/media/IOMX.h: IOMX
+ *
+ * IOmx is the main entry point for communicating with OMX components.
+ */
+interface IOmx {
+
+ /**
+ * Information for an IOmxNode component.
+ */
+ struct ComponentInfo {
+ string mName;
+ vec<string> mRoles;
+ };
+
+ /**
+ * List available components.
+ *
+ * @param[out] status The status of the call.
+ * @param[out] nodeList The list of ComponentInfo.
+ */
+ listNodes(
+ ) generates (
+ Status status,
+ vec<ComponentInfo> nodeList
+ );
+
+ /**
+ * Allocate an IOmxNode instance with the specified component name.
+ *
+ * @param[in] name The name of the component to create.
+ * @param[in] observer An observer object that will receive messages from
+ * the created instance.
+ * @param[out] status The status of the call.
+ * @param[out] omxNode The allocated instance of IOmxNode.
+ */
+ allocateNode(
+ string name,
+ IOmxObserver observer
+ ) generates (
+ Status status,
+ IOmxNode omxNode
+ );
+
+ /**
+ * Create an input surface for recording.
+ *
+ * @param[out] producer The associated producer end of the buffer queue.
+ * @param[out] source The associated `IGraphicBufferSource`.
+ */
+ createInputSurface(
+ ) generates (
+ Status status,
+ IGraphicBufferProducer producer,
+ IGraphicBufferSource source
+ );
+};
+
diff --git a/media/omx/1.0/IOmxBufferSource.hal b/media/omx/1.0/IOmxBufferSource.hal
new file mode 100644
index 0000000..94c43fc
--- /dev/null
+++ b/media/omx/1.0/IOmxBufferSource.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+import android.hardware.media@1.0::types;
+
+/**
+ * Ref: frameworks/av/media/libmedia/aidl/android/IOMXBufferSource.aidl
+ *
+ * IOmxBufferSource is an interface for a listener for certain events from an
+ * IOmxNode instance. Use IOmxNode::setInputSurface() to attach an
+ * IOmxBufferSource instance to an IOmxNode instance.
+ *
+ * @see OMX_STATETYPE in the OpenMax IL standard.
+ */
+interface IOmxBufferSource {
+
+ /**
+ * onOmxExecuting() is invoked when the node state changes to
+ * OMX_StateExecuting state.
+ */
+ oneway onOmxExecuting();
+
+ /**
+ * onOmxIdle() is invoked when the node transitions from OMX_StateExecuting
+ * to OMX_StateIdle.
+ */
+ oneway onOmxIdle();
+
+ /**
+ * onOmxLoaded() is invoked when the node transitions from OMX_StateIdle or
+ * OMX_StateExecuting to OMX_StateLoaded.
+ */
+ oneway onOmxLoaded();
+
+ /**
+ * onInputBufferAdded() is invoked after a new input buffer is added to the
+ * node. This may happen within IOmxNode::allocateSecureBuffer() or
+ * IOmxNode::useBuffer().
+ *
+ * @param[in] buffer is the id of the added buffer.
+ */
+ oneway onInputBufferAdded(BufferId buffer);
+
+ /**
+ * onInputBufferEmptied() is invoked after an input buffer is emptied. This
+ * may happen within IOmxNode::emptyBuffer().
+ *
+ * @param[in] buffer is the id of the emptied buffer.
+ * @param[in] fence is the fence associated with the buffer.
+ */
+ oneway onInputBufferEmptied(BufferId buffer, Fence fence);
+};
+
diff --git a/media/omx/1.0/IOmxNode.hal b/media/omx/1.0/IOmxNode.hal
new file mode 100644
index 0000000..8729637
--- /dev/null
+++ b/media/omx/1.0/IOmxNode.hal
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+import IOmxBufferSource;
+
+import android.hardware.media@1.0::types;
+
+/**
+ * Ref: frameworks/av/include/media/IOMX.h: IOMXNode
+ * Ref: https://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Specification.pdf
+ */
+
+/**
+ * IOmxNode is an interface for communicating with an OMX component (called
+ * "node" here) that has been previously obtained by calling
+ * IOmx::allocateNode().
+ */
+interface IOmxNode {
+
+ /**
+ * Free the node.
+ *
+ * @param[out] status Status of the call.
+ */
+ freeNode(
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Invoke a command on the node.
+ *
+ * @param[in] cmd Type of the command.
+ * @param[in] param Parameter for the command.
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_SendCommand() in the OpenMax IL standard.
+ */
+ sendCommand(
+ uint32_t cmd,
+ int32_t param
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Retrieve a parameter setting from the node.
+ *
+ * @param[in] index Type of the parameter to retrieve.
+ * @param[in] inParams Information about the retrieval.
+ * @param[out] status Status of the call.
+ * @param[out] outParams Current parameter setting.
+ *
+ * @see OMX_GetParameter() in the OpenMax IL standard.
+ */
+ getParameter(
+ uint32_t index,
+ Bytes inParams
+ ) generates (
+ Status status,
+ Bytes outParams
+ );
+
+ /**
+ * Change a parameter setting of the node.
+ *
+ * @param[in] index Type of the parameter to change.
+ * @param[in] params New parameter setting.
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_SetParameter() in the OpenMax IL standard.
+ */
+ setParameter(
+ uint32_t index,
+ Bytes params
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Retrieve a configuration from the node.
+ *
+ * @param[in] index Type of the configuration to retrieve.
+ * @param[in] inConfig Information about the retrieval.
+ * @param[out] status Status of the call.
+ * @param[out] outConfig Current configuration.
+ *
+ * @see OMX_GetConfig() in the OpenMax IL standard.
+ */
+ getConfig(
+ uint32_t index,
+ Bytes inConfig
+ ) generates (
+ Status status,
+ Bytes outConfig
+ );
+
+ /**
+ * Change a configuration of the node.
+ *
+ * @param[in] index Type of the configuration to change.
+ * @param[in] config New configuration.
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_SetConfig() in the OpenMax IL standard.
+ */
+ setConfig(
+ uint32_t index,
+ Bytes config
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Set the mode of a port on the node.
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] mode Target mode on the specified port.
+ * @param[out] status Status of the call.
+ */
+ setPortMode(
+ uint32_t portIndex,
+ PortMode mode
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Prepare a port for adaptive playback. This is based on the extension
+ * "OMX.google.android.index.prepareForAdaptivePlayback".
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] enable Whether the adaptive playback is enabled or not.
+ * @param[in] maxFrameWidth Maximum frame width.
+ * @param[in] maxFrameHeight Maximum frame height.
+ * @param[out] status Status of the call.
+ */
+ prepareForAdaptivePlayback(
+ uint32_t portIndex,
+ bool enable,
+ uint32_t maxFrameWidth,
+ uint32_t maxFrameHeight
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Configure a port for a tunneled playback mode. This is based on the
+ * extension "OMX.google.android.index.configureVideoTunnelMode".
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] tunneled Whether the tunneled mode is used or not.
+ * @param[in] audioHwSync HW SYNC ID of the audio HAL output stream to sync
+ * the video with.
+ * @param[out] status Status of the call.
+ * @param[out] sidebandHandle Codec-allocated sideband window handle.
+ */
+ configureVideoTunnelMode(
+ uint32_t portIndex,
+ bool tunneled,
+ uint32_t audioHwSync
+ ) generates (
+ Status status,
+ handle sidebandHandle
+ );
+
+ /**
+ * Retrieve the buffer usage on a port. This is based on the extension
+ * "OMX.google.android.index.getAndroidNativeBufferUsage".
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[out] status Status of the call.
+ * @param[out] usage Current graphic buffer usage.
+ */
+ getGraphicBufferUsage(
+ uint32_t portIndex
+ ) generates (
+ Status status,
+ uint32_t usage
+ );
+
+ /**
+ * Set up a listener to events related to the input surface.
+ *
+ * @param[in] bufferSource Listener object that implements
+ * IOmxBufferSource.
+ * @param[out] status Status of the call.
+ *
+ * @see IOmxBufferSource.
+ */
+ setInputSurface(
+ IOmxBufferSource bufferSource
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Allocate an opaque buffer on a port as a native handle.
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] size Desired size of the buffer.
+ * @param[out] status Status of the call.
+ * @param[out] buffer Id of the allocated buffer, which will be needed in
+ * other buffer-related functions.
+ * @param[out] nativeHandle Native handle of the allocated buffer.
+ *
+ * @see OMX_AllocateBuffer() in the OpenMax IL standard.
+ */
+ allocateSecureBuffer(
+ uint32_t portIndex,
+ uint64_t size
+ ) generates (
+ Status status,
+ BufferId buffer,
+ handle nativeHandle
+ );
+
+ /**
+ * Assign a buffer to a port.
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] omxBuffer Buffer to be assigned to the port.
+ * @param[out] status Status of the call.
+ * @param[out] buffer Id of the assigned buffer, which will be needed in
+ * other buffer-related functions.
+ *
+ * @see OMX_UseBuffer() in the OpenMax IL standard.
+ */
+ useBuffer(
+ uint32_t portIndex,
+ CodecBuffer omxBuffer
+ ) generates (
+ Status status,
+ BufferId buffer
+ );
+
+ /**
+ * Free a buffer previously assigned to a port by allocateSecureBuffer() or
+ * useBuffer().
+ *
+ * @param[in] portIndex Index of the port.
+ * @param[in] buffer Id of the buffer to be freed.
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_FreeBuffer() in the OpenMax IL standard.
+ */
+ freeBuffer(
+ uint32_t portIndex,
+ BufferId buffer
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Pass \p fence to the node if it supports fences. Otherwise, it waits on
+ * \p fence before calling OMX_FillThisBuffer(). The node will take
+ * ownership of the fence even if this call fails.
+ *
+ * If the port is in metadata mode, the buffer will be updated to point to
+ * the new buffer passed in via \p omxBuffer before OMX_FillThisBuffer() is
+ * called. Otherwise, \p omxBuffer is not used.
+ *
+ * @param[in] buffer Id of the buffer to fill.
+ * @param[in] omxBuffer New buffer information (in metadata mode).
+ * @param[in] fence Fence to wait for (if not null).
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_FillThisBuffer() in the OpenMax IL standard.
+ */
+ fillBuffer(
+ BufferId buffer,
+ CodecBuffer omxBuffer,
+ Fence fence
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Pass \p fence to the node if it supports fences. Otherwise, wait on
+ * \p fence before calling OMX_EmptyThisBuffer(). The node will take
+ * ownership of the fence even if this call fails.
+ *
+ * If the port is in metadata mode, the buffer will be updated to point to
+ * the new buffer passed in via \p omxBuffer before OMX_EmptyThisBuffer() is
+ * called. Otherwise, \p omxBuffer is not used.
+ *
+ * @param[in] buffer Id of the buffer to fill.
+ * @param[in] omxBuffer New buffer information (in metadata mode).
+ * @param[in] flags Flags to be passed to OMX_EmptyBuffer().
+ * @param[in] timestampUs Timestamp OMX_EmptyBuffer().
+ * @param[in] fence Fence to wait for (if not null).
+ * @param[out] status Status of the call.
+ *
+ * @see OMX_EmptyThisBuffer() in the OpenMax IL standard.
+ */
+ emptyBuffer(
+ BufferId buffer,
+ CodecBuffer omxBuffer,
+ uint32_t flags,
+ uint64_t timestampUs,
+ Fence fence
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Request the node to translate an extension string to an index.
+ *
+ * @param[in] parameterName Requested extension string.
+ * @param[out] status Status of the call.
+ * @param[out] index Translated index.
+ *
+ * @see OMX_GetExtensionIndex() in the OpenMax IL standard.
+ */
+ getExtensionIndex(
+ string parameterName
+ ) generates (
+ Status status,
+ uint32_t index
+ );
+
+ /**
+ * Add an OMX message on the node's message queue. The instance of
+ * IOmxObserver that was obtained during the creation of the node will
+ * receive the message in batches by the callback
+ * IOmxObserver::onMessages().
+ *
+ * @param[in] msg Message to send.
+ * @param[out] status Status of the call.
+ *
+ * @see IOmxObserver::onMessages().
+ */
+ dispatchMessage(
+ Message msg
+ ) generates (
+ Status status
+ );
+
+ /**
+ * Set quirks.
+ *
+ * @param[in] quirks Quirks for the component, generally obtained from
+ * MediaCodecList::getQuirksFor().
+ */
+ oneway setQuirks(
+ uint32_t quirks
+ );
+
+};
+
diff --git a/media/omx/1.0/IOmxObserver.hal b/media/omx/1.0/IOmxObserver.hal
new file mode 100644
index 0000000..c26a937
--- /dev/null
+++ b/media/omx/1.0/IOmxObserver.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+/**
+ * Ref: frameworks/av/include/media/IOMX.h: IOMXObserver
+ */
+
+/**
+ * IOmxObserver is a listener interface for OMX messages sent from an IOmxNode
+ * stance.
+ */
+interface IOmxObserver {
+
+ /**
+ * Invoked to process messages from an IOmxNode instance. Note that messages
+ * come in batches.
+ */
+ oneway onMessages(vec<Message> messages);
+};
+
diff --git a/media/omx/1.0/types.hal b/media/omx/1.0/types.hal
new file mode 100644
index 0000000..5413344
--- /dev/null
+++ b/media/omx/1.0/types.hal
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2016 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.media.omx@1.0;
+
+import android.hardware.media@1.0::types;
+
+// Aliases
+typedef uint32_t BufferId;
+
+/**
+ * Ref: system/core/include/utils/Errors.h
+ * Ref: bionic/libc/kernel/uapi/asm-generic/errno-base.h
+ * Ref: bionic/libc/kernel/uapi/asm-generic/errno.h
+ * Ref: frameworks/av/include/media/stagefright/MediaError.h
+ * Ref: frameworks/av/media/libstagefright/omx/OMXUtils.cpp: StatusFromOMXError
+ */
+enum Status : int32_t {
+ OK = 0,
+ NO_ERROR = 0,
+
+ NAME_NOT_FOUND = -2,
+ WOULD_BLOCK = -11,
+ NO_MEMORY = -12,
+ NO_INIT = -19,
+ BAD_VALUE = -22,
+ DEAD_OBJECT = -32,
+ INVALID_OPERATION = -38,
+ TIMED_OUT = -110,
+ ERROR_UNSUPPORTED = -1010,
+ UNKNOWN_ERROR = -2147483648,
+
+ BUFFER_NEEDS_REALLOCATION = 0x1,
+ RELEASE_ALL_BUFFERS = 0x2,
+};
+
+/**
+ * Ref: frameworks/av/include/media/IOMX.h: omx_message
+ *
+ * Data structure for an OMX message. This is essentially a union of different
+ * message types.
+ */
+struct Message {
+
+ /**
+ * There are four main types of messages.
+ */
+ enum Type : uint32_t {
+ EVENT,
+ EMPTY_BUFFER_DONE,
+ FILL_BUFFER_DONE,
+ FRAME_RENDERED,
+ };
+
+ /**
+ * @see OMX_EVENTTYPE in the OpenMax IL standard.
+ */
+ struct EventData {
+ uint32_t event; // TODO: if there are common core events, convert to an enum or point to std
+ uint32_t data1;
+ uint32_t data2;
+ uint32_t data3;
+ uint32_t data4;
+ };
+
+ struct BufferData {
+ BufferId buffer;
+ };
+
+ struct ExtendedBufferData {
+ BufferId buffer;
+ uint32_t rangeOffset;
+ uint32_t rangeLength;
+ uint32_t flags; // TODO: if common flags exist, define an enum of point to std
+ uint64_t timestampUs;
+ };
+
+ struct RenderData {
+ uint64_t timestampUs;
+ int64_t systemTimeNs;
+ };
+
+ union Data {
+ // if type == EVENT
+ EventData eventData;
+
+ // if type == EMPTY_BUFFER_DONE
+ BufferData bufferData;
+
+ // if type == FILL_BUFFER_DONE
+ ExtendedBufferData extendedBufferData;
+
+ // if type == FRAME_RENDERED
+ RenderData renderData;
+ };
+
+ /**
+ * The type of the message.
+ */
+ Type type;
+
+ /**
+ * The fence associated with the message.
+ */
+ Fence fence;
+
+ /**
+ * The union of data, discriminated by type.
+ */
+ Data data;
+};
+
+/**
+ * Ref: frameworks/native/include/ui/GraphicBuffer.h
+ * Ref: system/core/include/system/window.h
+ * Ref: frameworks/native/include/binder/IMemory.h
+ * Ref: frameworks/native/libs/binder/IMemory.cpp
+ * Ref: frameworks/av/include/media/OMXBuffer.h
+ *
+ * Data structure for buffer information. This is essentially a union of
+ * different buffer types.
+ */
+struct CodecBuffer {
+
+ /**
+ * There are four main types of buffers.
+ */
+ enum Type : int32_t {
+ INVALID = 0,
+ PRESET,
+ SHARED_MEM,
+ ANW_BUFFER,
+ NATIVE_HANDLE,
+ };
+
+ struct PresetAttributes {
+ uint32_t rangeOffset;
+ uint32_t rangeLength;
+ };
+
+ union Attributes {
+ // if bufferType == PRESET
+ PresetAttributes preset;
+
+ // if bufferType == SHARED_MEM
+ // No additional attributes.
+
+ // if bufferType == ANW_BUFFER
+ AnwBufferAttributes anwBuffer;
+
+ // if bufferType == NATIVE_HANDLE
+ // No additional attributes.
+ };
+
+ /**
+ * Type of the buffer.
+ */
+ Type type;
+
+ /**
+ * Attributes that can be put into a union.
+ */
+ Attributes attr;
+
+ /**
+ * Used only for types ANW_BUFFER and NATIVE_HANDLE.
+ *
+ * (A native handle cannot be put into a union as HIDL currently does not
+ * support discriminated unions.)
+ */
+ handle nativeHandle;
+
+ /**
+ * Used only for type SHARED_MEM.
+ */
+ memory sharedMemory;
+
+};
+
+/**
+ * Ref: frameworks/av/include/media/IOMX.h
+ *
+ * Enumeration of port modes.
+ */
+enum PortMode : int32_t {
+ PRESET_START = 0,
+ PRESET_BYTE_BUFFER,
+ PRESET_ANW_BUFFER,
+ PRESET_SECURE_BUFFER,
+ PRESET_END,
+ DYNAMIC_START = 100,
+ DYNAMIC_ANW_BUFFER,
+ DYNAMIC_NATIVE_HANDLE,
+ DYNAMIC_END
+};
+
+/**
+ * Ref: frameworks/native/include/media/hardware/VideoAPI.h
+ *
+ * Framework defined color aspects. These are based mainly on ISO 23001-8 spec. As this standard
+ * continues to evolve, new values may be defined in the future. Use OTHER for these future values
+ * as well as for values not listed here, as those are not supported by the framework.
+ */
+struct ColorAspects {
+ enum Range : uint32_t {
+ UNSPECIFIED, // Unspecified
+ FULL, // Full range
+ LIMITED, // Limited range (if defined), or not full range
+
+ OTHER = 0xff, // Not one of the above values
+ };
+
+ // Color primaries
+ enum Primaries : uint32_t {
+ UNSPECIFIED, // Unspecified
+ BT709_5, // Rec.ITU-R BT.709-5 or equivalent
+ BT470_6M, // Rec.ITU-R BT.470-6 System M or equivalent
+ BT601_6_625, // Rec.ITU-R BT.601-6 625 or equivalent
+ BT601_6_525, // Rec.ITU-R BT.601-6 525 or equivalent
+ GENERIC_FILM, // Generic Film
+ BT2020, // Rec.ITU-R BT.2020 or equivalent
+
+ OTHER = 0xff, // Not one of the above values
+ };
+
+ // Transfer characteristics
+ enum Transfer : uint32_t {
+ UNSPECIFIED, // Unspecified
+ LINEAR, // Linear transfer characteristics
+ SRGB, // sRGB or equivalent
+ SMPTE170M, // SMPTE 170M or equivalent (e.g. BT.601/709/2020)
+ GAMMA22, // Assumed display gamma 2.2
+ GAMMA28, // Assumed display gamma 2.8
+ ST2084, // SMPTE ST 2084 for 10/12/14/16 bit systems
+ HLG, // ARIB STD-B67 hybrid-log-gamma
+
+ // values unlikely to be required by Android follow here
+ SMPTE240M = 0x40, // SMPTE 240M
+ XVYCC, // IEC 61966-2-4
+ BT1361, // Rec.ITU-R BT.1361 extended gamut
+ ST428, // SMPTE ST 428-1
+
+ OTHER = 0xff, // Not one of the above values
+ };
+
+ // YUV <-> RGB conversion
+ enum MatrixCoeffs : uint32_t {
+ UNSPECIFIED, // Unspecified
+ BT709_5, // Rec.ITU-R BT.709-5 or equivalent
+ BT470_6M, // KR=0.30, KB=0.11 or equivalent
+ BT601_6, // Rec.ITU-R BT.601-6 625 or equivalent
+ SMPTE240M, // SMPTE 240M or equivalent
+ BT2020, // Rec.ITU-R BT.2020 non-constant luminance
+ BT2020CONSTANT, // Rec.ITU-R BT.2020 constant luminance
+
+ OTHER = 0xff, // Not one of the above values
+ };
+
+ Range range;
+ Primaries primaries;
+ Transfer transfer;
+ MatrixCoeffs matrixCoeffs;
+};
+
diff --git a/memtrack/1.0/Android.bp b/memtrack/1.0/Android.bp
new file mode 100644
index 0000000..9f4c7f6
--- /dev/null
+++ b/memtrack/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.memtrack@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IMemtrack.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.memtrack@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.memtrack@1.0",
+ srcs: [
+ ":android.hardware.memtrack@1.0_hal",
+ ],
+ out: [
+ "android/hardware/memtrack/1.0/types.cpp",
+ "android/hardware/memtrack/1.0/MemtrackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.memtrack@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.memtrack@1.0",
+ srcs: [
+ ":android.hardware.memtrack@1.0_hal",
+ ],
+ out: [
+ "android/hardware/memtrack/1.0/types.h",
+ "android/hardware/memtrack/1.0/IMemtrack.h",
+ "android/hardware/memtrack/1.0/IHwMemtrack.h",
+ "android/hardware/memtrack/1.0/BnHwMemtrack.h",
+ "android/hardware/memtrack/1.0/BpHwMemtrack.h",
+ "android/hardware/memtrack/1.0/BsMemtrack.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.memtrack@1.0",
+ generated_sources: ["android.hardware.memtrack@1.0_genc++"],
+ generated_headers: ["android.hardware.memtrack@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.memtrack@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/memtrack/1.0/Android.mk b/memtrack/1.0/Android.mk
new file mode 100644
index 0000000..62bee97
--- /dev/null
+++ b/memtrack/1.0/Android.mk
@@ -0,0 +1,232 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.memtrack@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (MemtrackFlag)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackRecord)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackRecord.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackRecord
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackStatus)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackType)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IMemtrack.hal
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/IMemtrack.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMemtrack.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::IMemtrack
+
+$(GEN): $(LOCAL_PATH)/IMemtrack.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.memtrack@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (MemtrackFlag)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackFlag.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackFlag
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackRecord)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackRecord.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackRecord
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackStatus)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MemtrackType)
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::types.MemtrackType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IMemtrack.hal
+#
+GEN := $(intermediates)/android/hardware/memtrack/V1_0/IMemtrack.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMemtrack.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.memtrack@1.0::IMemtrack
+
+$(GEN): $(LOCAL_PATH)/IMemtrack.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/memtrack/1.0/IMemtrack.hal b/memtrack/1.0/IMemtrack.hal
new file mode 100644
index 0000000..ae9d960
--- /dev/null
+++ b/memtrack/1.0/IMemtrack.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.memtrack@1.0;
+
+/*
+ * The Memory Tracker HAL is designed to return information about
+ * device-specific memory usage.
+ * The primary goal is to be able to track memory that is not
+ * trackable in any other way, for example texture memory that is allocated by
+ * a process, but not mapped in to that process's address space.
+ * A secondary goal is to be able to categorize memory used by a process into
+ * GL, graphics, etc. All memory sizes must be in real memory usage,
+ * accounting for stride, bit depth, rounding up to page size, etc.
+ *
+ * Constructor for the interface should be used to perform memtrack management
+ * setup actions and is called once before any calls to getMemory().
+ */
+interface IMemtrack {
+ /*
+ * getMemory() populates MemtrackRecord vector with the sizes of memory
+ * plus associated flags for that memory.
+ *
+ * This function must be thread-safe, it may get called from multiple
+ * threads at the same time.
+ *
+ * A process collecting memory statistics will call getMemory for each
+ * combination of pid and memory type. For each memory type that it
+ * recognizes, the HAL must fill out an array of memtrack_record
+ * structures breaking down the statistics of that memory type as much as
+ * possible. For example,
+ * getMemory(<pid>, GL) might return:
+ * { { 4096, ACCOUNTED | PRIVATE | SYSTEM },
+ * { 40960, UNACCOUNTED | PRIVATE | SYSTEM },
+ * { 8192, ACCOUNTED | PRIVATE | DEDICATED },
+ * { 8192, UNACCOUNTED | PRIVATE | DEDICATED } }
+ * If the HAL cannot differentiate between SYSTEM and DEDICATED memory, it
+ * could return:
+ * { { 12288, ACCOUNTED | PRIVATE },
+ * { 49152, UNACCOUNTED | PRIVATE } }
+ *
+ * Memory must not overlap between types. For example, a graphics buffer
+ * that has been mapped into the GPU as a surface must show up when
+ * GRAPHICS is requested and not when GL
+ * is requested.
+ *
+ * @param pid process for which memory information is requested
+ * @param type memory type that information is being requested about
+ * @return records vector of MemtrackRecord containing memory information
+ * @return retval SUCCESS on success, TYPE_NOT_FOUND if the type is not
+ * supported.
+ */
+ getMemory(int32_t pid, MemtrackType type)
+ generates (MemtrackStatus retval, vec<MemtrackRecord> records);
+};
diff --git a/memtrack/1.0/default/Android.bp b/memtrack/1.0/default/Android.bp
new file mode 100644
index 0000000..76d7fc8
--- /dev/null
+++ b/memtrack/1.0/default/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 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.
+
+cc_library_shared {
+ name: "android.hardware.memtrack@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Memtrack.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libhardware",
+ "libutils",
+ "android.hardware.memtrack@1.0",
+ ],
+
+}
+
+cc_binary {
+ relative_install_path: "hw",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ name: "android.hardware.memtrack@1.0-service",
+ init_rc: ["android.hardware.memtrack@1.0-service.rc"],
+ srcs: ["service.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libbase",
+ "libdl",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.memtrack@1.0",
+ ],
+
+}
diff --git a/memtrack/1.0/default/Memtrack.cpp b/memtrack/1.0/default/Memtrack.cpp
new file mode 100644
index 0000000..33a6906
--- /dev/null
+++ b/memtrack/1.0/default/Memtrack.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.memtrack@1.0-impl"
+
+#include <log/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/memtrack.h>
+
+#include "Memtrack.h"
+
+namespace android {
+namespace hardware {
+namespace memtrack {
+namespace V1_0 {
+namespace implementation {
+
+Memtrack::Memtrack(const memtrack_module_t *module) : mModule(module) {
+ if (mModule)
+ mModule->init(mModule);
+}
+
+Memtrack::~Memtrack() {
+ delete(mModule);
+}
+
+Return<void> Memtrack::getMemory(int32_t pid, MemtrackType type,
+ getMemory_cb _hidl_cb) {
+ hidl_vec<MemtrackRecord> records;
+ size_t temp = 0;
+ size_t *size = &temp;
+ int ret = 0;
+
+ if (mModule->getMemory == nullptr)
+ {
+ _hidl_cb(MemtrackStatus::SUCCESS, records);
+ return Void();
+ }
+ ret = mModule->getMemory(mModule, pid, static_cast<memtrack_type>(type),
+ NULL, size);
+ if (ret == 0)
+ {
+ memtrack_record *legacy_records = new memtrack_record[*size];
+ ret = mModule->getMemory(mModule, pid,
+ static_cast<memtrack_type>(type), legacy_records, size);
+ if (ret == 0)
+ {
+ records.resize(*size);
+ for(size_t i = 0; i < *size; i++)
+ {
+ records[i].sizeInBytes = legacy_records[i].size_in_bytes;
+ records[i].flags = legacy_records[i].flags;
+ }
+ }
+ delete[] legacy_records;
+ }
+ _hidl_cb(MemtrackStatus::SUCCESS, records);
+ return Void();
+}
+
+
+IMemtrack* HIDL_FETCH_IMemtrack(const char* /* name */) {
+ const hw_module_t* hw_module = nullptr;
+ const memtrack_module_t* memtrack_module = nullptr;
+ int err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID, &hw_module);
+ if (err) {
+ ALOGE ("hw_get_module %s failed: %d", MEMTRACK_HARDWARE_MODULE_ID, err);
+ return nullptr;
+ }
+
+ if (!hw_module->methods || !hw_module->methods->open) {
+ memtrack_module = reinterpret_cast<const memtrack_module_t*>(hw_module);
+ } else {
+ err = hw_module->methods->open(hw_module, MEMTRACK_HARDWARE_MODULE_ID,
+ reinterpret_cast<hw_device_t**>(const_cast<memtrack_module_t**>(&memtrack_module)));
+ if (err) {
+ ALOGE("Passthrough failed to load legacy HAL.");
+ return nullptr;
+ }
+ }
+ return new Memtrack(memtrack_module);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace memtrack
+} // namespace hardware
+} // namespace android
diff --git a/memtrack/1.0/default/Memtrack.h b/memtrack/1.0/default/Memtrack.h
new file mode 100644
index 0000000..0adba76
--- /dev/null
+++ b/memtrack/1.0/default/Memtrack.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H
+#define ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H
+
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace memtrack {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::memtrack::V1_0::IMemtrack;
+using ::android::hardware::memtrack::V1_0::MemtrackRecord;
+using ::android::hardware::memtrack::V1_0::MemtrackStatus;
+using ::android::hardware::memtrack::V1_0::MemtrackType;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Memtrack : public IMemtrack {
+ Memtrack(const memtrack_module_t* module);
+ ~Memtrack();
+ Return<void> getMemory(int32_t pid, MemtrackType type, getMemory_cb _hidl_cb) override;
+
+ private:
+ const memtrack_module_t* mModule;
+};
+
+extern "C" IMemtrack* HIDL_FETCH_IMemtrack(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace memtrack
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H
diff --git a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
new file mode 100644
index 0000000..c975a18
--- /dev/null
+++ b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
@@ -0,0 +1,4 @@
+service memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service
+ class hal
+ user system
+ group system
diff --git a/memtrack/1.0/default/service.cpp b/memtrack/1.0/default/service.cpp
new file mode 100644
index 0000000..f079743
--- /dev/null
+++ b/memtrack/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.memtrack@1.0-service"
+
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::memtrack::V1_0::IMemtrack;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IMemtrack>();
+}
diff --git a/memtrack/1.0/types.hal b/memtrack/1.0/types.hal
new file mode 100644
index 0000000..3d702b3
--- /dev/null
+++ b/memtrack/1.0/types.hal
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.memtrack@1.0;
+
+/*
+ * SMAPS_ACCOUNTED/SMAPS_UNACCOUNTED
+ * Flags to differentiate memory that can already be accounted for in
+ * /proc/<pid>/smaps,
+ * (Shared_Clean + Shared_Dirty + Private_Clean + Private_Dirty = Size).
+ * In general, memory mapped in to a userspace process is accounted unless
+ * it was mapped with remap_pfn_range.
+ * Exactly one of these must be set.
+ *
+ * SHARED/SHARED_PSS/PRIVATE
+ * Flags to differentiate memory shared across multiple processes vs. memory
+ * used by a single process.
+ * If SHARED_PSS flags is used, the memory must be divided by the number of
+ * processes holding reference to it (shared / num_processes).
+ * Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count shared + private memory.
+ *
+ * SYSTEM/DEDICATED
+ * Flags to differentiate memory taken from the kernel's allocation pool vs.
+ * memory that is dedicated to non-kernel allocations, for example a carveout
+ * or separate video memory. Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count system + dedicated memory.
+ *
+ * NONSECURE/SECURE
+ * Flags to differentiate memory accessible by the CPU in non-secure mode vs.
+ * memory that is protected. Only zero or one of these may be set in a record.
+ * If none are set, record is assumed to count secure + nonsecure memory.
+ */
+enum MemtrackFlag : uint32_t {
+ SMAPS_ACCOUNTED = 1 << 1,
+ SMAPS_UNACCOUNTED = 1 << 2,
+ SHARED = 1 << 3,
+ SHARED_PSS = 1 << 4,
+ PRIVATE = 1 << 5,
+ SYSTEM = 1 << 6,
+ DEDICATED = 1 << 7,
+ NONSECURE = 1 << 8,
+ SECURE = 1 << 9,
+};
+
+/* Tags which define the usage of the memory buffers. */
+enum MemtrackType : uint32_t {
+ OTHER = 0,
+ GL = 1,
+ GRAPHICS = 2,
+ MULTIMEDIA = 3,
+ CAMERA = 4,
+ NUM_TYPES,
+};
+
+enum MemtrackStatus : uint32_t {
+ SUCCESS = 0,
+ MEMORY_TRACKING_NOT_SUPPORTED = 1,
+ TYPE_NOT_SUPPORTED = 2,
+};
+
+/* A vector of MemtrackRecord is returned by the function getMemory().
+ * Each record consists of the size of the memory used by the process and
+ * flags indicate the all the MemtrackFlag that are valid for this record.
+ * see getMemory() comments for further details.
+ */
+struct MemtrackRecord {
+ uint64_t sizeInBytes;
+ /*
+ * This is the bitfield for the MemtrackFlag indicating all the flags that
+ * are valid for this record.
+ */
+ uint32_t flags;
+};
diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..71e6111
--- /dev/null
+++ b/memtrack/1.0/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalMemtrackV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libutils",
+ "android.hardware.memtrack@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
new file mode 100644
index 0000000..a8d8aea
--- /dev/null
+++ b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "memtrack_hidl_hal_test"
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <algorithm>
+#include <vector>
+
+using ::android::hardware::memtrack::V1_0::IMemtrack;
+using ::android::hardware::memtrack::V1_0::MemtrackRecord;
+using ::android::hardware::memtrack::V1_0::MemtrackFlag;
+using ::android::hardware::memtrack::V1_0::MemtrackType;
+using ::android::hardware::memtrack::V1_0::MemtrackStatus;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::sp;
+using ::android::base::unique_fd;
+using std::vector;
+using std::count_if;
+
+class MemtrackHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ memtrack = ::testing::VtsHalHidlTargetTestBase::getService<IMemtrack>();
+ ASSERT_NE(memtrack, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IMemtrack> memtrack;
+};
+
+/* Returns true if flags contains at least min, and no more than max,
+ * of the flags in flagSet. Returns false otherwise.
+ */
+bool rightFlagCount(uint32_t flags, vector<MemtrackFlag> flagSet, uint32_t min,
+ uint32_t max) {
+ uint32_t count =
+ count_if(flagSet.begin(), flagSet.end(),
+ [&](MemtrackFlag f) { return flags & (uint32_t)f; });
+ return (min <= count && count <= max);
+}
+
+/* Returns true when passed a valid, defined status, false otherwise.
+ */
+bool validStatus(MemtrackStatus s) {
+ vector<MemtrackStatus> statusVec = {
+ MemtrackStatus::SUCCESS, MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED,
+ MemtrackStatus::TYPE_NOT_SUPPORTED};
+ return std::find(statusVec.begin(), statusVec.end(), s) != statusVec.end();
+}
+
+auto generate_cb(MemtrackStatus *s, hidl_vec<MemtrackRecord> *v) {
+ return [=](MemtrackStatus status, hidl_vec<MemtrackRecord> vec) {
+ *s = status;
+ *v = vec;
+ };
+}
+
+/* Sanity check results when getMemory() is passed a negative PID
+ */
+TEST_F(MemtrackHidlTest, BadPidTest) {
+ MemtrackStatus s;
+ hidl_vec<MemtrackRecord> v;
+ auto cb = generate_cb(&s, &v);
+ for (uint32_t i = 0; i < static_cast<uint32_t>(MemtrackType::NUM_TYPES);
+ i++) {
+ Return<void> ret =
+ memtrack->getMemory(-1, static_cast<MemtrackType>(i), cb);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(validStatus(s));
+ }
+}
+
+/* Sanity check results when getMemory() is passed a bad memory usage type
+ */
+TEST_F(MemtrackHidlTest, BadTypeTest) {
+ MemtrackStatus s;
+ hidl_vec<MemtrackRecord> v;
+ auto cb = generate_cb(&s, &v);
+ Return<void> ret = memtrack->getMemory(getpid(), MemtrackType::NUM_TYPES, cb);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(validStatus(s));
+}
+
+/* Call memtrack on this process and check that the results are reasonable
+ * for all memory types, including valid flag combinations for every
+ * MemtrackRecord returned.
+ */
+TEST_F(MemtrackHidlTest, GetMemoryTest) {
+ /* Opening this device causes the kernel to provide memtrack with memory
+ * info for this process.
+ */
+ unique_fd fd(open("/dev/kgsl-3d0", O_RDWR));
+
+ MemtrackStatus s;
+ hidl_vec<MemtrackRecord> v;
+ auto cb = generate_cb(&s, &v);
+ uint32_t unsupportedCount = 0;
+ for (uint32_t i = 0; i < static_cast<uint32_t>(MemtrackType::NUM_TYPES);
+ i++) {
+ Return<void> ret =
+ memtrack->getMemory(getpid(), static_cast<MemtrackType>(i), cb);
+ ASSERT_TRUE(ret.isOk());
+
+ switch (s) {
+ case MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED:
+ unsupportedCount++;
+ break;
+ case MemtrackStatus::TYPE_NOT_SUPPORTED:
+ break;
+ case MemtrackStatus::SUCCESS: {
+ for (uint32_t j = 0; j < v.size(); j++) {
+ // Enforce flag constraints
+ vector<MemtrackFlag> smapFlags = {MemtrackFlag::SMAPS_ACCOUNTED,
+ MemtrackFlag::SMAPS_UNACCOUNTED};
+ EXPECT_TRUE(rightFlagCount(v[j].flags, smapFlags, 1, 1));
+ vector<MemtrackFlag> shareFlags = {MemtrackFlag::SHARED,
+ MemtrackFlag::SHARED_PSS,
+ MemtrackFlag::PRIVATE};
+ EXPECT_TRUE(rightFlagCount(v[j].flags, shareFlags, 0, 1));
+ vector<MemtrackFlag> systemFlags = {MemtrackFlag::SYSTEM,
+ MemtrackFlag::DEDICATED};
+ EXPECT_TRUE(rightFlagCount(v[j].flags, systemFlags, 0, 1));
+ vector<MemtrackFlag> secureFlags = {MemtrackFlag::SECURE,
+ MemtrackFlag::NONSECURE};
+ EXPECT_TRUE(rightFlagCount(v[j].flags, secureFlags, 0, 1));
+ }
+ break;
+ }
+ default:
+ FAIL();
+ }
+ }
+ // If tracking is not supported this should be returned for all types.
+ ASSERT_TRUE(unsupportedCount == 0 ||
+ unsupportedCount ==
+ static_cast<uint32_t>(MemtrackType::NUM_TYPES));
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/memtrack/Android.bp b/memtrack/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/memtrack/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/power/1.0/Android.bp b/power/1.0/Android.bp
new file mode 100644
index 0000000..453d525
--- /dev/null
+++ b/power/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.power@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IPower.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.power@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.power@1.0",
+ srcs: [
+ ":android.hardware.power@1.0_hal",
+ ],
+ out: [
+ "android/hardware/power/1.0/types.cpp",
+ "android/hardware/power/1.0/PowerAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.power@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.power@1.0",
+ srcs: [
+ ":android.hardware.power@1.0_hal",
+ ],
+ out: [
+ "android/hardware/power/1.0/types.h",
+ "android/hardware/power/1.0/IPower.h",
+ "android/hardware/power/1.0/IHwPower.h",
+ "android/hardware/power/1.0/BnHwPower.h",
+ "android/hardware/power/1.0/BpHwPower.h",
+ "android/hardware/power/1.0/BsPower.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.power@1.0",
+ generated_sources: ["android.hardware.power@1.0_genc++"],
+ generated_headers: ["android.hardware.power@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.power@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/power/1.0/Android.mk b/power/1.0/Android.mk
new file mode 100644
index 0000000..98d95a8
--- /dev/null
+++ b/power/1.0/Android.mk
@@ -0,0 +1,270 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.power@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (Feature)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/Feature.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.Feature
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerHint)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerHint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerHint
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerStatePlatformSleepState)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerStatePlatformSleepState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerStatePlatformSleepState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerStateVoter)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerStateVoter.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerStateVoter
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IPower.hal
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/IPower.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IPower.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::IPower
+
+$(GEN): $(LOCAL_PATH)/IPower.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.power@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (Feature)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/Feature.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.Feature
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerHint)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerHint.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerHint
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerStatePlatformSleepState)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerStatePlatformSleepState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerStatePlatformSleepState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PowerStateVoter)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/PowerStateVoter.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.PowerStateVoter
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IPower.hal
+#
+GEN := $(intermediates)/android/hardware/power/V1_0/IPower.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IPower.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.power@1.0::IPower
+
+$(GEN): $(LOCAL_PATH)/IPower.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/power/1.0/IPower.hal b/power/1.0/IPower.hal
new file mode 100644
index 0000000..6cba42a
--- /dev/null
+++ b/power/1.0/IPower.hal
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 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.power@1.0;
+
+/*
+ * Constructor for the interface performs power management setup actions at
+ * runtime startup, such as to set default cpufreq parameters.
+ */
+interface IPower {
+ /*
+ * setInteractive() performs power management actions upon the
+ * system entering interactive state (that is, the system is awake
+ * and ready for interaction, often with UI devices such as
+ * display and touchscreen enabled) or non-interactive state (the
+ * system appears asleep, display usually turned off). The
+ * non-interactive state may be entered after a period of
+ * inactivity in order to conserve battery power during
+ * such inactive periods.
+ *
+ * Typical actions are to turn on or off devices and adjust
+ * cpufreq parameters. This function may also call the
+ * appropriate interfaces to allow the kernel to suspend the
+ * system to low-power sleep state when entering non-interactive
+ * state, and to disallow low-power suspend when the system is in
+ * interactive state. When low-power suspend state is allowed, the
+ * kernel may suspend the system whenever no wakelocks are held.
+ *
+ * For example,
+ * This function can be called to enter non-interactive state after
+ * turning off the screen (if present) and called to enter
+ * interactive state prior to turning on the screen.
+ *
+ * @param interactive is true when the system is transitioning to an
+ * interactive state and false when transitioning to a
+ * non-interactive state.
+ */
+ setInteractive(bool interactive);
+
+ /*
+ * powerHint() is called to pass hints on power requirements which
+ * may result in adjustment of power/performance parameters of the
+ * cpufreq governor and other controls.
+ *
+ * A particular platform may choose to ignore any hint.
+ *
+ * @param hint PowerHint which is passed
+ * @param data contains additional information about the hint
+ * and is described along with the comments for each of the hints.
+ */
+ powerHint(PowerHint hint, int32_t data);
+
+ /*
+ * setFeature() is called to turn on or off a particular feature
+ * depending on the state parameter.
+ *
+ * @param feature Feature which needs to be set
+ * @param activate true/false to enable/disable the feature
+ */
+ setFeature(Feature feature, bool activate);
+
+ /*
+ * Platform-level sleep state stats:
+ * Report cumulative info on the statistics on platform-level sleep states
+ * since boot.
+ *
+ * Higher the index in the returned <states> vector deeper the state is
+ * i.e. lesser steady-state power is consumed by the platform to be
+ * resident in that state.
+ *
+ * @return states of power states the device supports
+ * @return retval SUCCESS on success or FILESYSTEM_ERROR on filesystem
+ * nodes access error.
+ */
+ getPlatformLowPowerStats()
+ generates (vec<PowerStatePlatformSleepState> states, Status retval);
+};
diff --git a/power/1.0/default/Android.bp b/power/1.0/default/Android.bp
new file mode 100644
index 0000000..4f43b95
--- /dev/null
+++ b/power/1.0/default/Android.bp
@@ -0,0 +1,61 @@
+// Copyright (C) 2016 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.
+
+cc_library_shared {
+ name: "android.hardware.power@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Power.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.hardware.power@1.0",
+ ],
+
+}
+
+cc_binary {
+ proprietary: true,
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ name: "android.hardware.power@1.0-service",
+ init_rc: ["android.hardware.power@1.0-service.rc"],
+ srcs: ["service.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libdl",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.power@1.0",
+ ],
+
+}
diff --git a/power/1.0/default/Power.cpp b/power/1.0/default/Power.cpp
new file mode 100644
index 0000000..6ea9167
--- /dev/null
+++ b/power/1.0/default/Power.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.power@1.0-impl"
+
+#include <log/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/power.h>
+
+#include "Power.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_0 {
+namespace implementation {
+
+Power::Power(power_module_t *module) : mModule(module) {
+ if (mModule)
+ mModule->init(mModule);
+}
+
+Power::~Power() {
+ delete(mModule);
+}
+
+// Methods from ::android::hardware::power::V1_0::IPower follow.
+Return<void> Power::setInteractive(bool interactive) {
+ if (mModule->setInteractive)
+ mModule->setInteractive(mModule, interactive ? 1 : 0);
+ return Void();
+}
+
+Return<void> Power::powerHint(PowerHint hint, int32_t data) {
+ int32_t param = data;
+ if (mModule->powerHint) {
+ if (data)
+ mModule->powerHint(mModule, static_cast<power_hint_t>(hint), ¶m);
+ else
+ mModule->powerHint(mModule, static_cast<power_hint_t>(hint), NULL);
+ }
+ return Void();
+}
+
+Return<void> Power::setFeature(Feature feature, bool activate) {
+ if (mModule->setFeature)
+ mModule->setFeature(mModule, static_cast<feature_t>(feature),
+ activate ? 1 : 0);
+ return Void();
+}
+
+Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
+ hidl_vec<PowerStatePlatformSleepState> states;
+ ssize_t number_platform_modes;
+ size_t *voters = nullptr;
+ power_state_platform_sleep_state_t *legacy_states = nullptr;
+ int ret;
+
+ if (mModule->get_number_of_platform_modes == nullptr ||
+ mModule->get_voter_list == nullptr ||
+ mModule->get_platform_low_power_stats == nullptr)
+ {
+ _hidl_cb(states, Status::SUCCESS);
+ return Void();
+ }
+
+ number_platform_modes = mModule->get_number_of_platform_modes(mModule);
+ if (number_platform_modes)
+ {
+ if ((ssize_t) (SIZE_MAX / sizeof(size_t)) <= number_platform_modes) // overflow
+ goto done;
+ voters = new (std::nothrow) size_t [number_platform_modes];
+ if (voters == nullptr)
+ goto done;
+
+ ret = mModule->get_voter_list(mModule, voters);
+ if (ret != 0)
+ goto done;
+
+ if ((ssize_t) (SIZE_MAX / sizeof(power_state_platform_sleep_state_t))
+ <= number_platform_modes) // overflow
+ goto done;
+ legacy_states = new (std::nothrow)
+ power_state_platform_sleep_state_t [number_platform_modes];
+ if (legacy_states == nullptr)
+ goto done;
+
+ for (int i = 0; i < number_platform_modes; i++)
+ {
+ legacy_states[i].voters = nullptr;
+ legacy_states[i].voters = new power_state_voter_t [voters[i]];
+ if (legacy_states[i].voters == nullptr)
+ goto done;
+ }
+
+ ret = mModule->get_platform_low_power_stats(mModule, legacy_states);
+ if (ret != 0)
+ goto done;
+
+ states.resize(number_platform_modes);
+ for (int i = 0; i < number_platform_modes; i++)
+ {
+ power_state_platform_sleep_state_t& legacy_state = legacy_states[i];
+ PowerStatePlatformSleepState& state = states[i];
+ state.name = legacy_state.name;
+ state.residencyInMsecSinceBoot = legacy_state.residency_in_msec_since_boot;
+ state.totalTransitions = legacy_state.total_transitions;
+ state.supportedOnlyInSuspend = legacy_state.supported_only_in_suspend;
+ state.voters.resize(voters[i]);
+ for(size_t j = 0; j < voters[i]; j++)
+ {
+ state.voters[j].name = legacy_state.voters[j].name;
+ state.voters[j].totalTimeInMsecVotedForSinceBoot = legacy_state.voters[j].total_time_in_msec_voted_for_since_boot;
+ state.voters[j].totalNumberOfTimesVotedSinceBoot = legacy_state.voters[j].total_number_of_times_voted_since_boot;
+ }
+ }
+ }
+done:
+ if (legacy_states)
+ {
+ for (int i = 0; i < number_platform_modes; i++)
+ {
+ if(legacy_states[i].voters)
+ delete(legacy_states[i].voters);
+ }
+ }
+ delete[] legacy_states;
+ delete[] voters;
+ _hidl_cb(states, Status::SUCCESS);
+ return Void();
+}
+
+IPower* HIDL_FETCH_IPower(const char* /* name */) {
+ int ret = 0;
+ const hw_module_t* hw_module = NULL;
+ power_module_t *power_module;
+ ret = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module);
+ if (ret == 0 && hw_module->methods->open) {
+ ret = hw_module->methods->open(hw_module, POWER_HARDWARE_MODULE_ID,
+ reinterpret_cast<hw_device_t**>(&power_module));
+ if (ret == 0) {
+ return new Power(power_module);
+ }
+ else {
+ ALOGE("Passthrough failed to load legacy power HAL.");
+ return nullptr;
+ }
+ }
+ else {
+ ALOGE ("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, ret);
+ return nullptr;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace power
+} // namespace hardware
+} // namespace android
diff --git a/power/1.0/default/Power.h b/power/1.0/default/Power.h
new file mode 100644
index 0000000..a43aefb
--- /dev/null
+++ b/power/1.0/default/Power.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_POWER_V1_0_POWER_H
+#define ANDROID_HARDWARE_POWER_V1_0_POWER_H
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::IPower;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using ::android::hardware::power::V1_0::Status;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Power : public IPower {
+ Power(power_module_t* module);
+ ~Power();
+ Return<void> setInteractive(bool interactive) override;
+ Return<void> powerHint(PowerHint hint, int32_t data) override;
+ Return<void> setFeature(Feature feature, bool activate) override;
+ Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
+
+ private:
+ power_module_t* mModule;
+};
+
+extern "C" IPower* HIDL_FETCH_IPower(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace power
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_POWER_V1_0_POWER_H
diff --git a/power/1.0/default/android.hardware.power@1.0-service.rc b/power/1.0/default/android.hardware.power@1.0-service.rc
new file mode 100644
index 0000000..1777e90
--- /dev/null
+++ b/power/1.0/default/android.hardware.power@1.0-service.rc
@@ -0,0 +1,4 @@
+service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
+ class hal
+ user system
+ group system
diff --git a/power/1.0/default/service.cpp b/power/1.0/default/service.cpp
new file mode 100644
index 0000000..e8618b8
--- /dev/null
+++ b/power/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.power@1.0-service"
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::power::V1_0::IPower;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IPower>();
+}
diff --git a/power/1.0/types.hal b/power/1.0/types.hal
new file mode 100644
index 0000000..debdc35
--- /dev/null
+++ b/power/1.0/types.hal
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 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.power@1.0;
+
+/* Power hint identifiers passed to powerHint() */
+enum PowerHint : uint32_t {
+ /*
+ * Foreground app has started or stopped requesting a VSYNC pulse
+ * from SurfaceFlinger. If the app has started requesting VSYNC
+ * then CPU and GPU load is expected soon, and it may be appropriate
+ * to raise speeds of CPU, memory bus, etc. The data parameter is
+ * non-zero to indicate VSYNC pulse is now requested, or zero for
+ * VSYNC pulse no longer requested.
+ */
+ VSYNC = 0x00000001,
+
+
+ /*
+ * User is interacting with the device, for example, touchscreen
+ * events are incoming. CPU and GPU load may be expected soon,
+ * and it may be appropriate to raise speeds of CPU, memory bus,
+ * etc. The data parameter is the estimated length of the interaction
+ * in milliseconds, or 0 if unknown.
+ */
+ INTERACTION = 0x00000002,
+
+
+ /* DO NOT USE VIDEO_ENCODE/_DECODE! They will be removed in
+ * KLP.
+ */
+ VIDEO_ENCODE = 0x00000003,
+ VIDEO_DECODE = 0x00000004,
+
+ /*
+ * Low power mode is activated or deactivated. Low power mode
+ * is intended to save battery at the cost of performance. The data
+ * parameter is non-zero when low power mode is activated, and zero
+ * when deactivated.
+ */
+ LOW_POWER = 0x00000005,
+
+ /*
+ * Sustained Performance mode is actived or deactivated. Sustained
+ * performance mode is intended to provide a consistent level of
+ * performance for a prolonged amount of time. The data parameter is
+ * non-zero when sustained performance mode is activated, and zero
+ * when deactivated.
+ */
+ SUSTAINED_PERFORMANCE = 0x00000006,
+
+ /*
+ * VR Mode is activated or deactivated. VR mode is intended to
+ * provide minimum guarantee for performance for the amount of time the
+ * device can sustain it. The data parameter is non-zero when the mode
+ * is activated and zero when deactivated.
+ */
+ VR_MODE = 0x00000007,
+
+ /*
+ * This hint indicates that an application has been launched. Can be used
+ * for device specific optimizations during application launch. The data
+ * parameter is non-zero when the application starts to launch and zero when
+ * it has been launched.
+ */
+ LAUNCH = 0x00000008,
+};
+
+enum Feature : uint32_t {
+ /*
+ * Enabling/Disabling this feature will allow/disallow the system
+ * to wake up by tapping the screen twice.
+ */
+ POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 0x00000001
+};
+
+enum Status : uint32_t {
+ SUCCESS = 0,
+ FILESYSTEM_ERROR = 1
+};
+/*
+ * Platform-level sleep state stats:
+ * PowerStateVoter struct is useful for describing the individual voters
+ * when a Platform-level sleep state is chosen by aggregation of votes from
+ * multiple clients/system conditions.
+ *
+ * This helps in attirbuting what in the device is blocking the device from
+ * entering the lowest Platform-level sleep state.
+ */
+struct PowerStateVoter {
+ /*
+ * Name of the voter.
+ */
+ string name;
+
+ /*
+ * Total time in msec the voter voted for the platform sleep state since
+ * boot.
+ */
+ uint64_t totalTimeInMsecVotedForSinceBoot;
+
+ /*
+ * Number of times the voter voted for the platform sleep state since boot.
+ */
+ uint64_t totalNumberOfTimesVotedSinceBoot;
+};
+
+/*
+ * Platform-level sleep state stats:
+ * PowerStatePlatformSleepState represents the Platform-level sleep state
+ * the device is capable of getting into.
+ *
+ * SoCs usually have more than one Platform-level sleep state.
+ */
+struct PowerStatePlatformSleepState {
+ /*
+ * Platform-level Sleep state name.
+ */
+ string name;
+
+ /*
+ * Time spent in msec at this platform-level sleep state since boot.
+ */
+ uint64_t residencyInMsecSinceBoot;
+
+ /*
+ * Total number of times system entered this state.
+ */
+ uint64_t totalTransitions;
+
+ /*
+ * This platform-level sleep state can only be reached during system suspend
+ */
+ bool supportedOnlyInSuspend;
+
+ /*
+ * voters is useful if the Platform-level sleep state
+ * is chosen by aggregation votes from multiple clients/system conditions.
+ * All the voters have to say yes or all the system conditions need to be
+ * met to enter a platform-level sleep state.
+ *
+ * Vector of size zero implies either the info is not available
+ * or the system does not follow a voting mechanism to choose this
+ * Platform-level sleep state.
+ */
+ vec<PowerStateVoter> voters;
+};
diff --git a/radio/1.0/vts/Android.mk b/power/1.0/vts/Android.mk
similarity index 100%
copy from radio/1.0/vts/Android.mk
copy to power/1.0/vts/Android.mk
diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..5ab1eb4
--- /dev/null
+++ b/power/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalPowerV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalPowerV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.power@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
new file mode 100644
index 0000000..cd1a261
--- /dev/null
+++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "power_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <cutils/properties.h>
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/power/1.0/IPower.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <algorithm>
+
+using ::android::hardware::power::V1_0::IPower;
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using ::android::hardware::power::V1_0::Status;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::sp;
+using ::android::base::unique_fd;
+
+using std::vector;
+
+#define CPU_GOVERNOR_PATH \
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+#define AVAILABLE_GOVERNORS_PATH \
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors"
+
+class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>();
+ ASSERT_NE(power, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IPower> power;
+};
+
+// Sanity check Power::setInteractive.
+TEST_F(PowerHidlTest, SetInteractive) {
+ Return<void> ret;
+
+ ret = power->setInteractive(true);
+ ASSERT_TRUE(ret.isOk());
+
+ ret = power->setInteractive(false);
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Test Power::setInteractive and Power::powerHint(Launch)
+// with each available CPU governor, if available
+TEST_F(PowerHidlTest, TryDifferentGovernors) {
+ Return<void> ret;
+
+ unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR));
+ unique_fd fd2(open(AVAILABLE_GOVERNORS_PATH, O_RDONLY));
+ if (fd1 < 0 || fd2 < 0) {
+ // Files don't exist, so skip the rest of the test case
+ SUCCEED();
+ }
+
+ char old_governor[80];
+ ASSERT_LE(0, read(fd1, old_governor, 80));
+
+ char governors[1024];
+ unsigned len = read(fd2, governors, 1024);
+ ASSERT_LE(0u, len);
+ governors[len] = '\0';
+
+ char *saveptr;
+ char *name = strtok_r(governors, " \n", &saveptr);
+ while (name) {
+ ASSERT_LE(0, write(fd1, name, strlen(name)));
+ ret = power->setInteractive(true);
+ ASSERT_TRUE(ret.isOk());
+
+ ret = power->setInteractive(false);
+ ASSERT_TRUE(ret.isOk());
+
+ ret = power->setInteractive(false);
+ ASSERT_TRUE(ret.isOk());
+
+ power->powerHint(PowerHint::LAUNCH, 1);
+ power->powerHint(PowerHint::LAUNCH, 0);
+
+ name = strtok_r(NULL, " \n", &saveptr);
+ }
+
+ ASSERT_LE(0, write(fd1, old_governor, strlen(old_governor)));
+}
+
+// Sanity check Power::powerHint on good and bad inputs.
+TEST_F(PowerHidlTest, PowerHint) {
+ PowerHint badHint = static_cast<PowerHint>(0xA);
+ auto hints = {PowerHint::VSYNC, PowerHint::INTERACTION,
+ PowerHint::VIDEO_ENCODE, PowerHint::VIDEO_DECODE,
+ PowerHint::LOW_POWER, PowerHint::SUSTAINED_PERFORMANCE,
+ PowerHint::VR_MODE, PowerHint::LAUNCH,
+ badHint};
+ Return<void> ret;
+ for (auto hint : hints) {
+ ret = power->powerHint(hint, 30000);
+ ASSERT_TRUE(ret.isOk());
+
+ ret = power->powerHint(hint, 0);
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ // Turning these hints on in different orders triggers different code paths,
+ // so iterate over possible orderings.
+ std::vector<PowerHint> hints2 = {PowerHint::LAUNCH, PowerHint::VR_MODE,
+ PowerHint::SUSTAINED_PERFORMANCE,
+ PowerHint::INTERACTION};
+ auto compareHints = [](PowerHint l, PowerHint r) {
+ return static_cast<uint32_t>(l) < static_cast<uint32_t>(r);
+ };
+ std::sort(hints2.begin(), hints2.end(), compareHints);
+ do {
+ for (auto iter = hints2.begin(); iter != hints2.end(); iter++) {
+ ret = power->powerHint(*iter, 0);
+ ASSERT_TRUE(ret.isOk());
+ }
+ for (auto iter = hints2.begin(); iter != hints2.end(); iter++) {
+ ret = power->powerHint(*iter, 30000);
+ ASSERT_TRUE(ret.isOk());
+ }
+ } while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
+}
+
+// Sanity check Power::setFeature() on good and bad inputs.
+TEST_F(PowerHidlTest, SetFeature) {
+ Return<void> ret;
+ ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, true);
+ ASSERT_TRUE(ret.isOk());
+ ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, false);
+ ASSERT_TRUE(ret.isOk());
+
+ Feature badFeature = static_cast<Feature>(0x2);
+ ret = power->setFeature(badFeature, true);
+ ASSERT_TRUE(ret.isOk());
+ ret = power->setFeature(badFeature, false);
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Sanity check Power::getPlatformLowPowerStats().
+TEST_F(PowerHidlTest, GetPlatformLowPowerStats) {
+ hidl_vec<PowerStatePlatformSleepState> vec;
+ Status s;
+ auto cb = [&vec, &s](hidl_vec<PowerStatePlatformSleepState> states,
+ Status status) {
+ vec = states;
+ s = status;
+ };
+ Return<void> ret = power->getPlatformLowPowerStats(cb);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(s == Status::SUCCESS || s == Status::FILESYSTEM_ERROR);
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/power/Android.bp b/power/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/power/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/sensors/1.0/Android.bp b/sensors/1.0/Android.bp
new file mode 100644
index 0000000..8357dbe
--- /dev/null
+++ b/sensors/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.sensors@1.0_hal",
+ srcs: [
+ "types.hal",
+ "ISensors.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.sensors@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.sensors@1.0",
+ srcs: [
+ ":android.hardware.sensors@1.0_hal",
+ ],
+ out: [
+ "android/hardware/sensors/1.0/types.cpp",
+ "android/hardware/sensors/1.0/SensorsAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.sensors@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.sensors@1.0",
+ srcs: [
+ ":android.hardware.sensors@1.0_hal",
+ ],
+ out: [
+ "android/hardware/sensors/1.0/types.h",
+ "android/hardware/sensors/1.0/ISensors.h",
+ "android/hardware/sensors/1.0/IHwSensors.h",
+ "android/hardware/sensors/1.0/BnHwSensors.h",
+ "android/hardware/sensors/1.0/BpHwSensors.h",
+ "android/hardware/sensors/1.0/BsSensors.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.sensors@1.0",
+ generated_sources: ["android.hardware.sensors@1.0_genc++"],
+ generated_headers: ["android.hardware.sensors@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.sensors@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/sensors/1.0/Android.mk b/sensors/1.0/Android.mk
new file mode 100644
index 0000000..29f7c7e
--- /dev/null
+++ b/sensors/1.0/Android.mk
@@ -0,0 +1,40 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.sensors@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/sensors/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/ISensors.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.sensors@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/sensors/1.0/ISensors.hal b/sensors/1.0/ISensors.hal
new file mode 100644
index 0000000..5c8301a
--- /dev/null
+++ b/sensors/1.0/ISensors.hal
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016 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.sensors@1.0;
+
+interface ISensors {
+ /**
+ * Enumerate all available (static) sensors.
+ */
+ getSensorsList() generates (vec<SensorInfo> list);
+
+ /**
+ * Place the module in a specific mode. The following modes are defined
+ *
+ * SENSOR_HAL_NORMAL_MODE - Normal operation. Default state of the module.
+ *
+ * SENSOR_HAL_DATA_INJECTION_MODE - Loopback mode.
+ * Data is injected for the supported sensors by the sensor service in
+ * this mode.
+ *
+ * @return OK on success
+ * BAD_VALUE if requested mode is not supported
+ * PERMISSION_DENIED if operation is not allowed
+ */
+ setOperationMode(OperationMode mode) generates (Result result);
+
+ /* Activate/de-activate one sensor.
+ *
+ * After sensor de-activation, existing sensor events that have not
+ * been picked up by poll() must be abandoned immediately so that
+ * subsequent activation will not get stale sensor events (events
+ * that are generated prior to the latter activation).
+ *
+ * @param sensorHandle is the handle of the sensor to change.
+ * @param enabled set to true to enable, or false to disable the sensor.
+ *
+ * @return result OK on success, BAD_VALUE if sensorHandle is invalid.
+ */
+ activate(int32_t sensorHandle, bool enabled) generates (Result result);
+
+ /**
+ * Generate a vector of sensor events containing at most "maxCount"
+ * entries.
+ *
+ * Additionally a vector of SensorInfos is returned for any dynamic sensors
+ * connected as notified by returned events of type DYNAMIC_SENSOR_META.
+ *
+ * If there is no sensor event when this function is being called, block
+ * until there are sensor events available.
+ *
+ * @param maxCount max number of samples can be returned, must be > 0.
+ * Actual number of events returned in data must be <= maxCount
+ * and > 0.
+ * @return result OK on success or BAD_VALUE if maxCount <= 0.
+ * @return data vector of Event contains sensor events.
+ * @return dynamicSensorsAdded vector of SensorInfo contains dynamic sensor
+ * added. Each element corresponds to a dynamic sensor meta events
+ * in data.
+ */
+ poll(int32_t maxCount)
+ generates (
+ Result result,
+ vec<Event> data,
+ vec<SensorInfo> dynamicSensorsAdded);
+
+ /*
+ * Sets a sensor’s parameters, including sampling frequency and maximum
+ * report latency. This function can be called while the sensor is
+ * activated, in which case it must not cause any sensor measurements to
+ * be lost: transitioning from one sampling rate to the other cannot cause
+ * lost events, nor can transitioning from a high maximum report latency to
+ * a low maximum report latency.
+ * See the Batching sensor results page for details:
+ * http://source.android.com/devices/sensors/batching.html
+ *
+ * @param sensorHandle handle of sensor to be changed.
+ * @param samplingPeriodNs specifies sensor sample period in nanoseconds.
+ * @param maxReportLatencyNs allowed delay time before an event is sampled
+ * to time of report.
+ * @return result OK on success, BAD_VALUE if any parameters are invalid.
+ */
+ batch(int32_t sensorHandle,
+ int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) generates (Result result);
+
+ /*
+ * Trigger a flush of internal FIFO.
+ *
+ * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode"
+ * FIFO for the specified sensor and flushes the FIFO. If the FIFO is empty
+ * or if the sensor doesn't support batching (FIFO size zero), return
+ * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream.
+ * This applies to all sensors other than one-shot sensors. If the sensor
+ * is a one-shot sensor, flush must return BAD_VALUE and not generate any
+ * flush complete metadata. If the sensor is not active at the time flush()
+ * is called, flush() return BAD_VALUE.
+ *
+ * @param sensorHandle handle of sensor to be flushed.
+ * @return result OK on success and BAD_VALUE if sensorHandle is invalid.
+ */
+ flush(int32_t sensorHandle) generates (Result result);
+
+ /*
+ * Inject a single sensor event or push operation environment parameters to
+ * device.
+ *
+ * When device is in NORMAL mode, this function is called to push operation
+ * environment data to device. In this operation, Event is always of
+ * SensorType::AdditionalInfo type. See operation evironment parameters
+ * section in AdditionalInfoType.
+ *
+ * When device is in DATA_INJECTION mode, this function is also used for
+ * injecting sensor events.
+ *
+ * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+ * type events should not be routed back to poll() function.
+ *
+ * @see AdditionalInfoType
+ * @see OperationMode
+ * @param event sensor event to be injected
+ * @return result OK on success; PERMISSION_DENIED if operation is not
+ * allowed; INVALID_OPERATION, if this functionality is
+ * unsupported; BAD_VALUE if sensor event cannot be injected.
+ */
+ injectSensorData(Event event) generates (Result result);
+
+ /*
+ * Register direct report channel.
+ *
+ * Register a direct channel with supplied shared memory information. Upon
+ * return, the sensor hardware is responsible for resetting the memory
+ * content to initial value (depending on memory format settings).
+ *
+ * @param mem shared memory info data structure.
+ * @return result OK on success; BAD_VALUE if shared memory information is
+ * not consistent; NO_MEMORY if shared memory cannot be used by
+ * sensor system; INVALID_OPERATION if functionality is not
+ * supported.
+ * @return channelHandle a positive integer used for referencing registered
+ * direct channel (>0) in configureDirectReport and
+ * unregisterDirectChannel if result is OK, -1 otherwise.
+ */
+ registerDirectChannel(SharedMemInfo mem)
+ generates (Result result, int32_t channelHandle);
+
+ /*
+ * Unregister direct report channel.
+ *
+ * Unregister a direct channel previously registered using
+ * registerDirectChannel, and remove all active sensor report configured in
+ * still active sensor report configured in the direct channel.
+ *
+ * @param channelHandle handle of direct channel to be unregistered.
+ * @return result OK if direct report is supported; INVALID_OPERATION
+ * otherwise.
+ */
+ unregisterDirectChannel(int32_t channelHandle) generates (Result result);
+
+ /*
+ * Configure direct sensor event report in direct channel.
+ *
+ * This function start, modify rate or stop direct report of a sensor in a
+ * certain direct channel.
+ *
+ * @param sensorHandle handle of sensor to be configured. When combined
+ * with STOP rate, sensorHandle can be -1 to denote all active
+ * sensors in the direct channel specified by channel Handle.
+ * @param channelHandle handle of direct channel to be configured.
+ * @param rate rate level, see RateLevel enum.
+ *
+ * @return result OK on success; BAD_VALUE if parameter is invalid (such as
+ * rate level is not supported by sensor, channelHandle does not
+ * exist, etc); INVALID_OPERATION if functionality is not
+ * supported.
+ * @return reportToken positive integer to identify multiple sensors of
+ * the same type in a single direct channel. Ignored if rate is
+ * STOP. See SharedMemFormat.
+ */
+ configDirectReport(
+ int32_t sensorHandle, int32_t channelHandle, RateLevel rate)
+ generates (Result result, int32_t reportToken);
+};
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
new file mode 100644
index 0000000..2ab1b90
--- /dev/null
+++ b/sensors/1.0/default/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+ name: "android.hardware.sensors@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Sensors.cpp"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.sensors@1.0",
+ ],
+ static_libs: [
+ "android.hardware.sensors@1.0-convert",
+ "multihal",
+ ],
+ local_include_dirs: ["include/sensors"],
+}
+
+cc_library_static {
+ name: "android.hardware.sensors@1.0-convert",
+ defaults: ["hidl_defaults"],
+ srcs: ["convert.cpp"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.sensors@1.0",
+ ],
+ local_include_dirs: ["include/sensors"],
+}
+
+
diff --git a/sensors/1.0/default/Android.mk b/sensors/1.0/default/Android.mk
new file mode 100644
index 0000000..bc1cfbd
--- /dev/null
+++ b/sensors/1.0/default/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.sensors@1.0-service
+LOCAL_INIT_RC := android.hardware.sensors@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.sensors@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/sensors/1.0/default/Sensors.cpp b/sensors/1.0/default/Sensors.cpp
new file mode 100644
index 0000000..1100dd6
--- /dev/null
+++ b/sensors/1.0/default/Sensors.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "Sensors.h"
+#include "convert.h"
+#include "multihal.h"
+
+#include <android-base/logging.h>
+
+#include <sys/stat.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V1_0 {
+namespace implementation {
+
+/*
+ * If a multi-hal configuration file exists in the proper location,
+ * return true indicating we need to use multi-hal functionality.
+ */
+static bool UseMultiHal() {
+ const std::string& name = MULTI_HAL_CONFIG_FILE_PATH;
+ struct stat buffer;
+ return (stat (name.c_str(), &buffer) == 0);
+}
+
+static Result ResultFromStatus(status_t err) {
+ switch (err) {
+ case OK:
+ return Result::OK;
+ case PERMISSION_DENIED:
+ return Result::PERMISSION_DENIED;
+ case NO_MEMORY:
+ return Result::NO_MEMORY;
+ case BAD_VALUE:
+ return Result::BAD_VALUE;
+ default:
+ return Result::INVALID_OPERATION;
+ }
+}
+
+Sensors::Sensors()
+ : mInitCheck(NO_INIT),
+ mSensorModule(nullptr),
+ mSensorDevice(nullptr) {
+ status_t err = OK;
+ if (UseMultiHal()) {
+ mSensorModule = ::get_multi_hal_module_info();
+ } else {
+ err = hw_get_module(
+ SENSORS_HARDWARE_MODULE_ID,
+ (hw_module_t const **)&mSensorModule);
+ }
+ if (mSensorModule == NULL) {
+ err = UNKNOWN_ERROR;
+ }
+
+ if (err != OK) {
+ LOG(ERROR) << "Couldn't load "
+ << SENSORS_HARDWARE_MODULE_ID
+ << " module ("
+ << strerror(-err)
+ << ")";
+
+ mInitCheck = err;
+ return;
+ }
+
+ err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
+
+ if (err != OK) {
+ LOG(ERROR) << "Couldn't open device for module "
+ << SENSORS_HARDWARE_MODULE_ID
+ << " ("
+ << strerror(-err)
+ << ")";
+
+ mInitCheck = err;
+ return;
+ }
+
+ // Require all the old HAL APIs to be present except for injection, which
+ // is considered optional.
+ CHECK_GE(getHalDeviceVersion(), SENSORS_DEVICE_API_VERSION_1_3);
+
+ if (getHalDeviceVersion() == SENSORS_DEVICE_API_VERSION_1_4) {
+ if (mSensorDevice->inject_sensor_data == nullptr) {
+ LOG(ERROR) << "HAL specifies version 1.4, but does not implement inject_sensor_data()";
+ }
+ if (mSensorModule->set_operation_mode == nullptr) {
+ LOG(ERROR) << "HAL specifies version 1.4, but does not implement set_operation_mode()";
+ }
+ }
+
+ mInitCheck = OK;
+}
+
+status_t Sensors::initCheck() const {
+ return mInitCheck;
+}
+
+Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) {
+ sensor_t const *list;
+ size_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+
+ hidl_vec<SensorInfo> out;
+ out.resize(count);
+
+ for (size_t i = 0; i < count; ++i) {
+ const sensor_t *src = &list[i];
+ SensorInfo *dst = &out[i];
+
+ convertFromSensor(*src, dst);
+ }
+
+ _hidl_cb(out);
+
+ return Void();
+}
+
+int Sensors::getHalDeviceVersion() const {
+ if (!mSensorDevice) {
+ return -1;
+ }
+
+ return mSensorDevice->common.version;
+}
+
+Return<Result> Sensors::setOperationMode(OperationMode mode) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4
+ || mSensorModule->set_operation_mode == nullptr) {
+ return Result::INVALID_OPERATION;
+ }
+ return ResultFromStatus(mSensorModule->set_operation_mode((uint32_t)mode));
+}
+
+Return<Result> Sensors::activate(
+ int32_t sensor_handle, bool enabled) {
+ return ResultFromStatus(
+ mSensorDevice->activate(
+ reinterpret_cast<sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle,
+ enabled));
+}
+
+Return<void> Sensors::poll(int32_t maxCount, poll_cb _hidl_cb) {
+
+ hidl_vec<Event> out;
+ hidl_vec<SensorInfo> dynamicSensorsAdded;
+
+ std::unique_ptr<sensors_event_t[]> data;
+ int err = android::NO_ERROR;
+
+ { // scope of reentry lock
+
+ // This enforces a single client, meaning that a maximum of one client can call poll().
+ // If this function is re-entred, it means that we are stuck in a state that may prevent
+ // the system from proceeding normally.
+ //
+ // Exit and let the system restart the sensor-hal-implementation hidl service.
+ //
+ // This function must not call _hidl_cb(...) or return until there is no risk of blocking.
+ std::unique_lock<std::mutex> lock(mPollLock, std::try_to_lock);
+ if(!lock.owns_lock()){
+ // cannot get the lock, hidl service will go into deadlock if it is not restarted.
+ // This is guaranteed to not trigger in passthrough mode.
+ LOG(ERROR) <<
+ "ISensors::poll() re-entry. I do not know what to do except killing myself.";
+ ::exit(-1);
+ }
+
+ if (maxCount <= 0) {
+ err = android::BAD_VALUE;
+ } else {
+ int bufferSize = maxCount <= kPollMaxBufferSize ? maxCount : kPollMaxBufferSize;
+ data.reset(new sensors_event_t[bufferSize]);
+ err = mSensorDevice->poll(
+ reinterpret_cast<sensors_poll_device_t *>(mSensorDevice),
+ data.get(), bufferSize);
+ }
+ }
+
+ if (err < 0) {
+ _hidl_cb(ResultFromStatus(err), out, dynamicSensorsAdded);
+ return Void();
+ }
+
+ const size_t count = (size_t)err;
+
+ for (size_t i = 0; i < count; ++i) {
+ if (data[i].type != SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+ continue;
+ }
+
+ const dynamic_sensor_meta_event_t *dyn = &data[i].dynamic_sensor_meta;
+
+ if (!dyn->connected) {
+ continue;
+ }
+
+ CHECK(dyn->sensor != nullptr);
+ CHECK_EQ(dyn->sensor->handle, dyn->handle);
+
+ SensorInfo info;
+ convertFromSensor(*dyn->sensor, &info);
+
+ size_t numDynamicSensors = dynamicSensorsAdded.size();
+ dynamicSensorsAdded.resize(numDynamicSensors + 1);
+ dynamicSensorsAdded[numDynamicSensors] = info;
+ }
+
+ out.resize(count);
+ convertFromSensorEvents(err, data.get(), &out);
+
+ _hidl_cb(Result::OK, out, dynamicSensorsAdded);
+
+ return Void();
+}
+
+Return<Result> Sensors::batch(
+ int32_t sensor_handle,
+ int64_t sampling_period_ns,
+ int64_t max_report_latency_ns) {
+ return ResultFromStatus(
+ mSensorDevice->batch(
+ mSensorDevice,
+ sensor_handle,
+ 0, /*flags*/
+ sampling_period_ns,
+ max_report_latency_ns));
+}
+
+Return<Result> Sensors::flush(int32_t sensor_handle) {
+ return ResultFromStatus(mSensorDevice->flush(mSensorDevice, sensor_handle));
+}
+
+Return<Result> Sensors::injectSensorData(const Event& event) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4
+ || mSensorDevice->inject_sensor_data == nullptr) {
+ return Result::INVALID_OPERATION;
+ }
+
+ sensors_event_t out;
+ convertToSensorEvent(event, &out);
+
+ return ResultFromStatus(
+ mSensorDevice->inject_sensor_data(mSensorDevice, &out));
+}
+
+Return<void> Sensors::registerDirectChannel(
+ const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) {
+ if (mSensorDevice->register_direct_channel == nullptr
+ || mSensorDevice->config_direct_report == nullptr) {
+ // HAL does not support
+ _hidl_cb(Result::INVALID_OPERATION, -1);
+ return Void();
+ }
+
+ sensors_direct_mem_t m;
+ if (!convertFromSharedMemInfo(mem, &m)) {
+ _hidl_cb(Result::BAD_VALUE, -1);
+ return Void();
+ }
+
+ int err = mSensorDevice->register_direct_channel(mSensorDevice, &m, -1);
+
+ if (err < 0) {
+ _hidl_cb(ResultFromStatus(err), -1);
+ } else {
+ int32_t channelHandle = static_cast<int32_t>(err);
+ _hidl_cb(Result::OK, channelHandle);
+ }
+ return Void();
+}
+
+Return<Result> Sensors::unregisterDirectChannel(int32_t channelHandle) {
+ if (mSensorDevice->register_direct_channel == nullptr
+ || mSensorDevice->config_direct_report == nullptr) {
+ // HAL does not support
+ return Result::INVALID_OPERATION;
+ }
+
+ mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
+
+ return Result::OK;
+}
+
+Return<void> Sensors::configDirectReport(
+ int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) {
+ if (mSensorDevice->register_direct_channel == nullptr
+ || mSensorDevice->config_direct_report == nullptr) {
+ // HAL does not support
+ _hidl_cb(Result::INVALID_OPERATION, -1);
+ return Void();
+ }
+
+ sensors_direct_cfg_t cfg = {
+ .rate_level = convertFromRateLevel(rate)
+ };
+ if (cfg.rate_level < 0) {
+ _hidl_cb(Result::BAD_VALUE, -1);
+ return Void();
+ }
+
+ int err = mSensorDevice->config_direct_report(mSensorDevice,
+ sensorHandle, channelHandle, &cfg);
+
+ if (rate == RateLevel::STOP) {
+ _hidl_cb(ResultFromStatus(err), -1);
+ } else {
+ _hidl_cb(err > 0 ? Result::OK : ResultFromStatus(err), err);
+ }
+ return Void();
+}
+
+// static
+void Sensors::convertFromSensorEvents(
+ size_t count,
+ const sensors_event_t *srcArray,
+ hidl_vec<Event> *dstVec) {
+ for (size_t i = 0; i < count; ++i) {
+ const sensors_event_t &src = srcArray[i];
+ Event *dst = &(*dstVec)[i];
+
+ convertFromSensorEvent(src, dst);
+ }
+}
+
+ISensors *HIDL_FETCH_ISensors(const char * /* hal */) {
+ Sensors *sensors = new Sensors;
+ if (sensors->initCheck() != OK) {
+ delete sensors;
+ sensors = nullptr;
+
+ return nullptr;
+ }
+
+ return sensors;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/1.0/default/Sensors.h b/sensors/1.0/default/Sensors.h
new file mode 100644
index 0000000..7d715e0
--- /dev/null
+++ b/sensors/1.0/default/Sensors.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_
+
+#define HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <hardware/sensors.h>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V1_0 {
+namespace implementation {
+
+
+struct Sensors : public ::android::hardware::sensors::V1_0::ISensors {
+ Sensors();
+
+ status_t initCheck() const;
+
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+ Return<Result> setOperationMode(OperationMode mode) override;
+
+ Return<Result> activate(
+ int32_t sensor_handle, bool enabled) override;
+
+ Return<void> poll(int32_t maxCount, poll_cb _hidl_cb) override;
+
+ Return<Result> batch(
+ int32_t sensor_handle,
+ int64_t sampling_period_ns,
+ int64_t max_report_latency_ns) override;
+
+ Return<Result> flush(int32_t sensor_handle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(
+ const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(
+ int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+private:
+ static constexpr int32_t kPollMaxBufferSize = 128;
+ status_t mInitCheck;
+ sensors_module_t *mSensorModule;
+ sensors_poll_device_1_t *mSensorDevice;
+ std::mutex mPollLock;
+
+ int getHalDeviceVersion() const;
+
+ static void convertFromSensorEvents(
+ size_t count, const sensors_event_t *src, hidl_vec<Event> *dst);
+
+ DISALLOW_COPY_AND_ASSIGN(Sensors);
+};
+
+extern "C" ISensors *HIDL_FETCH_ISensors(const char *name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
new file mode 100644
index 0000000..2360863
--- /dev/null
+++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -0,0 +1,4 @@
+service sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service
+ class main
+ user system
+ group system readproc
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
new file mode 100644
index 0000000..306d3a3
--- /dev/null
+++ b/sensors/1.0/default/convert.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "convert.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V1_0 {
+namespace implementation {
+
+void convertFromSensor(const sensor_t &src, SensorInfo *dst) {
+ dst->name = src.name;
+ dst->vendor = src.vendor;
+ dst->version = src.version;
+ dst->sensorHandle = src.handle;
+ dst->type = (SensorType)src.type;
+ dst->maxRange = src.maxRange;
+ dst->resolution = src.resolution;
+ dst->power = src.power;
+ dst->minDelay = src.minDelay;
+ dst->fifoReservedEventCount = src.fifoReservedEventCount;
+ dst->fifoMaxEventCount = src.fifoMaxEventCount;
+ dst->typeAsString = src.stringType;
+ dst->requiredPermission = src.requiredPermission;
+ dst->maxDelay = src.maxDelay;
+ dst->flags = src.flags;
+}
+
+void convertToSensor(
+ const ::android::hardware::sensors::V1_0::SensorInfo &src,
+ sensor_t *dst) {
+ dst->name = strdup(src.name.c_str());
+ dst->vendor = strdup(src.vendor.c_str());
+ dst->version = src.version;
+ dst->handle = src.sensorHandle;
+ dst->type = (int)src.type;
+ dst->maxRange = src.maxRange;
+ dst->resolution = src.resolution;
+ dst->power = src.power;
+ dst->minDelay = src.minDelay;
+ dst->fifoReservedEventCount = src.fifoReservedEventCount;
+ dst->fifoMaxEventCount = src.fifoMaxEventCount;
+ dst->stringType = strdup(src.typeAsString.c_str());
+ dst->requiredPermission = strdup(src.requiredPermission.c_str());
+ dst->maxDelay = src.maxDelay;
+ dst->flags = src.flags;
+ dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertFromSensorEvent(const sensors_event_t &src, Event *dst) {
+ typedef ::android::hardware::sensors::V1_0::SensorType SensorType;
+ typedef ::android::hardware::sensors::V1_0::MetaDataEventType MetaDataEventType;
+
+ dst->sensorHandle = src.sensor;
+ dst->sensorType = (SensorType)src.type;
+ dst->timestamp = src.timestamp;
+
+ switch (dst->sensorType) {
+ case SensorType::META_DATA:
+ {
+ dst->u.meta.what = (MetaDataEventType)src.meta_data.what;
+ // Legacy HALs contain the handle reference in the meta data field.
+ // Copy that over to the handle of the event. In legacy HALs this
+ // field was expected to be 0.
+ dst->sensorHandle = src.meta_data.sensor;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION:
+ {
+ dst->u.vec3.x = src.acceleration.x;
+ dst->u.vec3.y = src.acceleration.y;
+ dst->u.vec3.z = src.acceleration.z;
+ dst->u.vec3.status = (SensorStatus)src.acceleration.status;
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GAME_ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ {
+ dst->u.vec4.x = src.data[0];
+ dst->u.vec4.y = src.data[1];
+ dst->u.vec4.z = src.data[2];
+ dst->u.vec4.w = src.data[3];
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED:
+ {
+ dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib;
+ dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib;
+ dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib;
+ dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias;
+ dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias;
+ dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias;
+ break;
+ }
+
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::TEMPERATURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ {
+ dst->u.scalar = src.data[0];
+ break;
+ }
+
+ case SensorType::STEP_COUNTER:
+ {
+ dst->u.stepCount = src.u64.step_counter;
+ break;
+ }
+
+ case SensorType::HEART_RATE:
+ {
+ dst->u.heartRate.bpm = src.heart_rate.bpm;
+ dst->u.heartRate.status = (SensorStatus)src.heart_rate.status;
+ break;
+ }
+
+ case SensorType::POSE_6DOF: // 15 floats
+ {
+ for (size_t i = 0; i < 15; ++i) {
+ dst->u.pose6DOF[i] = src.data[i];
+ }
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META:
+ {
+ dst->u.dynamic.connected = src.dynamic_sensor_meta.connected;
+ dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+ memcpy(dst->u.dynamic.uuid.data(),
+ src.dynamic_sensor_meta.uuid,
+ 16);
+
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO:
+ {
+ ::android::hardware::sensors::V1_0::AdditionalInfo *dstInfo =
+ &dst->u.additional;
+
+ const additional_info_event_t &srcInfo = src.additional_info;
+
+ dstInfo->type =
+ (::android::hardware::sensors::V1_0::AdditionalInfoType)
+ srcInfo.type;
+
+ dstInfo->serial = srcInfo.serial;
+
+ CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32));
+ memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32));
+ break;
+ }
+
+ default:
+ {
+ CHECK_GE((int32_t)dst->sensorType,
+ (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
+ break;
+ }
+ }
+}
+
+void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
+ dst->version = sizeof(sensors_event_t);
+ dst->sensor = src.sensorHandle;
+ dst->type = (int32_t)src.sensorType;
+ dst->reserved0 = 0;
+ dst->timestamp = src.timestamp;
+ dst->flags = 0;
+ dst->reserved1[0] = dst->reserved1[1] = dst->reserved1[2] = 0;
+
+ switch (src.sensorType) {
+ case SensorType::META_DATA:
+ {
+ // Legacy HALs expect the handle reference in the meta data field.
+ // Copy it over from the handle of the event.
+ dst->meta_data.what = (int32_t)src.u.meta.what;
+ dst->meta_data.sensor = src.sensorHandle;
+ // Set the sensor handle to 0 to maintain compatibility.
+ dst->sensor = 0;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION:
+ {
+ dst->acceleration.x = src.u.vec3.x;
+ dst->acceleration.y = src.u.vec3.y;
+ dst->acceleration.z = src.u.vec3.z;
+ dst->acceleration.status = (int8_t)src.u.vec3.status;
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GAME_ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ {
+ dst->data[0] = src.u.vec4.x;
+ dst->data[1] = src.u.vec4.y;
+ dst->data[2] = src.u.vec4.z;
+ dst->data[3] = src.u.vec4.w;
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED:
+ {
+ dst->uncalibrated_gyro.x_uncalib = src.u.uncal.x;
+ dst->uncalibrated_gyro.y_uncalib = src.u.uncal.y;
+ dst->uncalibrated_gyro.z_uncalib = src.u.uncal.z;
+ dst->uncalibrated_gyro.x_bias = src.u.uncal.x_bias;
+ dst->uncalibrated_gyro.y_bias = src.u.uncal.y_bias;
+ dst->uncalibrated_gyro.z_bias = src.u.uncal.z_bias;
+ break;
+ }
+
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::TEMPERATURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ {
+ dst->data[0] = src.u.scalar;
+ break;
+ }
+
+ case SensorType::STEP_COUNTER:
+ {
+ dst->u64.step_counter = src.u.stepCount;
+ break;
+ }
+
+ case SensorType::HEART_RATE:
+ {
+ dst->heart_rate.bpm = src.u.heartRate.bpm;
+ dst->heart_rate.status = (int8_t)src.u.heartRate.status;
+ break;
+ }
+
+ case SensorType::POSE_6DOF: // 15 floats
+ {
+ for (size_t i = 0; i < 15; ++i) {
+ dst->data[i] = src.u.pose6DOF[i];
+ }
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META:
+ {
+ dst->dynamic_sensor_meta.connected = src.u.dynamic.connected;
+ dst->dynamic_sensor_meta.handle = src.u.dynamic.sensorHandle;
+ dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ src.u.dynamic.uuid.data(),
+ 16);
+
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO:
+ {
+ const ::android::hardware::sensors::V1_0::AdditionalInfo &srcInfo =
+ src.u.additional;
+
+ additional_info_event_t *dstInfo = &dst->additional_info;
+ dstInfo->type = (int32_t)srcInfo.type;
+ dstInfo->serial = srcInfo.serial;
+
+ CHECK_EQ(sizeof(srcInfo.u), sizeof(dstInfo->data_int32));
+
+ memcpy(dstInfo->data_int32,
+ &srcInfo.u,
+ sizeof(dstInfo->data_int32));
+
+ break;
+ }
+
+ default:
+ {
+ CHECK_GE((int32_t)src.sensorType,
+ (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->data, src.u.data.data(), 16 * sizeof(float));
+ break;
+ }
+ }
+}
+
+bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut) {
+ if (memOut == nullptr) {
+ return false;
+ }
+
+ switch(memIn.type) {
+ case SharedMemType::ASHMEM:
+ memOut->type = SENSOR_DIRECT_MEM_TYPE_ASHMEM;
+ break;
+ case SharedMemType::GRALLOC:
+ memOut->type = SENSOR_DIRECT_MEM_TYPE_GRALLOC;
+ break;
+ default:
+ return false;
+ }
+
+ switch(memIn.format) {
+ case SharedMemFormat::SENSORS_EVENT:
+ memOut->format = SENSOR_DIRECT_FMT_SENSORS_EVENT;
+ break;
+ default:
+ return false;
+ }
+
+ memOut->size = memIn.size;
+ memOut->handle = memIn.memoryHandle;
+ return true;
+}
+
+int convertFromRateLevel(RateLevel rate) {
+ switch(rate) {
+ case RateLevel::STOP:
+ return SENSOR_DIRECT_RATE_STOP;
+ case RateLevel::NORMAL:
+ return SENSOR_DIRECT_RATE_NORMAL;
+ case RateLevel::FAST:
+ return SENSOR_DIRECT_RATE_FAST;
+ case RateLevel::VERY_FAST:
+ return SENSOR_DIRECT_RATE_VERY_FAST;
+ default:
+ return -1;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h
new file mode 100644
index 0000000..c3a0125
--- /dev/null
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_
+
+#define HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V1_0 {
+namespace implementation {
+
+void convertFromSensor(const sensor_t &src, SensorInfo *dst);
+void convertToSensor(const SensorInfo &src, sensor_t *dst);
+
+void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
+void convertToSensorEvent(const Event &src, sensors_event_t *dst);
+
+bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
+int convertFromRateLevel(RateLevel rate);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/sensors/1.0/default/service.cpp b/sensors/1.0/default/service.cpp
new file mode 100644
index 0000000..65f6d81
--- /dev/null
+++ b/sensors/1.0/default/service.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.sensors@1.0-service"
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::sensors::V1_0::ISensors;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ /* Sensors framework service needs at least two threads.
+ * One thread blocks on a "poll"
+ * The second thread is needed for all other HAL methods.
+ */
+ return defaultPassthroughServiceImplementation<ISensors>(2);
+}
diff --git a/sensors/1.0/types.hal b/sensors/1.0/types.hal
new file mode 100644
index 0000000..c0d8c5d
--- /dev/null
+++ b/sensors/1.0/types.hal
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (C) 2016 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.sensors@1.0;
+
+/**
+ * Please see the Sensors section of source.android.com for an
+ * introduction to and detailed descriptions of Android sensor types:
+ * http://source.android.com/devices/sensors/index.html
+ */
+
+/* Type enumerating various result codes returned from ISensors methods */
+enum Result : int32_t {
+ OK,
+ PERMISSION_DENIED = -1,
+ NO_MEMORY = -12,
+ BAD_VALUE = -22,
+ INVALID_OPERATION = -38,
+};
+
+/*
+ * Sensor HAL modes used in setOperationMode method
+ */
+@export(name="", value_prefix="SENSOR_HAL_", value_suffix="_MODE")
+enum OperationMode : int32_t {
+ NORMAL = 0,
+ DATA_INJECTION = 1,
+};
+
+/*
+ * Sensor type
+ *
+ * Each sensor has a type which defines what this sensor measures and how
+ * measures are reported. See the Base sensors and Composite sensors lists
+ * for complete descriptions:
+ * http://source.android.com/devices/sensors/base_triggers.html
+ * http://source.android.com/devices/sensors/composite_sensors.html
+ *
+ * Device manufacturers (OEMs) can define their own sensor types, for
+ * their private use by applications or services provided by them. Such
+ * sensor types are specific to an OEM and can't be exposed in the SDK.
+ * These types must start at SensorType::DEVICE_PRIVATE_BASE.
+ *
+ * All sensors defined outside of the device private range must correspond to
+ * a type defined in this file, and must satisfy the characteristics listed in
+ * the description of the sensor type.
+ *
+ * Each sensor also has a "typeAsString".
+ * - string type of sensors defined in this file is overridden by Android to
+ * values defined in Android API with "android.sensor." prefix.
+ * Example: for an accelerometer,
+ * type = SensorType::Acclerometer
+ * typeAsString = "" (will be replace by "android.sensor.accelerometer" by
+ * Android frameowrk)
+ * - string type of sensors inside of the device private range MUST be prefixed
+ * by the sensor provider's or OEM reverse domain name. In particular, they
+ * cannot use the "android.sensor." prefix.
+ *
+ * When android introduces a new sensor type that can replace an OEM-defined
+ * sensor type, the OEM must use the official sensor type and stringType on
+ * versions of the HAL that support this new official sensor type.
+ *
+ * Example (made up): Suppose Google's Glass team wants to surface a sensor
+ * detecting that Glass is on a head.
+ * - Such a sensor is not officially supported in android KitKat
+ * - Glass devices launching on KitKat can implement a sensor with
+ * type = 0x10001
+ * typeAsString = "com.google.glass.onheaddetector"
+ * - In L android release, if android decides to define
+ * SensorType::ON_HEAD_DETECTOR and STRING_SensorType::ON_HEAD_DETECTOR,
+ * those types should replace the Glass-team-specific types in all future
+ * launches.
+ * - When launching Glass on the L release, Google should now use the official
+ * type (SensorType::ON_HEAD_DETECTOR) and stringType.
+ * - This way, all applications can now use this sensor.
+ */
+
+/*
+ * Wake up sensors.
+ * Each sensor may have either or both a wake-up and a non-wake variant.
+ * When registered in batch mode, wake-up sensors will wake up the AP when
+ * their FIFOs are full or when the batch timeout expires. A separate FIFO has
+ * to be maintained for wake up sensors and non wake up sensors. The non
+ * wake-up sensors need to overwrite their FIFOs when they are full till the AP
+ * wakes up and the wake-up sensors will wake-up the AP when their FIFOs are
+ * full or when the batch timeout expires without losing events.
+ * Wake-up and non wake-up variants of each sensor can be activated at
+ * different rates independently of each other.
+ *
+ * Note: Proximity sensor and significant motion sensor which were defined in
+ * previous releases are also wake-up sensors and must be treated as such.
+ * Wake-up one-shot sensors like SIGNIFICANT_MOTION cannot be batched, hence
+ * the text about batch above doesn't apply to them. See the definitions of
+ * SensorType::PROXIMITY and SensorType::SIGNIFICANT_MOTION for more info.
+ *
+ * Set SENSOR_FLAG_WAKE_UP flag for all wake-up sensors.
+ *
+ * For example, A device can have two sensors both of SensorType::ACCELEROMETER
+ * and one of them can be a wake_up sensor (with SENSOR_FLAG_WAKE_UP flag set)
+ * and the other can be a regular non wake_up sensor. Both of these sensors
+ * must be activated/deactivated independently of the other.
+ */
+
+@export(name="", value_prefix="SENSOR_TYPE_")
+enum SensorType : int32_t {
+ /* META_DATA is a special event type used to populate the MetaData
+ * structure. It doesn't correspond to a physical sensor. Events of this
+ * type exist only inside the HAL, their primary purpose is to signal the
+ * completion of a flush request.
+ */
+ META_DATA = 0,
+
+ /*
+ * ACCELEROMETER
+ * reporting-mode: continuous
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration of the
+ * device minus the acceleration due to gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ACCELEROMETER = 1,
+
+ /*
+ * MAGNETIC_FIELD
+ * reporting-mode: continuous
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ MAGNETIC_FIELD = 2,
+
+ /*
+ * ORIENTATION
+ * reporting-mode: continuous
+ *
+ * All values are angles in degrees.
+ *
+ * Orientation sensors return sensor events for all 3 axes at a constant
+ * rate defined by setDelay().
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ORIENTATION = 3,
+
+ /*
+ * GYROSCOPE
+ * reporting-mode: continuous
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GYROSCOPE = 4,
+
+ /*
+ * LIGHT
+ * reporting-mode: on-change
+ *
+ * The light sensor value is returned in SI lux units.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ LIGHT = 5,
+
+ /*
+ * PRESSURE
+ * reporting-mode: continuous
+ *
+ * The pressure sensor return the athmospheric pressure in hectopascal (hPa)
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ PRESSURE = 6,
+
+ /* TEMPERATURE is deprecated in the HAL */
+ TEMPERATURE = 7,
+
+ /*
+ * PROXIMITY
+ * reporting-mode: on-change
+ *
+ * The proximity sensor which turns the screen off and back on during calls
+ * is the wake-up proximity sensor. Implement wake-up proximity sensor
+ * before implementing a non wake-up proximity sensor. For the wake-up
+ * proximity sensor set the flag SENSOR_FLAG_WAKE_UP.
+ * The value corresponds to the distance to the nearest object in
+ * centimeters.
+ */
+ PROXIMITY = 8,
+
+ /*
+ * GRAVITY
+ * reporting-mode: continuous
+ *
+ * A gravity output indicates the direction of and magnitude of gravity in
+ * the devices's coordinates.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GRAVITY = 9,
+
+ /*
+ * LINEAR_ACCELERATION
+ * reporting-mode: continuous
+ *
+ * Indicates the linear acceleration of the device in device coordinates,
+ * not including gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ LINEAR_ACCELERATION = 10,
+
+ /*
+ * ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * The rotation vector symbolizes the orientation of the device relative to
+ * the East-North-Up coordinates frame.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ROTATION_VECTOR = 11,
+
+ /*
+ * RELATIVE_HUMIDITY
+ * reporting-mode: on-change
+ *
+ * A relative humidity sensor measures relative ambient air humidity and
+ * returns a value in percent.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ RELATIVE_HUMIDITY = 12,
+
+ /*
+ * AMBIENT_TEMPERATURE
+ * reporting-mode: on-change
+ *
+ * The ambient (room) temperature in degree Celsius.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ AMBIENT_TEMPERATURE = 13,
+
+ /*
+ * MAGNETIC_FIELD_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * Similar to MAGNETIC_FIELD, but the hard iron calibration is
+ * reported separately instead of being included in the measurement.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ MAGNETIC_FIELD_UNCALIBRATED = 14,
+
+ /*
+ * GAME_ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * Similar to ROTATION_VECTOR, but not using the geomagnetic
+ * field.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GAME_ROTATION_VECTOR = 15,
+
+ /*
+ * GYROSCOPE_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GYROSCOPE_UNCALIBRATED = 16,
+
+ /*
+ * SIGNIFICANT_MOTION
+ * reporting-mode: one-shot
+ *
+ * A sensor of this type triggers an event each time significant motion
+ * is detected and automatically disables itself.
+ * For Significant Motion sensor to be useful, it must be defined as a
+ * wake-up sensor. (set SENSOR_FLAG_WAKE_UP). Implement the wake-up
+ * significant motion sensor. A non wake-up version is not useful.
+ * The only allowed value to return is 1.0.
+ */
+ SIGNIFICANT_MOTION = 17,
+
+ /*
+ * STEP_DETECTOR
+ * reporting-mode: special
+ *
+ * A sensor of this type triggers an event each time a step is taken
+ * by the user. The only allowed value to return is 1.0 and an event
+ * is generated for each step.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ STEP_DETECTOR = 18,
+
+ /*
+ * STEP_COUNTER
+ * reporting-mode: on-change
+ *
+ * A sensor of this type returns the number of steps taken by the user since
+ * the last reboot while activated. The value is returned as a uint64_t and
+ * is reset to zero only on a system / android reboot.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ STEP_COUNTER = 19,
+
+ /*
+ * GEOMAGNETIC_ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * Similar to ROTATION_VECTOR, but using a magnetometer instead
+ * of using a gyroscope.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GEOMAGNETIC_ROTATION_VECTOR = 20,
+
+ /*
+ * HEART_RATE
+ * reporting-mode: on-change
+ *
+ * A sensor of this type returns the current heart rate.
+ * The events contain the current heart rate in beats per minute (BPM) and
+ * the status of the sensor during the measurement. See "HeartRate" below
+ * for more details.
+ *
+ * Because this sensor is on-change, events must be generated when and only
+ * when heart_rate.bpm or heart_rate.status have changed since the last
+ * event. In particular, upon the first activation, unless the device is
+ * known to not be on the body, the status field of the first event must be
+ * set to SensorStatus::UNRELIABLE. The event should be generated no faster
+ * than every period_ns passed to setDelay() or to batch().
+ * See the definition of the on-change reporting mode for more information.
+ *
+ * SensorInfo.requiredPermission must be set to
+ * SENSOR_PERMISSION_BODY_SENSORS.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ HEART_RATE = 21,
+
+ /*
+ * WAKE_UP_TILT_DETECTOR
+ * reporting-mode: special (setDelay has no impact)
+ *
+ * A sensor of this type generates an event each time a tilt event is
+ * detected. A tilt event must be generated if the direction of the
+ * 2-seconds window average gravity changed by at least 35 degrees since the
+ * activation or the last trigger of the sensor.
+ *
+ * reference_estimated_gravity = average of accelerometer measurements over
+ * the first 1 second after activation or the estimated gravity at the last
+ * trigger.
+ *
+ * current_estimated_gravity = average of accelerometer measurements over
+ * the last 2 seconds.
+ *
+ * trigger when
+ * angle(reference_estimated_gravity, current_estimated_gravity)
+ * > 35 degrees
+ *
+ * Large accelerations without a change in phone orientation must not
+ * trigger a tilt event.
+ * For example, a sharp turn or strong acceleration while driving a car
+ * must not trigger a tilt event, even though the angle of the average
+ * acceleration might vary by more than 35 degrees.
+ *
+ * Typically, this sensor is implemented with the help of only an
+ * accelerometer. Other sensors can be used as well if they do not increase
+ * the power consumption significantly. This is a low power sensor that
+ * must allow the AP to go into suspend mode. Do not emulate this sensor
+ * in the HAL.
+ * Like other wake up sensors, the driver is expected to a hold a wake_lock
+ * with a timeout of 200 ms while reporting this event. The only allowed
+ * return value is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ TILT_DETECTOR = 22,
+
+ /*
+ * WAKE_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor enabling waking up the device based on a device specific motion.
+ *
+ * When this sensor triggers, the device behaves as if the power button was
+ * pressed, turning the screen on. This behavior (turning on the screen when
+ * this sensor triggers) might be deactivated by the user in the device
+ * settings. Changes in settings do not impact the behavior of the sensor:
+ * only whether the framework turns the screen on when it triggers.
+ *
+ * The actual gesture to be detected is not specified, and can be chosen by
+ * the manufacturer of the device.
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ WAKE_GESTURE = 23,
+
+ /*
+ * GLANCE_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor enabling briefly turning the screen on to enable the user to
+ * glance content on screen based on a specific motion. The device must
+ * turn the screen off after a few moments.
+ *
+ * When this sensor triggers, the device turns the screen on momentarily
+ * to allow the user to glance notifications or other content while the
+ * device remains locked in a non-interactive state (dozing). This behavior
+ * (briefly turning on the screen when this sensor triggers) might be
+ * deactivated by the user in the device settings.
+ * Changes in settings do not impact the behavior of the sensor: only
+ * whether the framework briefly turns the screen on when it triggers.
+ *
+ * The actual gesture to be detected is not specified, and can be chosen by
+ * the manufacturer of the device.
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ GLANCE_GESTURE = 24,
+
+ /**
+ * PICK_UP_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor of this type triggers when the device is picked up regardless of
+ * wherever is was before (desk, pocket, bag). The only allowed return value
+ * is 1.0. This sensor de-activates itself immediately after it triggers.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ PICK_UP_GESTURE = 25,
+
+ /*
+ * WRIST_TILT_GESTURE
+ * trigger-mode: special
+ * wake-up sensor: yes
+ *
+ * A sensor of this type triggers an event each time a tilt of the
+ * wrist-worn device is detected.
+ *
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ WRIST_TILT_GESTURE = 26,
+
+ /*
+ * DEVICE_ORIENTATION
+ * reporting-mode: on-change
+ *
+ * The current orientation of the device. The value is reported in
+ * the "scalar" element of the EventPayload in Event. The
+ * only values that can be reported are (please refer to Android Sensor
+ * Coordinate System to understand the X and Y axis direction with respect
+ * to default orientation):
+ * - 0: device is in default orientation (Y axis is vertical and points up)
+ * - 1: device is rotated 90 degrees counter-clockwise from default
+ * orientation (X axis is vertical and points up)
+ * - 2: device is rotated 180 degrees from default orientation (Y axis is
+ * vertical and points down)
+ * - 3: device is rotated 90 degrees clockwise from default orientation
+ * (X axis is vertical and points down)
+ *
+ * Moving the device to an orientation where the Z axis is vertical (either
+ * up or down) must not cause a new event to be reported.
+ *
+ * To improve the user experience of this sensor, it is recommended to
+ * implement some physical (i.e., rotation angle) and temporal (i.e., delay)
+ * hysteresis. In other words, minor or transient rotations must not cause
+ * a new event to be reported.
+ *
+ * This is a low power sensor that intended to reduce interrupts of
+ * application processor and thus allow it to go sleep. Use hardware
+ * implementation based on low power consumption sensors, such as
+ * accelerometer. Device must not emulate this sensor in the HAL.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ DEVICE_ORIENTATION = 27,
+
+ /*
+ * POSE_6DOF
+ * trigger-mode: continuous
+ *
+ * A sensor of this type returns the pose of the device.
+ * Pose of the device is defined as the orientation of the device from a
+ * Earth Centered Earth Fixed frame and the translation from an arbitrary
+ * point at subscription.
+ *
+ * This sensor can be high power. It can use any and all of the following
+ * . Accelerometer
+ * . Gyroscope
+ * . Camera
+ * . Depth Camera
+ *
+ */
+ POSE_6DOF = 28,
+
+ /*
+ * STATIONARY_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is still/stationary
+ * for a while. The period of time to monitor for stationarity must be
+ * greater than 5 seconds. The latency must be less than 10 seconds.
+ *
+ * Stationarity here refers to absolute stationarity. eg: device on desk.
+ *
+ * The only allowed value to return is 1.0.
+ */
+ STATIONARY_DETECT = 29,
+
+ /*
+ * MOTION_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is not still for
+ * for a while. The period of time to monitor for stationarity must be
+ * greater than 5 seconds. The latency must be less than 10 seconds.
+ *
+ * Motion here refers to any mechanism in which the device is causes to be
+ * moved in its inertial frame. eg: Pickin up the device and walking with it
+ * to a nearby room may trigger motion wherewas keeping the device on a
+ * table on a smooth train moving at constant velocity may not trigger
+ * motion.
+ *
+ * The only allowed value to return is 1.0.
+ */
+ MOTION_DETECT = 30,
+
+ /*
+ * HEART_BEAT
+ * trigger mode: continuous
+ *
+ * A sensor of this type returns an event everytime a hear beat peak is
+ * detected.
+ *
+ * Peak here ideally corresponds to the positive peak in the QRS complex of
+ * and ECG signal.
+ *
+ * The sensor is not expected to be optimized for latency. As a guide, a
+ * latency of up to 10 seconds is acceptable. However, the timestamp attached
+ * to the event must be accuratly correspond to the time the peak occured.
+ *
+ * The sensor event contains a parameter for the confidence in the detection
+ * of the peak where 0.0 represent no information at all, and 1.0 represents
+ * certainty.
+ */
+ HEART_BEAT = 31,
+
+ /**
+ * DYNAMIC_SENSOR_META
+ * trigger-mode: special
+ * wake-up sensor: yes
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to
+ * or removed from the system. At most one sensor of this type can be
+ * present in one sensor HAL implementation and presence of a sensor of this
+ * type in sensor HAL implementation indicates that this sensor HAL supports
+ * dynamic sensor feature. Operations, such as batch, activate and setDelay,
+ * to this special purpose sensor must be treated as no-op and return
+ * successful; flush() also has to generate flush complete event as if this
+ * is a sensor that does not support batching.
+ *
+ * A dynamic sensor connection indicates connection of a physical device or
+ * instantiation of a virtual sensor backed by algorithm; and a dynamic
+ * sensor disconnection indicates the the opposite. A sensor event of
+ * DYNAMIC_SENSOR_META type should be delivered regardless of
+ * the activation status of the sensor in the event of dynamic sensor
+ * connection and disconnection. In the sensor event, besides the common
+ * data entries, "dynamic_sensor_meta", which includes fields for connection
+ * status, handle of the sensor involved, pointer to sensor_t structure and
+ * a uuid field, must be populated.
+ *
+ * At a dynamic sensor connection event, fields of sensor_t structure
+ * referenced by a pointer in dynamic_sensor_meta must be filled as if it
+ * was regular sensors. Sensor HAL is responsible for recovery of memory if
+ * the corresponding data is dynamicially allocated. However, the the
+ * pointer must be valid until the first activate call to the sensor
+ * reported in this connection event. At a dynamic sensor disconnection,
+ * the sensor_t pointer must be NULL.
+ *
+ * The sensor handle assigned to dynamic sensors must never be the same as
+ * that of any regular static sensors, and must be unique until next boot.
+ * In another word, if a handle h is used for a dynamic sensor A, that same
+ * number cannot be used for the same dynamic sensor A or another dynamic
+ * sensor B even after disconnection of A until reboot.
+ *
+ * The UUID field will be used for identifying the sensor in addition to
+ * name, vendor and version and type. For physical sensors of the same
+ * model, all sensors will have the same values in sensor_t, but the UUID
+ * must be unique and persistent for each individual unit. An all zero
+ * UUID indicates it is not possible to differentiate individual sensor
+ * unit.
+ *
+ */
+ DYNAMIC_SENSOR_META = 32,
+
+ /**
+ * ADDITIONAL_INFO
+ * reporting-mode: N/A
+ *
+ * This sensor type is for delivering additional sensor information aside
+ * from sensor event data.
+ * Additional information may include sensor front-end group delay, internal
+ * calibration parameters, noise level metrics, device internal temperature,
+ * etc.
+ *
+ * This type will never bind to a sensor. In other words, no sensor in the
+ * sensor list can have the type SENSOR_TYPE_ADDITIONAL_INFO. If a
+ * sensor HAL supports sensor additional information feature, it reports
+ * sensor_event_t with "sensor" field set to handle of the reporting sensor
+ * and "type" field set to ADDITIONAL_INFO. Delivery of
+ * additional information events is triggered under two conditions: an
+ * enable activate() call or a flush() call to the corresponding sensor.
+ * Besides, time varying parameters can update infrequently without being
+ * triggered. Device is responsible to control update rate. The recommend
+ * update rate is less than 1/1000 of sensor event rate or less than once
+ * per minute in average.
+ *
+ * A single additional information report consists of multiple frames.
+ * Sequences of these frames are ordered using timestamps, which means the
+ * timestamps of sequential frames have to be at least 1 nanosecond apart
+ * from each other. Each frame is a sensor_event_t delivered through the HAL
+ * interface, with related data stored in the "additional_info" field, which
+ * is of type additional_info_event_t.
+ * The "type" field of additional_info_event_t denotes the nature of the
+ * payload data (see additional_info_type_t).
+ * The "serial" field is used to keep the sequence of payload data that
+ * spans multiple frames. The first frame of the entire report is always of
+ * type AINFO_BEGIN, and the last frame is always AINFO_END.
+ *
+ * If flush() was triggering the report, all additional information frames
+ * must be delivered after flush complete event.
+ */
+ ADDITIONAL_INFO = 33,
+
+ /*
+ * LOW_LATENCY_OFFBODY_DETECT
+ * trigger-mode: on-change
+ * wake-up sensor: yes
+ *
+ * A sensor of this type is defined for devices that are supposed to be worn
+ * by the user in the normal use case (such as a watch, wristband, etc) and
+ * is not yet defined for other device.
+ *
+ * A sensor of this type triggers an event each time the wearable device
+ * is removed from the body and each time it's put back onto the body.
+ * It must be low-latency and be able to detect the on-body to off-body
+ * transition within one second (event delivery time included),
+ * and 3-second latency to determine the off-body to on-body transition
+ * (event delivery time included).
+ *
+ * There are only two valid event values for the sensor to return :
+ * 0.0 for off-body
+ * 1.0 for on-body
+ *
+ */
+ LOW_LATENCY_OFFBODY_DETECT = 34,
+
+ /*
+ * ACCELEROMETER_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration of the
+ * device minus the acceleration due to gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ACCELEROMETER_UNCALIBRATED = 35,
+
+ /*
+ * Base for device manufacturers private sensor types.
+ * These sensor types can't be exposed in the SDK.
+ */
+ DEVICE_PRIVATE_BASE = 0x10000
+};
+
+@export(name="", value_prefix="SENSOR_FLAG_")
+enum SensorFlagBits : uint32_t {
+ /*
+ * Whether this sensor wakes up the AP from suspend mode when data is
+ * available. Whenever sensor events are delivered from a wake_up sensor,
+ * the driver needs to hold a wake_lock till the events are read by the
+ * SensorService i.e till ISensors::poll() is called the next time.
+ * Once poll is called again it means events have been read by the
+ * SensorService, the driver can safely release the wake_lock. SensorService
+ * will continue to hold a wake_lock till the app actually reads the events.
+ */
+ WAKE_UP = 1,
+
+ /*
+ * Reporting modes for various sensors. Each sensor will have exactly one of
+ * these modes set.
+ * The least significant 2nd, 3rd and 4th bits are used to represent four
+ * possible reporting modes.
+ */
+ CONTINUOUS_MODE = 0,
+ ON_CHANGE_MODE = 2,
+ ONE_SHOT_MODE = 4,
+ SPECIAL_REPORTING_MODE = 6,
+
+ /*
+ * Set this flag if the sensor supports data_injection mode and allows data
+ * to be injected from the SensorService. When in data_injection ONLY
+ * sensors with this flag set are injected sensor data and only sensors with
+ * this flag set are activated. Eg: Accelerometer and Step Counter sensors
+ * can be set with this flag and SensorService will inject accelerometer
+ * data and read the corresponding step counts.
+ */
+ DATA_INJECTION = 0x10,
+
+ /*
+ * Set this flag if the sensor is a dynamically connected sensor. See
+ * DynamicSensorInfo and DYNAMIC_SENSOR_META for details.
+ */
+ DYNAMIC_SENSOR = 0x20,
+
+ /*
+ * Set this flag if sensor additional information is supported.
+ * See ADDITIONAL_INFO and AdditionalInfo for details.
+ */
+ ADDITIONAL_INFO = 0x40,
+
+ /*
+ * Set this flag if sensor suppor direct channel backed by ashmem.
+ * See SharedMemType and registerDirectChannel for more details.
+ */
+ DIRECT_CHANNEL_ASHMEM = 0x400,
+
+ /*
+ * Set this flag if sensor suppor direct channel backed by gralloc HAL memory.
+ * See SharedMemType and registerDirectChannel for more details.
+ */
+ DIRECT_CHANNEL_GRALLOC = 0x800,
+
+ /*
+ * Flags mask for reporting mode of sensor.
+ */
+ MASK_REPORTING_MODE = 0xE,
+
+ /*
+ * Flags mask for direct report maximum rate level support.
+ * See RateLevel.
+ */
+ MASK_DIRECT_REPORT = 0x380,
+
+ /*
+ * Flags mask for all direct channel support bits.
+ * See SharedMemType.
+ */
+ MASK_DIRECT_CHANNEL = 0xC00,
+};
+
+@export(name="sensor_flag_shift_t", value_prefix="SENSOR_FLAG_SHIFT_")
+enum SensorFlagShift : uint8_t {
+ REPORTING_MODE = 1,
+ DATA_INJECTION = 4,
+ DYNAMIC_SENSOR = 5,
+ ADDITIONAL_INFO = 6,
+ DIRECT_REPORT = 7,
+ DIRECT_CHANNEL = 10,
+};
+
+struct SensorInfo {
+ /* handle that identifies this sensors. This handle is used to reference
+ * this sensor throughout the HAL API.
+ */
+ int32_t sensorHandle;
+
+ /* Name of this sensor.
+ * All sensors of the same "type" must have a different "name".
+ */
+ string name;
+
+ /* vendor of the hardware part */
+ string vendor;
+
+ /* version of the hardware part + driver. The value of this field
+ * must increase when the driver is updated in a way that changes the
+ * output of this sensor. This is important for fused sensors when the
+ * fusion algorithm is updated.
+ */
+ int32_t version;
+
+ /* this sensor's type. */
+ SensorType type;
+
+ /* type of this sensor as a string.
+ *
+ * When defining an OEM specific sensor or sensor manufacturer specific
+ * sensor, use your reserve domain name as a prefix.
+ * e.g. com.google.glass.onheaddetector
+ *
+ * For sensors of known type defined in SensorType (value <
+ * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string.
+ */
+ string typeAsString;
+
+ /* maximum range of this sensor's value in SI units */
+ float maxRange;
+
+ /* smallest difference between two values reported by this sensor */
+ float resolution;
+
+ /* rough estimate of this sensor's power consumption in mA */
+ float power;
+
+ /* this value depends on the reporting mode:
+ *
+ * continuous: minimum sample period allowed in microseconds
+ * on-change : 0
+ * one-shot :-1
+ * special : 0, unless otherwise noted
+ */
+ int32_t minDelay;
+
+ /* number of events reserved for this sensor in the batch mode FIFO.
+ * If there is a dedicated FIFO for this sensor, then this is the
+ * size of this FIFO. If the FIFO is shared with other sensors,
+ * this is the size reserved for that sensor and it can be zero.
+ */
+ uint32_t fifoReservedEventCount;
+
+ /* maximum number of events of this sensor that could be batched.
+ * This is especially relevant when the FIFO is shared between
+ * several sensors; this value is then set to the size of that FIFO.
+ */
+ uint32_t fifoMaxEventCount;
+
+ /* permission required to see this sensor, register to it and receive data.
+ * Set to "" if no permission is required. Some sensor types like the
+ * heart rate monitor have a mandatory require_permission.
+ * For sensors that always require a specific permission, like the heart
+ * rate monitor, the android framework might overwrite this string
+ * automatically.
+ */
+ string requiredPermission;
+
+ /* This value is defined only for continuous mode and on-change sensors.
+ * It is the delay between two sensor events corresponding to the lowest
+ * frequency that this sensor supports. When lower frequencies are requested
+ * through batch()/setDelay() the events will be generated at this frequency
+ * instead.
+ * It can be used by the framework or applications to estimate when the
+ * batch FIFO may be full.
+ *
+ * NOTE: periodNs is in nanoseconds where as maxDelay/minDelay are in
+ * microseconds.
+ *
+ * continuous, on-change: maximum sampling period allowed in
+ * microseconds.
+ *
+ * one-shot, special : 0
+ */
+ int32_t maxDelay;
+
+ /* Bitmask of SensorFlagBits */
+ bitfield<SensorFlagBits> flags;
+};
+
+@export(name="", value_prefix="SENSOR_STATUS_")
+enum SensorStatus : int8_t {
+ NO_CONTACT = -1,
+ UNRELIABLE = 0,
+ ACCURACY_LOW = 1,
+ ACCURACY_MEDIUM = 2,
+ ACCURACY_HIGH = 3,
+};
+
+struct Vec3 {
+ float x;
+ float y;
+ float z;
+ SensorStatus status;
+};
+
+struct Vec4 {
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+struct Uncal {
+ float x;
+ float y;
+ float z;
+ float x_bias;
+ float y_bias;
+ float z_bias;
+};
+
+struct HeartRate {
+ /* Heart rate in beats per minute.
+ * Set to 0 when status is SensorStatus::UNRELIABLE or
+ * SensorStatus::NO_CONTACT
+ */
+ float bpm;
+
+ /* Status of the heart rate sensor for this reading. */
+ SensorStatus status;
+};
+
+@export(name="")
+enum MetaDataEventType : uint32_t {
+ META_DATA_FLUSH_COMPLETE = 1,
+};
+
+struct MetaData {
+ MetaDataEventType what;
+};
+
+struct DynamicSensorInfo {
+ bool connected;
+ int32_t sensorHandle;
+
+ /* UUID of a dynamic sensor (using RFC 4122 byte order)
+ * For UUID 12345678-90AB-CDEF-1122-334455667788 the uuid field is
+ * initialized as:
+ * {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x11, ...}
+ */
+ uint8_t[16] uuid;
+};
+
+@export(name="additional_info_type_t")
+enum AdditionalInfoType : uint32_t {
+ /* Marks the beginning of additional information frames */
+ AINFO_BEGIN = 0,
+
+ /* Marks the end of additional information frames */
+ AINFO_END = 1,
+
+ /* Estimation of the delay that is not tracked by sensor timestamps. This
+ * includes delay introduced by sensor front-end filtering, data transport,
+ * etc.
+ * float[2]: delay in seconds, standard deviation of estimated value
+ */
+ AINFO_UNTRACKED_DELAY = 0x10000,
+
+ /* float: Celsius temperature */
+ AINFO_INTERNAL_TEMPERATURE,
+
+ /* First three rows of a homogeneous matrix, which represents calibration to
+ * a three-element vector raw sensor reading.
+ * float[12]: 3x4 matrix in row major order
+ */
+ AINFO_VEC3_CALIBRATION,
+
+ /* Location and orientation of sensor element in the device frame: origin is
+ * the geometric center of the mobile device screen surface; the axis
+ * definition corresponds to Android sensor definitions.
+ * float[12]: 3x4 matrix in row major order
+ */
+ AINFO_SENSOR_PLACEMENT,
+
+ /* float[2]: raw sample period in seconds,
+ * standard deviation of sampling period
+ */
+ AINFO_SAMPLING,
+
+ // Sampling channel modeling information section
+
+ /* int32_t: noise type
+ * float[n]: parameters
+ */
+ AINFO_CHANNEL_NOISE = 0x20000,
+
+ /* float[3]: sample period, standard deviation of sample period,
+ * quantization unit
+ */
+ AINFO_CHANNEL_SAMPLER,
+
+ /* Represents a filter:
+ * \sum_j a_j y[n-j] == \sum_i b_i x[n-i]
+ *
+ * int32_t[3]: number of feedforward coeffients M,
+ * number of feedback coefficients N (for FIR filter, N = 1).
+ * bit mask that represents which element the filter is applied
+ * to. (bit 0==1 means this filter applies to vector element 0).
+ * float[M+N]: filter coefficients (b0, b1, ..., b_{M-1}), then
+ * (a0, a1, ..., a_{N-1}), a0 is always 1.
+ *
+ * Multiple frames may be needed for higher number of taps.
+ */
+ AINFO_CHANNEL_FILTER,
+
+ /* int32_t[2]: size in (row, column) ... 1st frame
+ * float[n]: matrix element values in row major order.
+ */
+ AINFO_CHANNEL_LINEAR_TRANSFORM,
+
+ /* int32_t[2]: extrapolate method, interpolate method
+ * float[n]: mapping key points in pairs, (in, out)...
+ * (may be used to model saturation).
+ */
+ AINFO_CHANNEL_NONLINEAR_MAP,
+
+ /* int32_t: resample method (0-th order, 1st order...)
+ * float[1]: resample ratio (upsampling if < 1.0, downsampling if > 1.0).
+ */
+ AINFO_CHANNEL_RESAMPLER,
+
+ /* Operation environment parameters section
+ * Types in the following section is sent down (instead of reported from)
+ * device as additional information to aid sensor operation. Data is sent
+ * via injectSensorData() function to sensor handle -1 denoting all sensors
+ * in device.
+ */
+
+ /* Local geomagnetic field information based on device geo location. This
+ * type is primarily for for magnetic field calibration and rotation vector
+ * sensor fusion.
+ * float[3]: strength (uT), declination and inclination angle (rad).
+ */
+ AINFO_LOCAL_GEOMAGNETIC_FIELD = 0x30000,
+
+ /* Local gravitational acceleration strength at device geo location.
+ * float: gravitational acceleration norm in m/s^2.
+ */
+ AINFO_LOCAL_GRAVITY,
+
+ /* Device dock state.
+ * int32_t: dock state following Android API Intent.EXTRA_DOCK_STATE
+ * definition, undefined value is ignored.
+ */
+ AINFO_DOCK_STATE,
+
+ /* High performance mode hint. Device is able to use up more power and take
+ * more reources to improve throughput and latency in high performance mode.
+ * One possible use case is virtual reality, when sensor latency need to be
+ * carefully controlled.
+ * int32_t: 1 or 0, denote if device is in/out of high performance mode,
+ * other values is ignored.
+ */
+ AINFO_HIGH_PERFORMANCE_MODE,
+
+ /* Magnetic field calibration hint. Device is notified when manually
+ * triggered magnetic field calibration procedure is started or stopped. The
+ * calibration procedure is assumed timed out after 1 minute from start,
+ * even if an explicit stop is not received.
+ *
+ * int32_t: 1 for start, 0 for stop, other value is ignored.
+ */
+ AINFO_MAGNETIC_FIELD_CALIBRATION,
+
+ /* Custom information */
+ AINFO_CUSTOM_START = 0x10000000,
+
+ /* Debugging */
+ AINFO_DEBUGGING_START = 0x40000000,
+};
+
+struct AdditionalInfo {
+ /* type of payload data, see AdditionalInfoType */
+ AdditionalInfoType type;
+
+ /* sequence number of this frame for this type */
+ int32_t serial;
+
+ union Payload {
+ int32_t[14] data_int32;
+ float[14] data_float;
+ } u;
+};
+
+/* acceleration values are in meter per second per second (m/s^2)
+ * magnetic vector values are in micro-Tesla (uT)
+ * orientation values are in degrees
+ * gyroscope values are in rad/s
+ * temperature is in degrees centigrade (Celsius)
+ * distance in centimeters
+ * light in SI lux units
+ * pressure in hectopascal (hPa)
+ * relative humidity in percent
+ */
+union EventPayload {
+ /* SensorType::ACCELEROMETER, SensorType::MAGNETIC_FIELD,
+ * SensorType::ORIENTATION, SensorType::GYROSCOPE, SensorType::GRAVITY,
+ * SensorType::LINEAR_ACCELERATION
+ */
+ Vec3 vec3;
+
+ /* SensorType::ROTATION_VECTOR, SensorType::GAME_ROTATION_VECTOR,
+ * SensorType::GEOMAGNETIC_ROTATION_VECTOR
+ */
+ Vec4 vec4;
+
+ /* SensorType::MAGNETIC_FIELD_UNCALIBRATED,
+ * SensorType::GYROSCOPE_UNCALIBRATED
+ * SensorType::ACCELEROMETER_UNCALIBRATED
+ */
+ Uncal uncal;
+
+ /* SensorType::META_DATA */
+ MetaData meta;
+
+ /* SensorType::DEVICE_ORIENTATION, SensorType::LIGHT, SensorType::PRESSURE,
+ * SensorType::TEMPERATURE, SensorType::PROXIMITY,
+ * SensorType::RELATIVE_HUMIDITY, SensorType::AMBIENT_TEMPERATURE,
+ * SensorType::SIGNIFICANT_MOTION, SensorType::STEP_DETECTOR,
+ * SensorType::TILT_DETECTOR, SensorType::WAKE_GESTURE,
+ * SensorType::GLANCE_GESTURE, SensorType::PICK_UP_GESTURE,
+ * SensorType::WRIST_TILT_GESTURE, SensorType::STATIONARY_DETECT,
+ * SensorType::MOTION_DETECT, SensorType::HEART_BEAT
+ */
+ float scalar;
+
+ /* SensorType::STEP_COUNTER */
+ uint64_t stepCount;
+
+ /* SensorType::HEART_RATE */
+ HeartRate heartRate;
+
+ /* SensorType::POSE_6DOF */
+ float[15] pose6DOF;
+
+ /* SensorType::DYNAMIC_SENSOR_META */
+ DynamicSensorInfo dynamic;
+
+ /* SensorType::ADDITIONAL_INFO */
+ AdditionalInfo additional;
+
+ /* undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE */
+ float[16] data;
+};
+
+struct Event {
+ /* Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase. */
+ int64_t timestamp;
+
+ /* sensor identifier */
+ int32_t sensorHandle;
+
+ SensorType sensorType;
+
+ /* Union discriminated on sensorType */
+ EventPayload u;
+};
+
+/**
+ * Direct report rate level definition. Except for SENSOR_DIRECT_RATE_STOP, each
+ * rate level covers the range (55%, 220%] * nominal report rate. For example,
+ * if config direct report specify a rate level SENSOR_DIRECT_RATE_FAST, it is
+ * legal for sensor hardware to report event at a rate greater than 110Hz, and
+ * less or equal to 440Hz. Note that rate has to remain steady without variation
+ * before new rate level is configured, i.e. if a sensor is configured to
+ * SENSOR_DIRECT_RATE_FAST and starts to report event at 256Hz, it cannot
+ * change rate to 128Hz after a few seconds of running even if 128Hz is also in
+ * the legal range of SENSOR_DIRECT_RATE_FAST. Thus, it is recommended to
+ * associate report rate with RateLvel statically for single sensor.
+ */
+@export(name="direct_rate_level_t", value_prefix="SENSOR_DIRECT_RATE_")
+enum RateLevel : int32_t {
+ STOP, // stop
+ NORMAL, // nominal 50Hz
+ FAST, // nominal 200Hz
+ VERY_FAST, // nominal 800Hz
+};
+
+/**
+ * Direct channel shared memory types. See struct SharedMemInfo.
+ */
+@export(name="direct_mem_type_t", value_prefix="SENSOR_DIRECT_MEM_TYPE_")
+enum SharedMemType : int32_t {
+ // handle contains 1 fd (ashmem handle) and 0 int.
+ ASHMEM = 1,
+ // handle definition matches gralloc HAL.
+ GRALLOC
+};
+
+
+/**
+ * Direct channel lock-free queue format, this defines how the shared memory is
+ * interpreted by both sensor hardware and application.
+ *
+ * @see SharedMemInfo.
+ */
+@export(name="direct_format_t", value_prefix="SENSOR_DIRECT_FMT_")
+enum SharedMemFormat : int32_t {
+ SENSORS_EVENT = 1, // shared memory is formated as an array of data
+ // elements. See SensorsEventFormatOffset for details.
+ // Upon return of channel registration call, the
+ // shared memory space must be formated to all 0 by HAL.
+};
+
+enum SensorsEventFormatOffset : uint16_t {
+ // offset type name
+ //-----------------------------------
+ // 0x0000 int32_t size (always 104)
+ // 0x0004 int32_t sensor report token
+ // 0x0008 int32_t type (see SensorType)
+ // 0x000C uint32_t atomic counter
+ // 0x0010 int64_t timestamp (see Event)
+ // 0x0018 float[16]/ data
+ // int64_t[8]
+ // 0x0058 int32_t[4] reserved (set to zero)
+ SIZE_FIELD = 0x0,
+ REPORT_TOKEN = 0x4,
+ SENSOR_TYPE = 0x8,
+ ATOMIC_COUNTER = 0xC,
+ TIMESTAMP = 0x10,
+ DATA = 0x18,
+ RESERVED = 0x58,
+ TOTAL_LENGTH = 0x68
+};
+
+/**
+ * Shared memory information for a direct channel
+ */
+struct SharedMemInfo {
+ SharedMemType type; // shared memory type
+ SharedMemFormat format;
+ uint32_t size; // size of the memory region, in bytes
+ handle memoryHandle; // shared memory handle, it is interpreted
+ // depending on type field, see SharedMemType.
+};
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..af149ba
--- /dev/null
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalSensorsV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalSensorsV1_0TargetTest.cpp"],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
new file mode 100644
index 0000000..d21b512
--- /dev/null
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -0,0 +1,1389 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "sensors_hidl_hal_test"
+#include <android-base/logging.h>
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/log.h>
+#include <cutils/ashmem.h>
+#include <utils/SystemClock.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <hardware/sensors.h> // for sensor type strings
+
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <unordered_set>
+#include <vector>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using namespace ::android::hardware::sensors::V1_0;
+
+// Test environment for sensors
+class SensorsHidlTest;
+class SensorsHidlEnvironment : public ::testing::Environment {
+ public:
+ // get the test environment singleton
+ static SensorsHidlEnvironment* Instance() {
+ static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment;
+ return instance;
+ }
+
+ virtual void SetUp();
+ virtual void TearDown();
+
+ // Get and clear all events collected so far (like "cat" shell command).
+ // If output is nullptr, it clears all collected events.
+ void catEvents(std::vector<Event>* output);
+
+ // set sensor event collection status
+ void setCollection(bool enable);
+
+ private:
+ friend SensorsHidlTest;
+ // sensors hidl service
+ sp<ISensors> sensors;
+
+ SensorsHidlEnvironment() {}
+
+ void addEvent(const Event& ev);
+ void startPollingThread();
+ void resetHal();
+ static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
+
+ bool collectionEnabled;
+ std::shared_ptr<bool> stopThread;
+ std::thread pollThread;
+ std::vector<Event> events;
+ std::mutex events_mutex;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment);
+};
+
+void SensorsHidlEnvironment::SetUp() {
+ resetHal();
+
+ ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
+
+ collectionEnabled = false;
+ startPollingThread();
+
+ // In case framework just stopped for test and there is sensor events in the pipe,
+ // wait some time for those events to be cleared to avoid them messing up the test.
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+}
+
+void SensorsHidlEnvironment::TearDown() {
+ if (stopThread) {
+ *stopThread = true;
+ }
+ pollThread.detach();
+}
+
+void SensorsHidlEnvironment::resetHal() {
+ // wait upto 100ms * 10 = 1s for hidl service.
+ constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+
+ std::string step;
+ bool succeed = false;
+ for (size_t retry = 10; retry > 0; --retry) {
+ // this do ... while is for easy error handling
+ do {
+ step = "getService()";
+ sensors = ISensors::getService();
+ if (sensors == nullptr) {
+ break;
+ }
+
+ step = "poll() check";
+ // Poke ISensor service. If it has lingering connection from previous generation of
+ // system server, it will kill itself. There is no intention to handle the poll result,
+ // which will be done since the size is 0.
+ if(!sensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+ break;
+ }
+
+ step = "getSensorList";
+ std::vector<SensorInfo> sensorList;
+ if (!sensors->getSensorsList(
+ [&] (const ::android::hardware::hidl_vec<SensorInfo> &list) {
+ sensorList.reserve(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ sensorList.push_back(list[i]);
+ }
+ }).isOk()) {
+ break;
+ }
+
+ // stop each sensor individually
+ step = "stop each sensor";
+ bool ok = true;
+ for (const auto &i : sensorList) {
+ if (!sensors->activate(i.sensorHandle, false).isOk()) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ break;
+ }
+
+ // mark it done
+ step = "done";
+ succeed = true;
+ } while(0);
+
+ if (succeed) {
+ return;
+ }
+
+ // Delay 100ms before retry, hidl service is expected to come up in short time after crash.
+ ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1);
+ std::this_thread::sleep_for(RETRY_DELAY);
+ }
+
+ sensors = nullptr;
+}
+
+void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) {
+ std::lock_guard<std::mutex> lock(events_mutex);
+ if (output) {
+ output->insert(output->end(), events.begin(), events.end());
+ }
+ events.clear();
+}
+
+void SensorsHidlEnvironment::setCollection(bool enable) {
+ std::lock_guard<std::mutex> lock(events_mutex);
+ collectionEnabled = enable;
+}
+
+void SensorsHidlEnvironment::addEvent(const Event& ev) {
+ std::lock_guard<std::mutex> lock(events_mutex);
+ if (collectionEnabled) {
+ events.push_back(ev);
+ }
+}
+
+void SensorsHidlEnvironment::startPollingThread() {
+ stopThread = std::shared_ptr<bool>(new bool(false));
+ pollThread = std::thread(pollingThread, this, stopThread);
+ events.reserve(128);
+}
+
+void SensorsHidlEnvironment::pollingThread(
+ SensorsHidlEnvironment* env, std::shared_ptr<bool> stop) {
+ ALOGD("polling thread start");
+ bool needExit = *stop;
+
+ while(!needExit) {
+ env->sensors->poll(1,
+ [&](auto result, const auto &events, const auto &dynamicSensorsAdded) {
+ if (result != Result::OK
+ || (events.size() == 0 && dynamicSensorsAdded.size() == 0)
+ || *stop) {
+ needExit = true;
+ return;
+ }
+
+ if (events.size() > 0) {
+ env->addEvent(events[0]);
+ }
+ });
+ }
+ ALOGD("polling thread end");
+}
+
+class SensorsTestSharedMemory {
+ public:
+ static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
+ SharedMemInfo getSharedMemInfo() const;
+ char * getBuffer() const;
+ std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
+ virtual ~SensorsTestSharedMemory();
+ private:
+ SensorsTestSharedMemory(SharedMemType type, size_t size);
+
+ SharedMemType mType;
+ native_handle_t* mNativeHandle;
+ size_t mSize;
+ char* mBuffer;
+
+ DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
+};
+
+SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
+ SharedMemInfo mem = {
+ .type = mType,
+ .format = SharedMemFormat::SENSORS_EVENT,
+ .size = static_cast<uint32_t>(mSize),
+ .memoryHandle = mNativeHandle
+ };
+ return mem;
+}
+
+char * SensorsTestSharedMemory::getBuffer() const {
+ return mBuffer;
+}
+
+std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
+
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+ constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
+ constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
+ constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
+ constexpr size_t kOffsetAtomicCounter =
+ static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
+ constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
+ constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
+
+ std::vector<Event> events;
+ std::vector<float> data(16);
+
+ while (offset + kEventSize <= mSize) {
+ int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
+ if (atomicCounter <= lastCounter) {
+ break;
+ }
+
+ int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
+ if (size != kEventSize) {
+ // unknown error, events parsed may be wrong, remove all
+ events.clear();
+ break;
+ }
+
+ int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken);
+ int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType);
+ int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp);
+
+ ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64,
+ offset, atomicCounter, token, type, timestamp);
+
+ Event event = {
+ .timestamp = timestamp,
+ .sensorHandle = token,
+ .sensorType = static_cast<SensorType>(type),
+ };
+ event.u.data = android::hardware::hidl_array<float, 16>
+ (reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+ events.push_back(event);
+
+ lastCounter = atomicCounter;
+ offset += kEventSize;
+ }
+
+ return events;
+}
+
+SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
+ : mType(type), mSize(0), mBuffer(nullptr) {
+ native_handle_t *handle = nullptr;
+ char *buffer = nullptr;
+ switch(type) {
+ case SharedMemType::ASHMEM: {
+ int fd;
+ handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/);
+ if (handle != nullptr) {
+ handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
+ if (handle->data[0] > 0) {
+ // memory is pinned by default
+ buffer = static_cast<char *>
+ (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+ break;
+ }
+ ::native_handle_close(handle);
+ }
+ ::native_handle_delete(handle);
+ handle = nullptr;
+ }
+ break;
+ }
+ case SharedMemType::GRALLOC: {
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (buffer != nullptr) {
+ mNativeHandle = handle;
+ mSize = size;
+ mBuffer = buffer;
+ }
+}
+
+SensorsTestSharedMemory::~SensorsTestSharedMemory() {
+ switch(mType) {
+ case SharedMemType::ASHMEM: {
+ if (mSize != 0) {
+ ::munmap(mBuffer, mSize);
+ mBuffer = nullptr;
+
+ ::native_handle_close(mNativeHandle);
+ ::native_handle_delete(mNativeHandle);
+
+ mNativeHandle = nullptr;
+ mSize = 0;
+ }
+ break;
+ }
+ default: {
+ if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+ ALOGE("SensorsTestSharedMemory %p not properly destructed: "
+ "type %d, native handle %p, size %zu, buffer %p",
+ this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+ }
+ break;
+ }
+ }
+}
+
+SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
+ constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
+ if (size == 0 || size >= kMaxSize) {
+ return nullptr;
+ }
+
+ auto m = new SensorsTestSharedMemory(type, size);
+ if (m->mSize != size || m->mBuffer == nullptr) {
+ delete m;
+ m = nullptr;
+ }
+ return m;
+}
+
+class SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &events, std::string *out) const = 0;
+ virtual ~SensorEventsChecker() {}
+};
+
+class NullChecker : public SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &, std::string *) const {
+ return true;
+ }
+};
+
+class SensorEventPerEventChecker : public SensorEventsChecker {
+ public:
+ virtual bool checkEvent(const Event &event, std::string *out) const = 0;
+ virtual bool check(const std::vector<Event> &events, std::string *out) const {
+ for (const auto &e : events) {
+ if (!checkEvent(e, out)) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+class Vec3NormChecker : public SensorEventPerEventChecker {
+ public:
+ Vec3NormChecker(float min, float max) : mRange(min, max) {}
+ static Vec3NormChecker byNominal(float nominal, float allowedError) {
+ return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
+ }
+
+ virtual bool checkEvent(const Event &event, std::string *out) const {
+ Vec3 v = event.u.vec3;
+ float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+ if (norm < mRange.first || norm > mRange.second) {
+ if (out != nullptr) {
+ std::ostringstream ss;
+ ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z << ")"
+ << " has norm " << norm << ", which is beyond range"
+ << " [" << mRange.first << ", " << mRange.second << "]";
+ *out = ss.str();
+ }
+ return false;
+ }
+ return true;
+ }
+ protected:
+ std::pair<float, float> mRange;
+};
+
+// The main test class for SENSORS HIDL HAL.
+class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ }
+
+ virtual void TearDown() override {
+ // stop all sensors
+ for (auto s : mSensorHandles) {
+ S()->activate(s, false);
+ }
+ mSensorHandles.clear();
+
+ // stop all direct report and channels
+ for (auto c : mDirectChannelHandles) {
+ // disable all reports
+ S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){});
+ S()->unregisterDirectChannel(c);
+ }
+ mDirectChannelHandles.clear();
+ }
+
+ protected:
+ SensorInfo defaultSensorByType(SensorType type);
+ std::vector<SensorInfo> getSensorsList();
+ std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ bool clearBeforeStart = true, bool changeCollection = true);
+
+ // implementation wrapper
+ Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) {
+ return S()->getSensorsList(_hidl_cb);
+ }
+
+ Return<Result> activate(
+ int32_t sensorHandle, bool enabled);
+
+ Return<Result> batch(
+ int32_t sensorHandle,
+ int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+ }
+
+ Return<Result> flush(int32_t sensorHandle) {
+ return S()->flush(sensorHandle);
+ }
+
+ Return<Result> injectSensorData(const Event& event) {
+ return S()->injectSensorData(event);
+ }
+
+ Return<void> registerDirectChannel(
+ const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb);
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) {
+ return S()->unregisterDirectChannel(channelHandle);
+ }
+
+ Return<void> configDirectReport(
+ int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ ISensors::configDirectReport_cb _hidl_cb) {
+ return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+ }
+
+ inline sp<ISensors>& S() {
+ return SensorsHidlEnvironment::Instance()->sensors;
+ }
+
+ inline static SensorFlagBits extractReportMode(uint64_t flag) {
+ return (SensorFlagBits) (flag
+ & ((uint64_t) SensorFlagBits::CONTINUOUS_MODE
+ | (uint64_t) SensorFlagBits::ON_CHANGE_MODE
+ | (uint64_t) SensorFlagBits::ONE_SHOT_MODE
+ | (uint64_t) SensorFlagBits::SPECIAL_REPORTING_MODE));
+ }
+
+ inline static bool isMetaSensorType(SensorType type) {
+ return (type == SensorType::META_DATA
+ || type == SensorType::DYNAMIC_SENSOR_META
+ || type == SensorType::ADDITIONAL_INFO);
+ }
+
+ inline static bool isValidType(SensorType type) {
+ return (int32_t) type > 0;
+ }
+
+ void testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker);
+ void testSamplingRateHotSwitchOperation(SensorType type);
+ void testBatchingOperation(SensorType type);
+ void testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker);
+
+ static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
+ static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+ static void assertDelayMatchReportMode(
+ int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
+ static SensorFlagBits expectedReportModeForType(SensorType type);
+ static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
+ static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+
+ // checkers
+ static const Vec3NormChecker sAccelNormChecker;
+ static const Vec3NormChecker sGyroNormChecker;
+
+ // all sensors and direct channnels used
+ std::unordered_set<int32_t> mSensorHandles;
+ std::unordered_set<int32_t> mDirectChannelHandles;
+};
+
+const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
+ Vec3NormChecker::byNominal(GRAVITY_EARTH, 0.5f/*m/s^2*/));
+const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
+ Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+ // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+ // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+ // check the return value of deactivation. Deactivating a sensor more than once does not have
+ // negative effect.
+ if (enabled) {
+ mSensorHandles.insert(sensorHandle);
+ }
+ return S()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(
+ const SharedMemInfo& mem, ISensors::registerDirectChannel_cb cb) {
+ // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+ // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+ // Unregistering a channel more than once should not have negative effect.
+ S()->registerDirectChannel(mem,
+ [&] (auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ mDirectChannelHandles.insert(channelHandle);
+ }
+ cb(result, channelHandle);
+ });
+ return Void();
+}
+
+std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+ bool clearBeforeStart, bool changeCollection) {
+ std::vector<Event> events;
+ constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms
+
+ ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
+ nEventLimit, timeLimitUs, clearBeforeStart);
+
+ if (changeCollection) {
+ SensorsHidlEnvironment::Instance()->setCollection(true);
+ }
+ if (clearBeforeStart) {
+ SensorsHidlEnvironment::Instance()->catEvents(nullptr);
+ }
+
+ while (timeLimitUs > 0) {
+ useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
+ usleep(duration);
+ timeLimitUs -= duration;
+
+ SensorsHidlEnvironment::Instance()->catEvents(&events);
+ if (events.size() >= nEventLimit) {
+ break;
+ }
+ ALOGV("time to go = %d, events to go = %d",
+ (int)timeLimitUs, (int)(nEventLimit - events.size()));
+ }
+
+ if (changeCollection) {
+ SensorsHidlEnvironment::Instance()->setCollection(false);
+ }
+ return events;
+}
+
+void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) {
+
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
+ case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType); break;
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+ default:
+ FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, "
+ << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+ }
+}
+
+void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ SensorFlagBits expected = expectedReportModeForType(type);
+
+ ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode)
+ << "reportMode=" << static_cast<int>(reportMode)
+ << "expected=" << static_cast<int>(expected);
+}
+
+void SensorsHidlTest::assertDelayMatchReportMode(
+ int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) {
+ switch(reportMode) {
+ case SensorFlagBits::CONTINUOUS_MODE:
+ ASSERT_LT(0, minDelay);
+ ASSERT_LE(0, maxDelay);
+ break;
+ case SensorFlagBits::ON_CHANGE_MODE:
+ ASSERT_LE(0, minDelay);
+ ASSERT_LE(0, maxDelay);
+ break;
+ case SensorFlagBits::ONE_SHOT_MODE:
+ ASSERT_EQ(-1, minDelay);
+ ASSERT_EQ(0, maxDelay);
+ break;
+ case SensorFlagBits::SPECIAL_REPORTING_MODE:
+ // do not enforce anything for special reporting mode
+ break;
+ default:
+ FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+ }
+}
+
+// return -1 means no expectation for this type
+SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) {
+ switch (type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::PRESSURE:
+ case SensorType::TEMPERATURE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION:
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GAME_ROTATION_VECTOR:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ case SensorType::POSE_6DOF:
+ case SensorType::HEART_BEAT:
+ return SensorFlagBits::CONTINUOUS_MODE;
+
+ case SensorType::LIGHT:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::HEART_RATE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::MOTION_DETECT:
+ case SensorType::STEP_COUNTER:
+ return SensorFlagBits::ON_CHANGE_MODE;
+
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ return SensorFlagBits::ONE_SHOT_MODE;
+
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::DYNAMIC_SENSOR_META:
+ return SensorFlagBits::SPECIAL_REPORTING_MODE;
+
+ default:
+ ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+ return (SensorFlagBits)-1;
+ }
+}
+
+bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
+ unsigned int r =
+ static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT)
+ >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+ return r >= static_cast<unsigned int>(rate);
+}
+
+bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
+ switch (type) {
+ case SharedMemType::ASHMEM:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+ case SharedMemType::GRALLOC:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+ default:
+ return false;
+ }
+}
+
+SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
+ SensorInfo ret;
+
+ ret.type = (SensorType) -1;
+ S()->getSensorsList(
+ [&] (const auto &list) {
+ const size_t count = list.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (list[i].type == type) {
+ ret = list[i];
+ return;
+ }
+ }
+ });
+
+ return ret;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
+ std::vector<SensorInfo> ret;
+
+ S()->getSensorsList(
+ [&] (const auto &list) {
+ const size_t count = list.size();
+ ret.reserve(list.size());
+ for (size_t i = 0; i < count; ++i) {
+ ret.push_back(list[i]);
+ }
+ });
+
+ return ret;
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SensorListValid) {
+ S()->getSensorsList(
+ [&] (const auto &list) {
+ const size_t count = list.size();
+ for (size_t i = 0; i < count; ++i) {
+ const auto &s = list[i];
+ SCOPED_TRACE(::testing::Message() << i << "/" << count << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec
+ << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
+
+ // Test non-empty type string
+ EXPECT_FALSE(s.typeAsString.empty());
+
+ // Test defined type matches defined string type
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+
+ // Test if all sensor has name and vendor
+ EXPECT_FALSE(s.name.empty());
+ EXPECT_FALSE(s.vendor.empty());
+
+ // Test power > 0, maxRange > 0
+ EXPECT_LE(0, s.power);
+ EXPECT_LT(0, s.maxRange);
+
+ // Info type, should have no sensor
+ EXPECT_FALSE(
+ s.type == SensorType::ADDITIONAL_INFO
+ || s.type == SensorType::META_DATA);
+
+ // Test fifoMax >= fifoReserved
+ EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+ << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+
+ // Test Reporting mode valid
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+
+ // Test min max are in the right order
+ EXPECT_LE(s.minDelay, s.maxDelay);
+ // Test min/max delay matches reporting mode
+ EXPECT_NO_FATAL_FAILURE(
+ assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+ }
+ });
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SetOperationMode) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [] (const auto& s) {
+ return (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, InjectSensorEventData) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+ std::vector<SensorInfo> sensorSupportInjection;
+
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [&sensorSupportInjection] (const auto& s) {
+ bool ret = (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ if (ret) {
+ sensorSupportInjection.push_back(s);
+ }
+ return ret;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+
+ for (const auto &s : sensorSupportInjection) {
+ switch (s.type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD: {
+ usleep(100000); // sleep 100ms
+
+ Event dummy;
+ dummy.timestamp = android::elapsedRealtimeNano();
+ dummy.sensorType = s.type;
+ dummy.sensorHandle = s.sensorHandle;
+ Vec3 v = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+ dummy.u.vec3 = v;
+
+ EXPECT_EQ(Result::OK, S()->injectSensorData(dummy));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+
+void SensorsHidlTest::testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker) {
+ std::vector<Event> events;
+
+ const int64_t samplingPeriodInNs = samplingPeriod.count();
+ const int64_t batchingPeriodInNs = 0; // no batching
+ const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+ const size_t minNEvent = duration / samplingPeriod;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+ // rate not supported
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+
+ ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+ events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ ALOGI("Collected %zu samples", events.size());
+
+ ASSERT_GT(events.size(), 0u);
+
+ size_t nRealEvent = 0;
+ bool handleMismatchReported = false;
+ bool metaSensorTypeErrorReported = false;
+ for (auto & e : events) {
+ if (e.sensorType == type) {
+ // avoid generating hundreds of error
+ if (!handleMismatchReported) {
+ EXPECT_EQ(e.sensorHandle, handle)
+ << (handleMismatchReported = true,
+ "Event of the same type must come from the sensor registered");
+ }
+ ++ nRealEvent;
+ } else {
+ // avoid generating hundreds of error
+ if (!metaSensorTypeErrorReported) {
+ EXPECT_TRUE(isMetaSensorType(e.sensorType))
+ << (metaSensorTypeErrorReported = true,
+ "Only meta types are allowed besides the type registered");
+ }
+ }
+ }
+
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
+
+ EXPECT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
+}
+
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
+
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
+
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
+
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type) {
+ std::vector<Event> events1, events2;
+
+ constexpr int64_t batchingPeriodInNs = 0; // no batching
+ constexpr size_t minNEvent = 50;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+ int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+ int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
+
+ if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
+ // only support single rate
+ return;
+ }
+
+ ASSERT_EQ(batch(handle, minSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for change rate to happen
+ events1 = collectEvents(sensor.minDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
+
+ ASSERT_EQ(batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for change rate to happen
+ events2 = collectEvents(sensor.maxDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
+
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
+
+ ASSERT_GT(events1.size(), 0u);
+ ASSERT_GT(events2.size(), 0u);
+
+ int64_t minDelayAverageInterval, maxDelayAverageInterval;
+
+ size_t nEvent = 0;
+ int64_t prevTimestamp = -1;
+ int64_t timestampInterval = 0;
+ for (auto & e : events1) {
+ if (e.sensorType == type) {
+ ASSERT_EQ(e.sensorHandle, handle);
+ if (prevTimestamp > 0) {
+ timestampInterval += e.timestamp - prevTimestamp;
+ }
+ prevTimestamp = e.timestamp;
+ ++ nEvent;
+ }
+ }
+ ASSERT_GT(nEvent, 2u);
+ minDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+ nEvent = 0;
+ prevTimestamp = -1;
+ timestampInterval = 0;
+ for (auto & e : events2) {
+ if (e.sensorType == type) {
+ ASSERT_EQ(e.sensorHandle, handle);
+ if (prevTimestamp > 0) {
+ timestampInterval += e.timestamp - prevTimestamp;
+ }
+ prevTimestamp = e.timestamp;
+ ++ nEvent;
+ }
+ }
+ ASSERT_GT(nEvent, 2u);
+ maxDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+ // change of rate is significant.
+ EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
+
+ // fastest rate sampling time is close to spec
+ ALOGI("minDelayAverageInterval = %" PRId64, minDelayAverageInterval);
+ EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ minSamplingPeriodInNs / 10);
+}
+
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testBatchingOperation(SensorType type) {
+ std::vector<Event> events;
+
+ constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+ constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isValidType(sensor.type)) {
+ // no default sensor of this type
+ return;
+ }
+
+ int32_t handle = sensor.sensorHandle;
+ int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+ uint32_t minFifoCount = sensor.fifoReservedEventCount;
+ int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
+
+ if (batchingPeriodInNs < oneSecondInNs) {
+ // batching size too small to test reliably
+ return;
+ }
+
+ batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
+
+ ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
+
+ int64_t allowedBatchDeliverTimeNs =
+ std::max(oneSecondInNs, batchingPeriodInNs / 10);
+
+ ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
+ ASSERT_EQ(activate(handle, 1), Result::OK);
+
+ usleep(500000); // sleep 0.5 sec to wait for initialization
+ ASSERT_EQ(flush(handle), Result::OK);
+
+ // wait for 80% of the reserved batching period
+ // there should not be any significant amount of events
+ // since collection is not enabled all events will go down the drain
+ usleep(batchingPeriodInNs / 1000 * 8 / 10);
+
+ SensorsHidlEnvironment::Instance()->setCollection(true);
+ // 0.8 + 0.3 times the batching period
+ // plus some time for the event to deliver
+ events = collectEvents(
+ batchingPeriodInNs / 1000 * 3 / 10,
+ minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
+
+ ASSERT_EQ(flush(handle), Result::OK);
+
+ events = collectEvents(allowedBatchDeliverTimeNs / 1000,
+ minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
+
+ SensorsHidlEnvironment::Instance()->setCollection(false);
+ ASSERT_EQ(activate(handle, 0), Result::OK);
+
+ size_t nEvent = 0;
+ for (auto & e : events) {
+ if (e.sensorType == type && e.sensorHandle == handle) {
+ ++ nEvent;
+ }
+ }
+
+ // at least reach 90% of advertised capacity
+ ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10));
+}
+
+// Test if sensor hal can do accelerometer batching properly
+TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+ testBatchingOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope batching properly
+TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+ testBatchingOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer batching properly
+TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+ testBatchingOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+ constexpr size_t kNEvent = 500;
+ constexpr size_t kMemSize = kEventSize * kNEvent;
+
+ constexpr float kNormalNominal = 50;
+ constexpr float kFastNominal = 200;
+ constexpr float kVeryFastNominal = 800;
+
+ constexpr float kNominalTestTimeSec = 1.f;
+ constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
+
+ SensorInfo sensor = defaultSensorByType(type);
+
+ if (!isDirectReportRateSupported(sensor, rate)) {
+ return;
+ }
+
+ if (!isDirectChannelTypeSupported(sensor, memType)) {
+ return;
+ }
+
+ std::unique_ptr<SensorsTestSharedMemory>
+ mem(SensorsTestSharedMemory::create(memType, kMemSize));
+ ASSERT_NE(mem, nullptr);
+
+ char* buffer = mem->getBuffer();
+ // fill memory with data
+ for (size_t i = 0; i < kMemSize; ++i) {
+ buffer[i] = '\xcc';
+ }
+
+ int32_t channelHandle;
+ registerDirectChannel(mem->getSharedMemInfo(),
+ [&channelHandle] (auto result, auto channelHandle_) {
+ ASSERT_EQ(result, Result::OK);
+ channelHandle = channelHandle_;
+ });
+
+ // check memory is zeroed
+ for (size_t i = 0; i < kMemSize; ++i) {
+ ASSERT_EQ(buffer[i], '\0');
+ }
+
+ int32_t eventToken;
+ configDirectReport(sensor.sensorHandle, channelHandle, rate,
+ [&eventToken] (auto result, auto token) {
+ ASSERT_EQ(result, Result::OK);
+ eventToken = token;
+ });
+
+ usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
+ auto events = mem->parseEvents();
+
+ // find norminal rate
+ float nominalFreq = 0.f;
+ switch (rate) {
+ case RateLevel::NORMAL:
+ nominalFreq = kNormalNominal;
+ break;
+ case RateLevel::FAST:
+ nominalFreq = kFastNominal;
+ break;
+ case RateLevel::VERY_FAST:
+ nominalFreq = kVeryFastNominal;
+ break;
+ case RateLevel::STOP:
+ FAIL();
+ }
+
+ // allowed to be between 55% and 220% of nominal freq
+ ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+ ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
+
+ int64_t lastTimestamp = 0;
+ bool typeErrorReported = false;
+ bool tokenErrorReported = false;
+ bool timestampErrorReported = false;
+ for (auto &e : events) {
+ if (!typeErrorReported) {
+ EXPECT_EQ(type, e.sensorType)
+ << (typeErrorReported = true, "Type in event does not match type of sensor registered.");
+ }
+ if (!tokenErrorReported) {
+ EXPECT_EQ(eventToken, e.sensorHandle)
+ << (tokenErrorReported = true,
+ "Event token does not match that retured from configDirectReport");
+ }
+ if (!timestampErrorReported) {
+ EXPECT_GT(e.timestamp, lastTimestamp)
+ << (timestampErrorReported = true, "Timestamp not monotonically increasing");
+ }
+ lastTimestamp = e.timestamp;
+ }
+
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
+
+ // stop sensor and unregister channel
+ configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
+ [&eventToken] (auto result, auto) {
+ EXPECT_EQ(result, Result::OK);
+ });
+ EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(
+ SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::VERY_FAST, NullChecker());
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
+// vim: set ts=2 sw=2
diff --git a/sensors/Android.bp b/sensors/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/sensors/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/soundtrigger/2.0/Android.bp b/soundtrigger/2.0/Android.bp
new file mode 100644
index 0000000..4d2bb1a
--- /dev/null
+++ b/soundtrigger/2.0/Android.bp
@@ -0,0 +1,71 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.soundtrigger@2.0_hal",
+ srcs: [
+ "types.hal",
+ "ISoundTriggerHw.hal",
+ "ISoundTriggerHwCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.soundtrigger@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.soundtrigger@2.0",
+ srcs: [
+ ":android.hardware.soundtrigger@2.0_hal",
+ ],
+ out: [
+ "android/hardware/soundtrigger/2.0/types.cpp",
+ "android/hardware/soundtrigger/2.0/SoundTriggerHwAll.cpp",
+ "android/hardware/soundtrigger/2.0/SoundTriggerHwCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.soundtrigger@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.soundtrigger@2.0",
+ srcs: [
+ ":android.hardware.soundtrigger@2.0_hal",
+ ],
+ out: [
+ "android/hardware/soundtrigger/2.0/types.h",
+ "android/hardware/soundtrigger/2.0/ISoundTriggerHw.h",
+ "android/hardware/soundtrigger/2.0/IHwSoundTriggerHw.h",
+ "android/hardware/soundtrigger/2.0/BnHwSoundTriggerHw.h",
+ "android/hardware/soundtrigger/2.0/BpHwSoundTriggerHw.h",
+ "android/hardware/soundtrigger/2.0/BsSoundTriggerHw.h",
+ "android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h",
+ "android/hardware/soundtrigger/2.0/IHwSoundTriggerHwCallback.h",
+ "android/hardware/soundtrigger/2.0/BnHwSoundTriggerHwCallback.h",
+ "android/hardware/soundtrigger/2.0/BpHwSoundTriggerHwCallback.h",
+ "android/hardware/soundtrigger/2.0/BsSoundTriggerHwCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.soundtrigger@2.0",
+ generated_sources: ["android.hardware.soundtrigger@2.0_genc++"],
+ generated_headers: ["android.hardware.soundtrigger@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.soundtrigger@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/soundtrigger/2.0/Android.mk b/soundtrigger/2.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/soundtrigger/2.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/soundtrigger/2.0/ISoundTriggerHw.hal b/soundtrigger/2.0/ISoundTriggerHw.hal
new file mode 100644
index 0000000..cf35ef1
--- /dev/null
+++ b/soundtrigger/2.0/ISoundTriggerHw.hal
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2016 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.soundtrigger@2.0;
+
+import android.hardware.audio.common@2.0;
+
+import ISoundTriggerHwCallback;
+
+interface ISoundTriggerHw {
+
+ /*
+ * Sound trigger implementation descriptor read by the framework via
+ * getProperties(). Used by SoundTrigger service to report to applications
+ * and manage concurrency and policy.
+ */
+ struct Properties {
+ /* Implementor name */
+ string implementor;
+ /* Implementation description */
+ string description;
+ /* Implementation version */
+ uint32_t version;
+ /* Unique implementation ID. The UUID must change with each version of
+ the engine implementation */
+ Uuid uuid;
+ /* Maximum number of concurrent sound models loaded */
+ uint32_t maxSoundModels;
+ /* Maximum number of key phrases */
+ uint32_t maxKeyPhrases;
+ /* Maximum number of concurrent users detected */
+ uint32_t maxUsers;
+ /* All supported modes. e.g RecognitionMode.VOICE_TRIGGER */
+ uint32_t recognitionModes;
+ /* Supports seamless transition from detection to capture */
+ bool captureTransition;
+ /* Maximum buffering capacity in ms if captureTransition is true */
+ uint32_t maxBufferMs;
+ /* Supports capture by other use cases while detection is active */
+ bool concurrentCapture;
+ /* Returns the trigger capture in event */
+ bool triggerInEvent;
+ /* Rated power consumption when detection is active with TDB
+ * silence/sound/speech ratio */
+ uint32_t powerConsumptionMw;
+ };
+
+
+ /*
+ * Base sound model descriptor. This struct is the header of a larger block
+ * passed to loadSoundModel() and contains the binary data of the
+ * sound model.
+ */
+ struct SoundModel {
+ /* Model type. e.g. SoundModelType.KEYPHRASE */
+ SoundModelType type;
+ /* Unique sound model ID. */
+ Uuid uuid;
+ /* Unique vendor ID. Identifies the engine the sound model
+ * was build for */
+ Uuid vendorUuid;
+ /* Opaque data transparent to Android framework */
+ vec<uint8_t> data;
+ };
+
+ /* Key phrase descriptor */
+ struct Phrase {
+ /* Unique keyphrase ID assigned at enrollment time */
+ uint32_t id;
+ /* Recognition modes supported by this key phrase */
+ uint32_t recognitionModes;
+ /* List of users IDs associated with this key phrase */
+ vec<uint32_t> users;
+ /* Locale - Java Locale style (e.g. en_US) */
+ string locale;
+ /* Phrase text in UTF-8 format. */
+ string text;
+ };
+
+ /*
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match
+ * information indicated by phrases field
+ */
+ struct PhraseSoundModel {
+ /* Common part of sound model descriptor */
+ SoundModel common;
+ /* List of descriptors for key phrases supported by this sound model */
+ vec<Phrase> phrases;
+ };
+
+ /*
+ * Configuration for sound trigger capture session passed to
+ * startRecognition() method
+ */
+ struct RecognitionConfig {
+ /* IO handle that will be used for capture. N/A if captureRequested
+ * is false */
+ AudioIoHandle captureHandle;
+ /* Input device requested for detection capture */
+ AudioDevice captureDevice;
+ /* Capture and buffer audio for this recognition instance */
+ bool captureRequested;
+ /* Configuration for each key phrase */
+ vec<PhraseRecognitionExtra> phrases;
+ /* Opaque capture configuration data transparent to the framework */
+ vec<uint8_t> data;
+ };
+
+
+ /*
+ * Retrieve implementation properties.
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENODEV in case of initialization error.
+ * @return properties A Properties structure containing implementation
+ * description and capabilities.
+ */
+ getProperties() generates (int32_t retval, Properties properties);
+
+ /*
+ * Load a sound model. Once loaded, recognition of this model can be
+ * started and stopped. Only one active recognition per model at a time.
+ * The SoundTrigger service must handle concurrent recognition requests by
+ * different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions
+ * (unloadSoundModel(), startRecognition(), etc...
+ * @param soundModel A SoundModel structure describing the sound model to
+ * load.
+ * @param callback The callback interface on which the soundmodelCallback()
+ * method will be called upon completion.
+ * @param cookie The value of the cookie argument passed to the completion
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid sound model (e.g 0 data size),
+ * -ENOSYS in case of invalid operation (e.g max number of
+ * models exceeded),
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return modelHandle A unique handle assigned by the HAL for use by the
+ * framework when controlling activity for this sound model.
+ */
+ loadSoundModel(SoundModel soundModel,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval, SoundModelHandle modelHandle);
+
+ /*
+ * Load a key phrase sound model. Once loaded, recognition of this model can
+ * be started and stopped. Only one active recognition per model at a time.
+ * The SoundTrigger service must handle concurrent recognition requests by
+ * different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions
+ * (unloadSoundModel(), startRecognition(), etc...
+ * @param soundModel A PhraseSoundModel structure describing the sound model
+ * to load.
+ * @param callback The callback interface on which the soundmodelCallback()
+ * method will be called upon completion.
+ * @param cookie The value of the cookie argument passed to the completion
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid sound model (e.g 0 data size),
+ * -ENOSYS in case of invalid operation (e.g max number of
+ * models exceeded),
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ * @return modelHandle A unique handle assigned by the HAL for use by the
+ * framework when controlling activity for this sound model.
+ */
+ loadPhraseSoundModel(PhraseSoundModel soundModel,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval, SoundModelHandle modelHandle);
+
+ /*
+ * Unload a sound model. A sound model may be unloaded to make room for a
+ * new one to overcome implementation limitations.
+ * @param modelHandle the handle of the sound model to unload
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENOSYS if the model is not loaded,
+ * -ENODEV in case of initialization error.
+ */
+ unloadSoundModel(SoundModelHandle modelHandle)
+ generates (int32_t retval);
+
+ /*
+ * Start recognition on a given model. Only one recognition active
+ * at a time per model. Once recognition succeeds of fails, the callback
+ * is called.
+ * @param modelHandle the handle of the sound model to use for recognition
+ * @param config A RecognitionConfig structure containing attributes of the
+ * recognition to perform
+ * @param callback The callback interface on which the recognitionCallback()
+ * method must be called upon recognition.
+ * @param cookie The value of the cookie argument passed to the recognition
+ * callback. This unique context information is assigned and
+ * used only by the framework.
+ * @return retval Operation completion status: 0 in case of success,
+ * -EINVAL in case of invalid recognition attributes,
+ * -ENOSYS in case of invalid model handle,
+ * -ENOMEM in case of memory allocation failure,
+ * -ENODEV in case of initialization error.
+ */
+ startRecognition(SoundModelHandle modelHandle,
+ RecognitionConfig config,
+ ISoundTriggerHwCallback callback,
+ CallbackCookie cookie)
+ generates (int32_t retval);
+
+ /*
+ * Stop recognition on a given model.
+ * The implementation must not call the recognition callback when stopped
+ * via this method.
+ * @param modelHandle The handle of the sound model to use for recognition
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENOSYS in case of invalid model handle,
+ * -ENODEV in case of initialization error.
+ */
+ stopRecognition(SoundModelHandle modelHandle)
+ generates (int32_t retval);
+
+ /*
+ * Stop recognition on all models.
+ * @return retval Operation completion status: 0 in case of success,
+ * -ENODEV in case of initialization error.
+ */
+ stopAllRecognitions()
+ generates (int32_t retval);
+};
diff --git a/soundtrigger/2.0/ISoundTriggerHwCallback.hal b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
new file mode 100644
index 0000000..c6555f6
--- /dev/null
+++ b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 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.soundtrigger@2.0;
+
+import android.hardware.audio.common@2.0;
+
+interface ISoundTriggerHwCallback {
+ enum RecognitionStatus : uint32_t {
+ SUCCESS = 0,
+ ABORT = 1,
+ FAILURE = 2,
+ };
+
+ enum SoundModelStatus : uint32_t {
+ UPDATED = 0,
+ };
+
+ /*
+ * Generic recognition event sent via recognition callback
+ */
+ struct RecognitionEvent {
+ /* Recognition status e.g. SUCCESS */
+ RecognitionStatus status;
+ /* Sound model type for this event. e.g SoundModelType.TYPE_KEYPHRASE */
+ SoundModelType type;
+ /* Handle of loaded sound model which triggered the event */
+ SoundModelHandle model;
+ /* It is possible to capture audio from this */
+ /* utterance buffered by the implementation */
+ bool captureAvailable;
+ /* Audio session ID. framework use */
+ int32_t captureSession;
+ /* Delay in ms between end of model detection and start of audio
+ /* available for capture. A negative value is possible
+ * (e.g. if key phrase is also available for capture */
+ int32_t captureDelayMs;
+ /* Duration in ms of audio captured before the start of the trigger.
+ * 0 if none. */
+ int32_t capturePreambleMs;
+ /* The opaque data is the capture of the trigger sound */
+ bool triggerInData;
+ /* Audio format of either the trigger in event data or to use for
+ * capture of the rest of the utterance */
+ AudioConfig audioConfig;
+ /* Opaque event data */
+ vec<uint8_t> data;
+ };
+
+ /*
+ * Specialized recognition event for key phrase recognitions
+ */
+ struct PhraseRecognitionEvent {
+ /* Common part of the recognition event */
+ RecognitionEvent common;
+ /* List of descriptors for each recognized key phrase */
+ vec<PhraseRecognitionExtra> phraseExtras;
+ };
+
+ /*
+ * Event sent via load sound model callback
+ */
+ struct ModelEvent {
+ /* Sound model status e.g. SoundModelStatus.UPDATED */
+ SoundModelStatus status;
+ /* Loaded sound model that triggered the event */
+ SoundModelHandle model;
+ /* Opaque event data, passed transparently by the framework */
+ vec<uint8_t> data;
+ };
+
+ typedef int32_t CallbackCookie;
+
+ /*
+ * Callback method called by the HAL when the sound recognition triggers
+ * @param event A RecognitionEvent structure containing detailed results
+ * of the recognition triggered
+ * @param cookie The cookie passed by the framework when recognition was
+ * started (see ISoundtriggerHw.startRecognition()
+ */
+ recognitionCallback(RecognitionEvent event, CallbackCookie cookie);
+
+ /*
+ * Callback method called by the HAL when the sound recognition triggers
+ * for a key phrase sound model.
+ * @param event A RecognitionEvent structure containing detailed results
+ * of the recognition triggered
+ * @param cookie The cookie passed by the framework when recognition was
+ * started (see ISoundtriggerHw.startRecognition()
+ */
+ phraseRecognitionCallback(PhraseRecognitionEvent event,
+ CallbackCookie cookie);
+ /*
+ * Callback method called by the HAL when the sound model loading completes
+ * @param event A ModelEvent structure containing detailed results of the
+ * model loading operation
+ * @param cookie The cookie passed by the framework when loading was
+ * initiated (see ISoundtriggerHw.loadSoundModel()
+ */
+ soundModelCallback(ModelEvent event, CallbackCookie cookie);
+};
diff --git a/soundtrigger/2.0/default/Android.mk b/soundtrigger/2.0/default/Android.mk
new file mode 100644
index 0000000..068c6b4
--- /dev/null
+++ b/soundtrigger/2.0/default/Android.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2016 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.soundtrigger@2.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ SoundTriggerHalImpl.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ libhardware \
+ android.hardware.soundtrigger@2.0 \
+ android.hardware.audio.common@2.0
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
new file mode 100644
index 0000000..b0aef4b
--- /dev/null
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "SoundTriggerHalImpl"
+//#define LOG_NDEBUG 0
+
+#include <android/log.h>
+#include "SoundTriggerHalImpl.h"
+
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_0 {
+namespace implementation {
+
+// static
+void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent,
+ void *cookie)
+{
+ if (halEvent == NULL) {
+ ALOGW("soundModelCallback called with NULL event");
+ return;
+ }
+ sp<SoundModelClient> client =
+ wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+ if (client == 0) {
+ ALOGW("soundModelCallback called on stale client");
+ return;
+ }
+ if (halEvent->model != client->mHalHandle) {
+ ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
+ (int)halEvent->model, (int)client->mHalHandle);
+ return;
+ }
+
+ ISoundTriggerHwCallback::ModelEvent event;
+ convertSoundModelEventFromHal(&event, halEvent);
+ event.model = client->mId;
+
+ client->mCallback->soundModelCallback(event, client->mCookie);
+}
+
+// static
+void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent,
+ void *cookie)
+{
+ if (halEvent == NULL) {
+ ALOGW("recognitionCallback call NULL event");
+ return;
+ }
+ sp<SoundModelClient> client =
+ wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+ if (client == 0) {
+ ALOGW("soundModelCallback called on stale client");
+ return;
+ }
+
+ ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent);
+ event->model = client->mId;
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ client->mCallback->phraseRecognitionCallback(
+ *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)),
+ client->mCookie);
+ } else {
+ client->mCallback->recognitionCallback(*event, client->mCookie);
+ }
+ delete event;
+}
+
+
+
+// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
+Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb)
+{
+ ALOGV("getProperties() mHwDevice %p", mHwDevice);
+ int ret;
+ struct sound_trigger_properties halProperties;
+ ISoundTriggerHw::Properties properties;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = mHwDevice->get_properties(mHwDevice, &halProperties);
+
+ convertPropertiesFromHal(&properties, &halProperties);
+
+ ALOGV("getProperties implementor %s recognitionModes %08x",
+ properties.implementor.c_str(), properties.recognitionModes);
+
+exit:
+ _hidl_cb(ret, properties);
+ return Void();
+}
+
+int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ uint32_t *modelId)
+{
+ int32_t ret = 0;
+ struct sound_trigger_sound_model *halSoundModel;
+ *modelId = 0;
+ sp<SoundModelClient> client;
+
+ ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ halSoundModel = convertSoundModelToHal(&soundModel);
+ if (halSoundModel == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ do {
+ *modelId = nextUniqueId();
+ } while (mClients.valueFor(*modelId) != 0 && *modelId != 0);
+ }
+ LOG_ALWAYS_FATAL_IF(*modelId == 0,
+ "wrap around in sound model IDs, num loaded models %zu", mClients.size());
+
+ client = new SoundModelClient(*modelId, callback, cookie);
+
+ ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback,
+ client.get(), &client->mHalHandle);
+
+ free(halSoundModel);
+
+ if (ret != 0) {
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ mClients.add(*modelId, client);
+ }
+
+exit:
+ return ret;
+}
+
+Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ loadSoundModel_cb _hidl_cb)
+{
+ uint32_t modelId = 0;
+ int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId);
+
+ _hidl_cb(ret, modelId);
+ return Void();
+}
+
+Return<void> SoundTriggerHalImpl::loadPhraseSoundModel(
+ const ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb)
+{
+ uint32_t modelId = 0;
+ int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel,
+ callback, cookie, &modelId);
+
+ _hidl_cb(ret, modelId);
+ return Void();
+}
+
+Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle)
+{
+ int32_t ret;
+ sp<SoundModelClient> client;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle);
+
+ mClients.removeItem(modelHandle);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle,
+ const ISoundTriggerHw::RecognitionConfig& config,
+ const sp<ISoundTriggerHwCallback>& callback __unused,
+ ISoundTriggerHwCallback::CallbackCookie cookie __unused)
+{
+ int32_t ret;
+ sp<SoundModelClient> client;
+ struct sound_trigger_recognition_config *halConfig;
+
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+
+ halConfig = convertRecognitionConfigToHal(&config);
+
+ if (halConfig == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig,
+ recognitionCallback, client.get());
+
+ free(halConfig);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle)
+{
+ int32_t ret;
+ sp<SoundModelClient> client;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ {
+ AutoMutex lock(mLock);
+ client = mClients.valueFor(modelHandle);
+ if (client == 0) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+ }
+
+ ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle);
+
+exit:
+ return ret;
+}
+
+Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions()
+{
+ int32_t ret;
+ if (mHwDevice == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
+ mHwDevice->stop_all_recognitions) {
+ ret = mHwDevice->stop_all_recognitions(mHwDevice);
+ } else {
+ ret = -ENOSYS;
+ }
+exit:
+ return ret;
+}
+
+SoundTriggerHalImpl::SoundTriggerHalImpl(const char *moduleName)
+ : mModuleName(moduleName), mHwDevice(NULL), mNextModelId(1)
+{
+}
+
+void SoundTriggerHalImpl::onFirstRef()
+{
+ const hw_module_t *mod;
+ int rc;
+
+ if (mModuleName == NULL || strlen(mModuleName) == 0) {
+ mModuleName = "primary";
+ }
+ rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load sound trigger module %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ return;
+ }
+ rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
+ mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+ sound_trigger_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ return;
+ }
+
+ ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
+}
+
+SoundTriggerHalImpl::~SoundTriggerHalImpl()
+{
+ if (mHwDevice != NULL) {
+ sound_trigger_hw_device_close(mHwDevice);
+ }
+}
+
+uint32_t SoundTriggerHalImpl::nextUniqueId()
+{
+ return (uint32_t) atomic_fetch_add_explicit(&mNextModelId,
+ (uint_fast32_t) 1, memory_order_acq_rel);
+}
+
+void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid,
+ const sound_trigger_uuid_t *halUuid)
+{
+ uuid->timeLow = halUuid->timeLow;
+ uuid->timeMid = halUuid->timeMid;
+ uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
+ uuid->variantAndClockSeqHigh = halUuid->clockSeq;
+ memcpy(&uuid->node[0], &halUuid->node[0], 6);
+}
+
+void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid,
+ const Uuid *uuid)
+{
+ halUuid->timeLow = uuid->timeLow;
+ halUuid->timeMid = uuid->timeMid;
+ halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
+ halUuid->clockSeq = uuid->variantAndClockSeqHigh;
+ memcpy(&halUuid->node[0], &uuid->node[0], 6);
+}
+
+void SoundTriggerHalImpl::convertPropertiesFromHal(
+ ISoundTriggerHw::Properties *properties,
+ const struct sound_trigger_properties *halProperties)
+{
+ properties->implementor = halProperties->implementor;
+ properties->description = halProperties->description;
+ properties->version = halProperties->version;
+ convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+ properties->maxSoundModels = halProperties->max_sound_models;
+ properties->maxKeyPhrases = halProperties->max_key_phrases;
+ properties->maxUsers = halProperties->max_users;
+ properties->recognitionModes = halProperties->recognition_modes;
+ properties->captureTransition = halProperties->capture_transition;
+ properties->maxBufferMs = halProperties->max_buffer_ms;
+ properties->concurrentCapture = halProperties->concurrent_capture;
+ properties->triggerInEvent = halProperties->trigger_in_event;
+ properties->powerConsumptionMw = halProperties->power_consumption_mw;
+
+}
+
+void SoundTriggerHalImpl::convertTriggerPhraseToHal(
+ struct sound_trigger_phrase *halTriggerPhrase,
+ const ISoundTriggerHw::Phrase *triggerPhrase)
+{
+ halTriggerPhrase->id = triggerPhrase->id;
+ halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
+ unsigned int i;
+ for (i = 0; i < triggerPhrase->users.size(); i++) {
+ halTriggerPhrase->users[i] = triggerPhrase->users[i];
+ }
+ halTriggerPhrase->num_users = i;
+
+ strlcpy(halTriggerPhrase->locale,
+ triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+ strlcpy(halTriggerPhrase->text,
+ triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+}
+
+struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal(
+ const ISoundTriggerHw::SoundModel *soundModel)
+{
+ struct sound_trigger_sound_model *halModel = NULL;
+ if (soundModel->type == SoundModelType::KEYPHRASE) {
+ size_t allocSize =
+ sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+ struct sound_trigger_phrase_sound_model *halKeyPhraseModel =
+ static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize);
+
+ const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel =
+ reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel);
+
+ size_t i;
+ for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i],
+ &keyPhraseModel->phrases[i]);
+ }
+ halKeyPhraseModel->num_phrases = (unsigned int)i;
+ halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel);
+ halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
+ } else {
+ size_t allocSize =
+ sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+ halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize));
+ LOG_ALWAYS_FATAL_IF(halModel == NULL,
+ "malloc failed for size %zu in convertSoundModelToHal GENERIC",
+ allocSize);
+
+ halModel->data_offset = sizeof(struct sound_trigger_sound_model);
+ }
+ halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
+ convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+ convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
+ halModel->data_size = soundModel->data.size();
+ uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset;
+ const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]);
+ memcpy(dst, src, soundModel->data.size());
+
+ return halModel;
+}
+
+void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal(
+ struct sound_trigger_phrase_recognition_extra *halExtra,
+ const PhraseRecognitionExtra *extra)
+{
+ halExtra->id = extra->id;
+ halExtra->recognition_modes = extra->recognitionModes;
+ halExtra->confidence_level = extra->confidenceLevel;
+
+ unsigned int i;
+ for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+ halExtra->levels[i].user_id = extra->levels[i].userId;
+ halExtra->levels[i].level = extra->levels[i].levelPercent;
+ }
+ halExtra->num_levels = i;
+}
+
+struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal(
+ const ISoundTriggerHw::RecognitionConfig *config)
+{
+ size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
+ struct sound_trigger_recognition_config *halConfig =
+ static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize));
+
+ LOG_ALWAYS_FATAL_IF(halConfig == NULL,
+ "malloc failed for size %zu in convertRecognitionConfigToHal",
+ allocSize);
+
+ halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
+ halConfig->capture_device = (audio_devices_t)config->captureDevice;
+ halConfig->capture_requested = config->captureRequested;
+
+ unsigned int i;
+ for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+ convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
+ &config->phrases[i]);
+ }
+ halConfig->num_phrases = i;
+
+ halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
+ halConfig->data_size = config->data.size();
+ uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset;
+ const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]);
+ memcpy(dst, src, config->data.size());
+ return halConfig;
+}
+
+// static
+void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
+ const struct sound_trigger_model_event *halEvent)
+{
+ event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
+ // event->model to be remapped by called
+ event->data.setToExternal(
+ const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
+}
+
+// static
+ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal(
+ const struct sound_trigger_recognition_event *halEvent)
+{
+ ISoundTriggerHwCallback::RecognitionEvent * event;
+
+ if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ const struct sound_trigger_phrase_recognition_event *halPhraseEvent =
+ reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent);
+ ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent =
+ new ISoundTriggerHwCallback::PhraseRecognitionEvent();
+
+ PhraseRecognitionExtra *phraseExtras =
+ new PhraseRecognitionExtra[halPhraseEvent->num_phrases];
+ for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) {
+ convertPhraseRecognitionExtraFromHal(&phraseExtras[i],
+ &halPhraseEvent->phrase_extras[i]);
+ }
+ phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases);
+ delete[] phraseExtras;
+ event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent);
+ } else {
+ event = new ISoundTriggerHwCallback::RecognitionEvent();
+ }
+
+ event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
+ event->type = static_cast<SoundModelType>(halEvent->type);
+ // event->model to be remapped by called
+ event->captureAvailable = halEvent->capture_available;
+ event->captureSession = halEvent->capture_session;
+ event->captureDelayMs = halEvent->capture_delay_ms;
+ event->capturePreambleMs = halEvent->capture_preamble_ms;
+ event->triggerInData = halEvent->trigger_in_data;
+ event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
+ event->audioConfig.channelMask =
+ (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+ event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
+ event->data.setToExternal(
+ const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
+ halEvent->data_size);
+
+ return event;
+}
+
+// static
+void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal(
+ PhraseRecognitionExtra *extra,
+ const struct sound_trigger_phrase_recognition_extra *halExtra)
+{
+ extra->id = halExtra->id;
+ extra->recognitionModes = halExtra->recognition_modes;
+ extra->confidenceLevel = halExtra->confidence_level;
+
+ ConfidenceLevel *levels =
+ new ConfidenceLevel[halExtra->num_levels];
+ for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+ levels[i].userId = halExtra->levels[i].user_id;
+ levels[i].levelPercent = halExtra->levels[i].level;
+ }
+ extra->levels.setToExternal(levels, halExtra->num_levels);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ extra->levels.resize(halExtra->num_levels);
+ delete[] levels;
+}
+
+ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name)
+{
+ if (name != NULL) {
+ if (strncmp(SOUND_TRIGGER_HARDWARE_MODULE_ID, name,
+ strlen(SOUND_TRIGGER_HARDWARE_MODULE_ID)) != 0) {
+ return NULL;
+ }
+ name = strchr(name, '.');
+ if (name == NULL) {
+ return NULL;
+ }
+ name++;
+ }
+ return new SoundTriggerHalImpl(name);
+}
+} // namespace implementation
+} // namespace V2_0
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
+
+
+
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
new file mode 100644
index 0000000..8aa9285
--- /dev/null
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
+
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <hidl/Status.h>
+#include <stdatomic.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::Uuid;
+using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+
+
+class SoundTriggerHalImpl : public ISoundTriggerHw {
+public:
+ explicit SoundTriggerHalImpl(const char *moduleName = NULL);
+
+ // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
+ Return<void> getProperties(getProperties_cb _hidl_cb) override;
+ Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ loadSoundModel_cb _hidl_cb) override;
+ Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ loadPhraseSoundModel_cb _hidl_cb) override;
+
+ Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override;
+ Return<int32_t> startRecognition(SoundModelHandle modelHandle,
+ const ISoundTriggerHw::RecognitionConfig& config,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie) override;
+ Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override;
+ Return<int32_t> stopAllRecognitions() override;
+
+ // RefBase
+ virtual void onFirstRef();
+
+ static void soundModelCallback(struct sound_trigger_model_event *halEvent,
+ void *cookie);
+ static void recognitionCallback(struct sound_trigger_recognition_event *halEvent,
+ void *cookie);
+
+private:
+
+ class SoundModelClient : public RefBase {
+ public:
+ SoundModelClient(uint32_t id, sp<ISoundTriggerHwCallback> callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie)
+ : mId(id), mCallback(callback), mCookie(cookie) {}
+ virtual ~SoundModelClient() {}
+
+ uint32_t mId;
+ sound_model_handle_t mHalHandle;
+ sp<ISoundTriggerHwCallback> mCallback;
+ ISoundTriggerHwCallback::CallbackCookie mCookie;
+ };
+
+ uint32_t nextUniqueId();
+ void convertUuidFromHal(Uuid *uuid,
+ const sound_trigger_uuid_t *halUuid);
+ void convertUuidToHal(sound_trigger_uuid_t *halUuid,
+ const Uuid *uuid);
+ void convertPropertiesFromHal(ISoundTriggerHw::Properties *properties,
+ const struct sound_trigger_properties *halProperties);
+ void convertTriggerPhraseToHal(struct sound_trigger_phrase *halTriggerPhrase,
+ const ISoundTriggerHw::Phrase *triggerPhrase);
+ // returned HAL sound model must be freed by caller
+ struct sound_trigger_sound_model *convertSoundModelToHal(
+ const ISoundTriggerHw::SoundModel *soundModel);
+ void convertPhraseRecognitionExtraToHal(
+ struct sound_trigger_phrase_recognition_extra *halExtra,
+ const PhraseRecognitionExtra *extra);
+ // returned recognition config must be freed by caller
+ struct sound_trigger_recognition_config *convertRecognitionConfigToHal(
+ const ISoundTriggerHw::RecognitionConfig *config);
+
+
+ static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
+ const struct sound_trigger_model_event *halEvent);
+ static ISoundTriggerHwCallback::RecognitionEvent *convertRecognitionEventFromHal(
+ const struct sound_trigger_recognition_event *halEvent);
+ static void convertPhraseRecognitionExtraFromHal(PhraseRecognitionExtra *extra,
+ const struct sound_trigger_phrase_recognition_extra *halExtra);
+
+ int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+ const sp<ISoundTriggerHwCallback>& callback,
+ ISoundTriggerHwCallback::CallbackCookie cookie,
+ uint32_t *modelId);
+
+ virtual ~SoundTriggerHalImpl();
+
+ const char * mModuleName;
+ struct sound_trigger_hw_device* mHwDevice;
+ volatile atomic_uint_fast32_t mNextModelId;
+ DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
+ Mutex mLock;
+};
+
+extern "C" ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace soundtrigger
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
+
diff --git a/soundtrigger/2.0/types.hal b/soundtrigger/2.0/types.hal
new file mode 100644
index 0000000..26928ba
--- /dev/null
+++ b/soundtrigger/2.0/types.hal
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 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.soundtrigger@2.0;
+
+/*
+ * Sound model types modes used in ISoundTriggerHw.SoundModel
+ */
+enum SoundModelType : int32_t {
+ /* use for unspecified sound model type */
+ UNKNOWN = -1,
+ /* use for key phrase sound models */
+ KEYPHRASE = 0,
+ /* use for all models other than keyphrase */
+ GENERIC = 1,
+};
+
+typedef int32_t SoundModelHandle;
+
+
+/*
+ * Recognition modes used in ISoundTriggerHw.RecognitionConfig,
+ * ISoundTriggerHw.Properties or PhraseRecognitionExtra
+ */
+enum RecognitionMode : uint32_t {
+ /* simple voice trigger */
+ VOICE_TRIGGER = (1 << 0),
+ /* trigger only if one user in model identified */
+ USER_IDENTIFICATION = (1 << 1),
+ /* trigger only if one user in mode authenticated */
+ USER_AUTHENTICATION = (1 << 2),
+ /* generic sound trigger */
+ GENERIC_TRIGGER = (1 << 3),
+};
+
+/*
+ * Confidence level for each user in structure PhraseRecognitionExtra
+ */
+struct ConfidenceLevel {
+ /* user ID */
+ uint32_t userId;
+ /* confidence level in percent (0 - 100): */
+ /* - min level for recognition configuration */
+ /* - detected level for recognition event */
+ uint32_t levelPercent;
+};
+
+/*
+ * Specialized recognition event for key phrase detection
+ */
+struct PhraseRecognitionExtra {
+ /* keyphrase ID */
+ uint32_t id;
+ /* recognition modes used for this keyphrase */
+ uint32_t recognitionModes;
+ /* confidence level for mode RecognitionMode.VOICE_TRIGGER */
+ uint32_t confidenceLevel;
+ /* list of confidence levels per user for
+ * RecognitionMode.USER_IDENTIFICATION and
+ * RecognitionMode.USER_AUTHENTICATION */
+ vec<ConfidenceLevel> levels;
+};
+
+/* TODO(elaurent) remove when Java build problem is fixed */
+union Dummy {
+ uint32_t dummy1;
+ int32_t dummy2;
+};
\ No newline at end of file
diff --git a/soundtrigger/2.0/vts/Android.mk b/soundtrigger/2.0/vts/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/soundtrigger/2.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..8f0cc4e
--- /dev/null
+++ b/soundtrigger/2.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalSoundtriggerV2_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.soundtrigger@2.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
new file mode 100644
index 0000000..3fbef18
--- /dev/null
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#define SHORT_TIMEOUT_PERIOD (1)
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using ::android::hardware::soundtrigger::V2_0::SoundModelType;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+ public:
+ Monitor() : mCount(0) {}
+
+ /**
+ * Adds 1 to the internal counter and unblocks one of the waiting threads.
+ */
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMtx);
+ mCount++;
+ mCv.notify_one();
+ }
+
+ /**
+ * Blocks until the internal counter becomes greater than 0.
+ *
+ * If notified, this method decreases the counter by 1 and returns true.
+ * If timeout, returns false.
+ */
+ bool wait(int timeoutSeconds) {
+ std::unique_lock<std::mutex> lock(mMtx);
+ auto deadline = std::chrono::system_clock::now() +
+ std::chrono::seconds(timeoutSeconds);
+ while (mCount == 0) {
+ if (mCv.wait_until(lock, deadline) == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ mCount--;
+ return true;
+ }
+
+ private:
+ std::mutex mMtx;
+ std::condition_variable mCv;
+ int mCount;
+};
+
+// The main test class for Sound Trigger HIDL HAL.
+class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>("sound_trigger.primary");
+ ASSERT_NE(nullptr, mSoundTriggerHal.get());
+ mCallback = new SoundTriggerHwCallback(*this);
+ ASSERT_NE(nullptr, mCallback.get());
+ }
+
+ static void SetUpTestCase() {
+ srand(time(nullptr));
+ }
+
+ class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+ private:
+ SoundTriggerHidlTest& mParent;
+
+ public:
+ SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+ virtual Return<void> recognitionCallback(
+ const ISoundTriggerHwCallback::RecognitionEvent& event __unused,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ virtual Return<void> phraseRecognitionCallback(
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ return Void();
+ }
+
+ virtual Return<void> soundModelCallback(
+ const ISoundTriggerHwCallback::ModelEvent& event,
+ int32_t cookie __unused) {
+ ALOGI("%s", __FUNCTION__);
+ mParent.lastModelEvent = event;
+ mParent.monitor.notify();
+ return Void();
+ }
+ };
+
+ virtual void TearDown() override {}
+
+ Monitor monitor;
+ // updated by soundModelCallback()
+ ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+ protected:
+ sp<ISoundTriggerHw> mSoundTriggerHal;
+ sp<SoundTriggerHwCallback> mCallback;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class SoundTriggerHidlEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ private:
+};
+
+/**
+ * Test ISoundTriggerHw::getProperties() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the method returns 0 (no error)
+ * - the implementation supports at least one sound model and one key phrase
+ * - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_F(SoundTriggerHidlTest, GetProperties) {
+ ISoundTriggerHw::Properties halProperties;
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+
+ hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
+ ret = rc;
+ halProperties = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_EQ(0, ret);
+ EXPECT_GT(halProperties.maxSoundModels, 0u);
+ EXPECT_GT(halProperties.maxKeyPhrases, 0u);
+ EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+ Return<void> hidlReturn;
+ int ret = -ENODEV;
+ ISoundTriggerHw::PhraseSoundModel model;
+ SoundModelHandle handle;
+
+ model.common.type = SoundModelType::UNKNOWN;
+
+ hidlReturn = mSoundTriggerHal->loadPhraseSoundModel(
+ model,
+ mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+ int ret = -ENODEV;
+ ISoundTriggerHw::SoundModel model;
+ SoundModelHandle handle = 0;
+
+ model.type = SoundModelType::GENERIC;
+ model.data.resize(100);
+ for (auto& d : model.data) {
+ d = rand();
+ }
+
+ Return<void> loadReturn = mSoundTriggerHal->loadSoundModel(
+ model,
+ mCallback, 0, [&](int32_t retval, auto res) {
+ ret = retval;
+ handle = res;
+ });
+
+ EXPECT_TRUE(loadReturn.isOk());
+ EXPECT_NE(0, ret);
+ EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::unloadSoundModel() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without a valid loaded sound model
+ *
+ */
+TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle halHandle = 0;
+
+ hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle handle = 0;
+ PhraseRecognitionExtra phrase;
+ ISoundTriggerHw::RecognitionConfig config;
+
+ config.captureHandle = 0;
+ config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+ phrase.id = 0;
+ phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+ phrase.confidenceLevel = 0;
+
+ config.phrases.setToExternal(&phrase, 1);
+
+ hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopRecognition() method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the implementation returns an error when called without an active recognition running
+ *
+ */
+TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+ Return<int32_t> hidlReturn(0);
+ SoundModelHandle handle = 0;
+
+ hidlReturn = mSoundTriggerHal->stopRecognition(handle);
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopAllRecognitions() method
+ *
+ * Verifies that:
+ * - the implementation implements this optional method or indicates it is not support by
+ * returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+ Return<int32_t> hidlReturn(0);
+
+ hidlReturn = mSoundTriggerHal->stopAllRecognitions();
+
+ EXPECT_TRUE(hidlReturn.isOk());
+ EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
+
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(new SoundTriggerHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp
new file mode 100644
index 0000000..8d2c986
--- /dev/null
+++ b/soundtrigger/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "2.0",
+ "2.0/vts/functional",
+]
diff --git a/tests/Android.bp b/tests/Android.bp
index 4467994..31dc75e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -5,6 +5,7 @@
"baz/1.0",
"baz/1.0/default",
"expression/1.0",
+ "extension/light/2.0",
"foo/1.0",
"foo/1.0/default",
"foo/1.0/default/lib",
diff --git a/tests/bar/Android.mk b/tests/bar/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/bar/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/baz/Android.mk b/tests/baz/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/baz/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/expression/Android.mk b/tests/expression/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/expression/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/extension/light/2.0/Android.bp b/tests/extension/light/2.0/Android.bp
new file mode 100644
index 0000000..123bea1
--- /dev/null
+++ b/tests/extension/light/2.0/Android.bp
@@ -0,0 +1,64 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.tests.extension.light@2.0_hal",
+ srcs: [
+ "types.hal",
+ "IExtLight.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tests.extension.light@2.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.extension.light@2.0",
+ srcs: [
+ ":android.hardware.tests.extension.light@2.0_hal",
+ ],
+ out: [
+ "android/hardware/tests/extension/light/2.0/types.cpp",
+ "android/hardware/tests/extension/light/2.0/ExtLightAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tests.extension.light@2.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.extension.light@2.0",
+ srcs: [
+ ":android.hardware.tests.extension.light@2.0_hal",
+ ],
+ out: [
+ "android/hardware/tests/extension/light/2.0/types.h",
+ "android/hardware/tests/extension/light/2.0/IExtLight.h",
+ "android/hardware/tests/extension/light/2.0/IHwExtLight.h",
+ "android/hardware/tests/extension/light/2.0/BnHwExtLight.h",
+ "android/hardware/tests/extension/light/2.0/BpHwExtLight.h",
+ "android/hardware/tests/extension/light/2.0/BsExtLight.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tests.extension.light@2.0",
+ generated_sources: ["android.hardware.tests.extension.light@2.0_genc++"],
+ generated_headers: ["android.hardware.tests.extension.light@2.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.tests.extension.light@2.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.light@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.light@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/tests/extension/light/2.0/Android.mk b/tests/extension/light/2.0/Android.mk
new file mode 100644
index 0000000..16424a3
--- /dev/null
+++ b/tests/extension/light/2.0/Android.mk
@@ -0,0 +1,196 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tests.extension.light@2.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hardware.light@2.0-java \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (Default)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/Default.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.Default
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ExtBrightness)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtBrightness.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.ExtBrightness
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ExtLightState)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtLightState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.ExtLightState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IExtLight.hal
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/IExtLight.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IExtLight.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::IExtLight
+
+$(GEN): $(LOCAL_PATH)/IExtLight.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tests.extension.light@2.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hardware.light@2.0-java-static \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (Default)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/Default.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.Default
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ExtBrightness)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtBrightness.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.ExtBrightness
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ExtLightState)
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtLightState.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::types.ExtLightState
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IExtLight.hal
+#
+GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/IExtLight.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IExtLight.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tests.extension.light@2.0::IExtLight
+
+$(GEN): $(LOCAL_PATH)/IExtLight.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/extension/light/2.0/IExtLight.hal b/tests/extension/light/2.0/IExtLight.hal
new file mode 100644
index 0000000..1515b86
--- /dev/null
+++ b/tests/extension/light/2.0/IExtLight.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Would normally be 'vendor.example.extension.light@2.0' however, this is
+// a google extension example. A vendor extension should also live in the
+// vendor partition.
+package android.hardware.tests.extension.light@2.0;
+
+import android.hardware.light@2.0;
+
+interface IExtLight extends android.hardware.light@2.0::ILight {
+
+ /**
+ * Set the provided lights to the provided values.
+ *
+ * @param type logical light to set
+ * @param state describes what the light should look like.
+ * @return status result of applying state transformation.
+ */
+ setExtLight(Type type, ExtLightState state) generates (Status status);
+
+};
diff --git a/tests/extension/light/2.0/default/Android.mk b/tests/extension/light/2.0/default/Android.mk
new file mode 100644
index 0000000..b30d11c
--- /dev/null
+++ b/tests/extension/light/2.0/default/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tests.extension.light@2.0-service
+LOCAL_INIT_RC := android.hardware.tests.extension.light@2.0-service.rc
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ Light.cpp \
+ service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ android.hardware.light@2.0 \
+ android.hardware.tests.extension.light@2.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/extension/light/2.0/default/Light.cpp b/tests/extension/light/2.0/default/Light.cpp
new file mode 100644
index 0000000..d941e73
--- /dev/null
+++ b/tests/extension/light/2.0/default/Light.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include "Light.h"
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace extension {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::light::V2_0::ILight follow.
+Return<Status> Light::setLight(Type type, const LightState& state) {
+ // Forward types for new methods.
+
+ ExtLightState extState {
+ .state = state,
+ .interpolationOmega =
+ static_cast<int32_t>(Default::INTERPOLATION_OMEGA),
+ .brightness = // ExtBrightness inherits from Brightness
+ static_cast<ExtBrightness>(state.brightnessMode)
+ };
+
+ return setExtLight(type, extState);
+}
+
+Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
+ // implement unchanged method as you would always
+ hidl_vec<Type> vec{};
+
+ // ******************************************************
+ // Note: awesome proprietary hardware implementation here
+ // ******************************************************
+
+ _hidl_cb(vec);
+
+ return Void();
+}
+
+// Methods from ::android::hardware::example::extension::light::V2_0::ILight follow.
+Return<Status> Light::setExtLight(Type /* type */,
+ const ExtLightState& /* state */) {
+
+ // ******************************************************
+ // Note: awesome proprietary hardware implementation here
+ // ******************************************************
+
+ return Status::SUCCESS;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace light
+} // namespace extension
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/extension/light/2.0/default/Light.h b/tests/extension/light/2.0/default/Light.h
new file mode 100644
index 0000000..dc2c5dd
--- /dev/null
+++ b/tests/extension/light/2.0/default/Light.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H
+#define ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H
+
+#include <android/hardware/tests/extension/light/2.0/IExtLight.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace tests {
+namespace extension {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::tests::extension::light::V2_0::ExtLightState;
+using ::android::hardware::tests::extension::light::V2_0::IExtLight;
+using ::android::hardware::light::V2_0::ILight;
+using ::android::hardware::light::V2_0::LightState;
+using ::android::hardware::light::V2_0::Status;
+using ::android::hardware::light::V2_0::Type;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Light : public IExtLight {
+ // Methods from ::android::hardware::light::V2_0::ILight follow.
+ Return<Status> setLight(Type type, const LightState& state) override;
+ Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::example::extension::light::V2_0::ILight follow.
+ Return<Status> setExtLight(Type type, const ExtLightState& state) override;
+
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace light
+} // namespace extension
+} // namespace tests
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H
diff --git a/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
new file mode 100644
index 0000000..8f379ee
--- /dev/null
+++ b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
@@ -0,0 +1,4 @@
+service light-ext-2-0 /vendor/bin/hw/android.hardware.tests.extension.light@2.0-service
+ class hal
+ user system
+ group system
\ No newline at end of file
diff --git a/tests/extension/light/2.0/default/service.cpp b/tests/extension/light/2.0/default/service.cpp
new file mode 100644
index 0000000..4d839b2
--- /dev/null
+++ b/tests/extension/light/2.0/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.tests.extension.light@2.0-service"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Light.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::sp;
+
+using android::hardware::light::V2_0::ILight;
+using android::hardware::tests::extension::light::V2_0::implementation::Light;
+
+int main() {
+ android::sp<ILight> service = new Light();
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+ service->registerAsService();
+ joinRpcThreadpool();
+}
diff --git a/tests/extension/light/2.0/types.hal b/tests/extension/light/2.0/types.hal
new file mode 100644
index 0000000..1b09479
--- /dev/null
+++ b/tests/extension/light/2.0/types.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.tests.extension.light@2.0;
+
+import android.hardware.light@2.0;
+
+enum Default : int32_t {
+ // for calls to setLight from the framework that don't know about this
+ // extension or its requirements
+ INTERPOLATION_OMEGA = 2
+};
+
+/**
+ * One possibility is renaming an old type. Another possibility is taking
+ * advantages of the different namespaces.
+ */
+enum ExtBrightness : Brightness {
+ /**
+ * Say we're really going to use the phone as a heater.
+ */
+ EXTREME,
+
+ /**
+ * Sometimes at night, we need it to be day.
+ */
+ THE_SUN,
+};
+
+/**
+ * Structs can't inherit eachother in hidl. Use composition instead. In this
+ * case, I won't use inheritence because I want to replace Brightness with
+ * ExtBrightness.
+ */
+struct ExtLightState {
+ LightState state;
+
+ /**
+ * This is the secret sauce that will really make this extension shine.
+ * No other person has such a cool feature in their hals. Don't forget
+ * to describe all details of parameters. An interface is a contract, and
+ * specifying this contract to the letter is what allows that contracted
+ * to be maintained. :)
+ *
+ * So, this parameter represents the speed at which brightness is changed
+ * to the new value in the three dimensional space with coordinates RGB
+ * from the red, blue, and green.
+ */
+ int32_t interpolationOmega;
+
+ /**
+ * Include new values.
+ */
+ ExtBrightness brightness;
+};
diff --git a/tests/foo/Android.mk b/tests/foo/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/foo/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/inheritance/Android.mk b/tests/inheritance/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/inheritance/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/libhwbinder/Android.mk b/tests/libhwbinder/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/libhwbinder/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/msgq/Android.mk b/tests/msgq/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/msgq/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tests/pointer/Android.mk b/tests/pointer/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tests/pointer/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/thermal/1.0/Android.bp b/thermal/1.0/Android.bp
new file mode 100644
index 0000000..fab5533
--- /dev/null
+++ b/thermal/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.thermal@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IThermal.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.thermal@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.0",
+ srcs: [
+ ":android.hardware.thermal@1.0_hal",
+ ],
+ out: [
+ "android/hardware/thermal/1.0/types.cpp",
+ "android/hardware/thermal/1.0/ThermalAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.thermal@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.0",
+ srcs: [
+ ":android.hardware.thermal@1.0_hal",
+ ],
+ out: [
+ "android/hardware/thermal/1.0/types.h",
+ "android/hardware/thermal/1.0/IThermal.h",
+ "android/hardware/thermal/1.0/IHwThermal.h",
+ "android/hardware/thermal/1.0/BnHwThermal.h",
+ "android/hardware/thermal/1.0/BpHwThermal.h",
+ "android/hardware/thermal/1.0/BsThermal.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.thermal@1.0",
+ generated_sources: ["android.hardware.thermal@1.0_genc++"],
+ generated_headers: ["android.hardware.thermal@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.thermal@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/thermal/1.0/Android.mk b/thermal/1.0/Android.mk
new file mode 100644
index 0000000..7748b9e
--- /dev/null
+++ b/thermal/1.0/Android.mk
@@ -0,0 +1,380 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.thermal@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (CoolingDevice)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingDevice.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CoolingDevice
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CoolingType)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CoolingType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CpuUsage)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CpuUsage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CpuUsage
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Temperature)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/Temperature.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.Temperature
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TemperatureType)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/TemperatureType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.TemperatureType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ThermalStatus)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.ThermalStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ThermalStatusCode)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.ThermalStatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IThermal.hal
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/IThermal.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermal.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::IThermal
+
+$(GEN): $(LOCAL_PATH)/IThermal.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.thermal@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (CoolingDevice)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingDevice.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CoolingDevice
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CoolingType)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CoolingType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CpuUsage)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/CpuUsage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.CpuUsage
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Temperature)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/Temperature.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.Temperature
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (TemperatureType)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/TemperatureType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.TemperatureType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ThermalStatus)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.ThermalStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (ThermalStatusCode)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatusCode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::types.ThermalStatusCode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IThermal.hal
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/IThermal.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermal.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0::IThermal
+
+$(GEN): $(LOCAL_PATH)/IThermal.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.thermal@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/thermal/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IThermal.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.thermal@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/thermal/1.0/IThermal.hal b/thermal/1.0/IThermal.hal
new file mode 100644
index 0000000..e5f70cb
--- /dev/null
+++ b/thermal/1.0/IThermal.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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.thermal@1.0;
+
+interface IThermal {
+
+ /*
+ * Retrieves temperatures in Celsius.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with the human-readable
+ * error message.
+ * @return temperatures If status code is SUCCESS, it's filled with the
+ * current temperatures. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures.
+ *
+ */
+ @callflow(next={"*"})
+ @entry
+ @exit
+ getTemperatures()
+ generates (ThermalStatus status, vec<Temperature> temperatures);
+
+ /*
+ * Retrieves CPU usage information of each core: active and total times
+ * in ms since first boot.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with the human-readable
+ * error message.
+ * @return cpuUsages If status code is SUCCESS, it's filled with the current
+ * CPU usages. The order and number of CPUs in the list must be kept
+ * the same regardless the number of calls to this method.
+ *
+ */
+ @callflow(next={"*"})
+ @entry
+ @exit
+ getCpuUsages() generates (ThermalStatus status, vec<CpuUsage> cpuUsages);
+
+ /*
+ * Retrieves the cooling devices information.
+ *
+ * @return status Status of the operation. If status code is FAILURE,
+ * the status.debugMessage must be populated with the human-readable
+ * error message.
+ * @return devices If status code is SUCCESS, it's filled with the current
+ * cooling device information. The order of built-in cooling
+ * devices in the list must be kept the same regardless the number
+ * of calls to this method even if they go offline, if these devices
+ * exist on boot. The method always returns and never removes from
+ * the list such cooling devices.
+ *
+ */
+ @callflow(next={"*"})
+ @entry
+ @exit
+ getCoolingDevices()
+ generates (ThermalStatus status, vec<CoolingDevice> devices);
+
+};
diff --git a/thermal/1.0/default/Android.bp b/thermal/1.0/default/Android.bp
new file mode 100644
index 0000000..1510509
--- /dev/null
+++ b/thermal/1.0/default/Android.bp
@@ -0,0 +1,18 @@
+cc_library_shared {
+ name: "android.hardware.thermal@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Thermal.cpp"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.thermal@1.0",
+ ],
+}
diff --git a/thermal/1.0/default/Android.mk b/thermal/1.0/default/Android.mk
new file mode 100644
index 0000000..2d25dc3
--- /dev/null
+++ b/thermal/1.0/default/Android.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2016 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.thermal@1.0-service
+LOCAL_INIT_RC := android.hardware.thermal@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.thermal@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/thermal/1.0/default/Thermal.cpp b/thermal/1.0/default/Thermal.cpp
new file mode 100644
index 0000000..2dd0090
--- /dev/null
+++ b/thermal/1.0/default/Thermal.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.thermal@1.0-impl"
+
+#include <errno.h>
+#include <math.h>
+
+#include <vector>
+
+#include <log/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/thermal.h>
+
+#include "Thermal.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+float finalizeTemperature(float temperature) {
+ return temperature == UNKNOWN_TEMPERATURE ? NAN : temperature;
+}
+
+}
+
+Thermal::Thermal(thermal_module_t* module) : mModule(module) {}
+
+// Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ hidl_vec<Temperature> temperatures;
+
+ if (!mModule || !mModule->getTemperatures) {
+ ALOGI("getTemperatures is not implemented in Thermal HAL.");
+ _hidl_cb(status, temperatures);
+ return Void();
+ }
+
+ ssize_t size = mModule->getTemperatures(mModule, nullptr, 0);
+ if (size >= 0) {
+ std::vector<temperature_t> list;
+ list.resize(size);
+ size = mModule->getTemperatures(mModule, list.data(), list.size());
+ if (size >= 0) {
+ temperatures.resize(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ switch (list[i].type) {
+ case DEVICE_TEMPERATURE_UNKNOWN:
+ temperatures[i].type = TemperatureType::UNKNOWN;
+ break;
+ case DEVICE_TEMPERATURE_CPU:
+ temperatures[i].type = TemperatureType::CPU;
+ break;
+ case DEVICE_TEMPERATURE_GPU:
+ temperatures[i].type = TemperatureType::GPU;
+ break;
+ case DEVICE_TEMPERATURE_BATTERY:
+ temperatures[i].type = TemperatureType::BATTERY;
+ break;
+ case DEVICE_TEMPERATURE_SKIN:
+ temperatures[i].type = TemperatureType::SKIN;
+ break;
+ default:
+ ALOGE("Unknown temperature %s type", list[i].name);
+ ;
+ }
+ temperatures[i].name = list[i].name;
+ temperatures[i].currentValue = finalizeTemperature(list[i].current_value);
+ temperatures[i].throttlingThreshold = finalizeTemperature(list[i].throttling_threshold);
+ temperatures[i].shutdownThreshold = finalizeTemperature(list[i].shutdown_threshold);
+ temperatures[i].vrThrottlingThreshold =
+ finalizeTemperature(list[i].vr_throttling_threshold);
+ }
+ }
+ }
+ if (size < 0) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = strerror(-size);
+ }
+ _hidl_cb(status, temperatures);
+ return Void();
+}
+
+Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) {
+ ThermalStatus status;
+ hidl_vec<CpuUsage> cpuUsages;
+ status.code = ThermalStatusCode::SUCCESS;
+
+ if (!mModule || !mModule->getCpuUsages) {
+ ALOGI("getCpuUsages is not implemented in Thermal HAL");
+ _hidl_cb(status, cpuUsages);
+ return Void();
+ }
+
+ ssize_t size = mModule->getCpuUsages(mModule, nullptr);
+ if (size >= 0) {
+ std::vector<cpu_usage_t> list;
+ list.resize(size);
+ size = mModule->getCpuUsages(mModule, list.data());
+ if (size >= 0) {
+ list.resize(size);
+ cpuUsages.resize(size);
+ for (size_t i = 0; i < list.size(); ++i) {
+ cpuUsages[i].name = list[i].name;
+ cpuUsages[i].active = list[i].active;
+ cpuUsages[i].total = list[i].total;
+ cpuUsages[i].isOnline = list[i].is_online;
+ }
+ } else {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = strerror(-size);
+ }
+ }
+ if (size < 0) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = strerror(-size);
+ }
+ _hidl_cb(status, cpuUsages);
+ return Void();
+}
+
+Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) {
+ ThermalStatus status;
+ status.code = ThermalStatusCode::SUCCESS;
+ hidl_vec<CoolingDevice> coolingDevices;
+
+ if (!mModule || !mModule->getCoolingDevices) {
+ ALOGI("getCoolingDevices is not implemented in Thermal HAL.");
+ _hidl_cb(status, coolingDevices);
+ return Void();
+ }
+
+ ssize_t size = mModule->getCoolingDevices(mModule, nullptr, 0);
+ if (size >= 0) {
+ std::vector<cooling_device_t> list;
+ list.resize(size);
+ size = mModule->getCoolingDevices(mModule, list.data(), list.size());
+ if (size >= 0) {
+ list.resize(size);
+ coolingDevices.resize(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ switch (list[i].type) {
+ case FAN_RPM:
+ coolingDevices[i].type = CoolingType::FAN_RPM;
+ break;
+ default:
+ ALOGE("Unknown cooling device %s type", list[i].name);
+ }
+ coolingDevices[i].name = list[i].name;
+ coolingDevices[i].currentValue = list[i].current_value;
+ }
+ }
+ }
+ if (size < 0) {
+ status.code = ThermalStatusCode::FAILURE;
+ status.debugMessage = strerror(-size);
+ }
+ _hidl_cb(status, coolingDevices);
+ return Void();
+}
+
+IThermal* HIDL_FETCH_IThermal(const char* /* name */) {
+ thermal_module_t* module;
+ status_t err = hw_get_module(THERMAL_HARDWARE_MODULE_ID,
+ const_cast<hw_module_t const**>(
+ reinterpret_cast<hw_module_t**>(&module)));
+ if (err || !module) {
+ ALOGE("Couldn't load %s module (%s)", THERMAL_HARDWARE_MODULE_ID,
+ strerror(-err));
+ }
+
+ if (err == 0 && module->common.methods->open) {
+ struct hw_device_t* device;
+ err = module->common.methods->open(&module->common,
+ THERMAL_HARDWARE_MODULE_ID, &device);
+ if (err) {
+ ALOGE("Couldn't open %s module (%s)", THERMAL_HARDWARE_MODULE_ID,
+ strerror(-err));
+ } else {
+ return new Thermal(reinterpret_cast<thermal_module_t*>(device));
+ }
+ }
+ return new Thermal(module);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/1.0/default/Thermal.h b/thermal/1.0/default/Thermal.h
new file mode 100644
index 0000000..2e06289
--- /dev/null
+++ b/thermal/1.0/default/Thermal.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H
+#define ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H
+
+#include <android/hardware/thermal/1.0/IThermal.h>
+#include <hidl/Status.h>
+#include <hardware/thermal.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::thermal::V1_0::CoolingDevice;
+using ::android::hardware::thermal::V1_0::CpuUsage;
+using ::android::hardware::thermal::V1_0::IThermal;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Thermal : public IThermal {
+ Thermal(thermal_module_t* module);
+ // Methods from ::android::hardware::thermal::V1_0::IThermal follow.
+ Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override;
+ Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override;
+ Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override;
+ private:
+ thermal_module_t* mModule;
+};
+
+extern "C" IThermal* HIDL_FETCH_IThermal(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H
diff --git a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
new file mode 100644
index 0000000..f8da101
--- /dev/null
+++ b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
@@ -0,0 +1,4 @@
+service thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service
+ class hal
+ user system
+ group system readproc
diff --git a/thermal/1.0/default/service.cpp b/thermal/1.0/default/service.cpp
new file mode 100644
index 0000000..b83cbf8
--- /dev/null
+++ b/thermal/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.thermal@1.0-service"
+
+#include <android/hardware/thermal/1.0/IThermal.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::thermal::V1_0::IThermal;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IThermal>();
+}
diff --git a/thermal/1.0/types.hal b/thermal/1.0/types.hal
new file mode 100644
index 0000000..eb5d7c7
--- /dev/null
+++ b/thermal/1.0/types.hal
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 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.thermal@1.0;
+
+/** Device temperature types */
+@export
+enum TemperatureType : int32_t {
+ UNKNOWN = -1,
+ CPU = 0,
+ GPU = 1,
+ BATTERY = 2,
+ SKIN = 3,
+};
+
+enum CoolingType : uint32_t {
+ /** Fan cooling device speed in RPM. */
+ FAN_RPM = 0,
+};
+
+struct Temperature {
+ /**
+ * This temperature's type.
+ */
+ TemperatureType type;
+
+ /**
+ * Name of this temperature.
+ * All temperatures of the same "type" must have a different "name",
+ * e.g., cpu0, battery.
+ */
+ string name;
+
+ /**
+ * Current temperature in Celsius. If not available set by HAL to NAN.
+ * Current temperature can be in any units if type=UNKNOWN.
+ */
+ float currentValue;
+
+ /**
+ * Throttling temperature constant for this temperature.
+ * If not available, set by HAL to NAN.
+ */
+ float throttlingThreshold;
+
+ /**
+ * Shutdown temperature constant for this temperature.
+ * If not available, set by HAL to NAN.
+ */
+ float shutdownThreshold;
+
+ /**
+ * Threshold temperature above which the VR mode clockrate minimums cannot
+ * be maintained for this device.
+ * If not available, set by HAL to NAN.
+ */
+ float vrThrottlingThreshold;
+
+};
+
+struct CoolingDevice {
+ /**
+ * This cooling device type.
+ */
+ CoolingType type;
+
+ /**
+ * Name of this cooling device.
+ * All cooling devices of the same "type" must have a different "name".
+ */
+ string name;
+
+ /**
+ * Current cooling device value. Units depend on cooling device "type".
+ */
+ float currentValue;
+
+};
+
+struct CpuUsage {
+ /**
+ * Name of this CPU.
+ * All CPUs must have a different "name".
+ */
+ string name;
+
+ /**
+ * Active time since the last boot in ms.
+ */
+ uint64_t active;
+
+ /**
+ * Total time since the last boot in ms.
+ */
+ uint64_t total;
+
+ /**
+ * Is set to true when a core is online.
+ * If the core is offline, all other members except |name| should be ignored.
+ */
+ bool isOnline;
+
+};
+
+enum ThermalStatusCode : uint32_t {
+ /** No errors. */
+ SUCCESS = 0,
+ /** Unknown failure occured. */
+ FAILURE = 1
+};
+
+/**
+ * Generic structure to return the status of any thermal operation.
+ */
+struct ThermalStatus {
+ ThermalStatusCode code;
+
+ /**
+ * A specific error message to provide more information.
+ * This can be used for debugging purposes only.
+ */
+ string debugMessage;
+};
diff --git a/thermal/1.0/vts/Android.mk b/thermal/1.0/vts/Android.mk
new file mode 100644
index 0000000..60cc723
--- /dev/null
+++ b/thermal/1.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..9046882
--- /dev/null
+++ b/thermal/1.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalThermalV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalThermalV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.thermal@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
diff --git a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
new file mode 100644
index 0000000..3989c94
--- /dev/null
+++ b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "thermal_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/thermal/1.0/IThermal.h>
+#include <android/hardware/thermal/1.0/types.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <unistd.h>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::thermal::V1_0::CoolingDevice;
+using ::android::hardware::thermal::V1_0::CpuUsage;
+using ::android::hardware::thermal::V1_0::IThermal;
+using ::android::hardware::thermal::V1_0::Temperature;
+using ::android::hardware::thermal::V1_0::TemperatureType;
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+#define MONITORING_OPERATION_NUMBER 10
+
+#define MAX_DEVICE_TEMPERATURE 200
+#define MAX_FAN_SPEED 20000
+
+// The main test class for THERMAL HIDL HAL.
+class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>();
+ ASSERT_NE(thermal_, nullptr);
+ baseSize_ = 0;
+ names_.clear();
+ }
+
+ virtual void TearDown() override {}
+
+ protected:
+ // Check validity of temperatures returned by Thremal HAL.
+ void checkTemperatures(const hidl_vec<Temperature> temperatures) {
+ size_t size = temperatures.size();
+ EXPECT_LE(baseSize_, size);
+
+ for (size_t i = 0; i < size; ++i) {
+ checkDeviceTemperature(temperatures[i]);
+ if (i < baseSize_) {
+ EXPECT_EQ(names_[i], temperatures[i].name.c_str());
+ } else {
+ // Names must be unique.
+ EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(),
+ temperatures[i].name.c_str()));
+ names_.push_back(temperatures[i].name);
+ }
+ }
+ baseSize_ = size;
+ }
+
+ // Check validity of CPU usages returned by Thermal HAL.
+ void checkCpuUsages(const hidl_vec<CpuUsage>& cpuUsages) {
+ size_t size = cpuUsages.size();
+ // A number of CPU's does not change.
+ if (baseSize_ != 0) EXPECT_EQ(baseSize_, size);
+
+ for (size_t i = 0; i < size; ++i) {
+ checkCpuUsage(cpuUsages[i]);
+ if (i < baseSize_) {
+ EXPECT_EQ(names_[i], cpuUsages[i].name.c_str());
+ } else {
+ // Names must be unique.
+ EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(),
+ cpuUsages[i].name.c_str()));
+ names_.push_back(cpuUsages[i].name);
+ }
+ }
+ baseSize_ = size;
+ }
+
+ // Check validity of cooling devices information returned by Thermal HAL.
+ void checkCoolingDevices(const hidl_vec<CoolingDevice> coolingDevices) {
+ size_t size = coolingDevices.size();
+ EXPECT_LE(baseSize_, size);
+
+ for (size_t i = 0; i < size; ++i) {
+ checkCoolingDevice(coolingDevices[i]);
+ if (i < baseSize_) {
+ EXPECT_EQ(names_[i], coolingDevices[i].name.c_str());
+ } else {
+ // Names must be unique.
+ EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(),
+ coolingDevices[i].name.c_str()));
+ names_.push_back(coolingDevices[i].name);
+ }
+ }
+ baseSize_ = size;
+ }
+
+ sp<IThermal> thermal_;
+
+ private:
+ // Check validity of temperature returned by Thermal HAL.
+ void checkDeviceTemperature(const Temperature& temperature) {
+ // .currentValue of known type is in Celsius and must be reasonable.
+ EXPECT_TRUE(temperature.type == TemperatureType::UNKNOWN ||
+ std::abs(temperature.currentValue) < MAX_DEVICE_TEMPERATURE ||
+ isnan(temperature.currentValue));
+
+ // .name must not be empty.
+ EXPECT_LT(0u, temperature.name.size());
+
+ // .currentValue must not exceed .shutdwonThreshold if defined.
+ EXPECT_TRUE(temperature.currentValue < temperature.shutdownThreshold ||
+ isnan(temperature.currentValue) || isnan(temperature.shutdownThreshold));
+
+ // .throttlingThreshold must not exceed .shutdownThreshold if defined.
+ EXPECT_TRUE(temperature.throttlingThreshold < temperature.shutdownThreshold ||
+ isnan(temperature.throttlingThreshold) || isnan(temperature.shutdownThreshold));
+ }
+
+ // Check validity of CPU usage returned by Thermal HAL.
+ void checkCpuUsage(const CpuUsage& cpuUsage) {
+ // .active must be less than .total if CPU is online.
+ EXPECT_TRUE(!cpuUsage.isOnline ||
+ (cpuUsage.active >= 0 && cpuUsage.total >= 0 &&
+ cpuUsage.total >= cpuUsage.active));
+
+ // .name must be not empty.
+ EXPECT_LT(0u, cpuUsage.name.size());
+ }
+
+ // Check validity of a cooling device information returned by Thermal HAL.
+ void checkCoolingDevice(const CoolingDevice& coolingDevice) {
+ EXPECT_LE(0, coolingDevice.currentValue);
+ EXPECT_GT(MAX_FAN_SPEED, coolingDevice.currentValue);
+ EXPECT_LT(0u, coolingDevice.name.size());
+ }
+
+ size_t baseSize_;
+ std::vector<hidl_string> names_;
+};
+
+// Sanity test for Thermal::getTemperatures().
+TEST_F(ThermalHidlTest, TemperatureTest) {
+ hidl_vec<Temperature> passed;
+ for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
+ thermal_->getTemperatures(
+ [&passed](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ passed = temperatures;
+ });
+
+ checkTemperatures(passed);
+ sleep(1);
+ }
+}
+
+// Sanity test for Thermal::getCpuUsages().
+TEST_F(ThermalHidlTest, CpuUsageTest) {
+ hidl_vec<CpuUsage> passed;
+ for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
+ thermal_->getCpuUsages(
+ [&passed](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ passed = cpuUsages;
+ });
+
+ checkCpuUsages(passed);
+ sleep(1);
+ }
+}
+
+// Sanity test for Thermal::getCoolingDevices().
+TEST_F(ThermalHidlTest, CoolingDeviceTest) {
+ hidl_vec<CoolingDevice> passed;
+ for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) {
+ thermal_->getCoolingDevices([&passed](
+ ThermalStatus status, hidl_vec<CoolingDevice> coolingDevices) {
+ EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code);
+ passed = coolingDevices;
+ });
+
+ checkCoolingDevices(passed);
+ sleep(1);
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/thermal/Android.bp b/thermal/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/thermal/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/tv/Android.bp b/tv/Android.bp
new file mode 100644
index 0000000..ac54910
--- /dev/null
+++ b/tv/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "cec/1.0",
+ "input/1.0",
+ "input/1.0/vts/functional",
+]
diff --git a/tv/cec/1.0/Android.bp b/tv/cec/1.0/Android.bp
new file mode 100644
index 0000000..5c6919d
--- /dev/null
+++ b/tv/cec/1.0/Android.bp
@@ -0,0 +1,69 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.tv.cec@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IHdmiCec.hal",
+ "IHdmiCecCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.cec@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.cec@1.0",
+ srcs: [
+ ":android.hardware.tv.cec@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tv/cec/1.0/types.cpp",
+ "android/hardware/tv/cec/1.0/HdmiCecAll.cpp",
+ "android/hardware/tv/cec/1.0/HdmiCecCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.cec@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.cec@1.0",
+ srcs: [
+ ":android.hardware.tv.cec@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tv/cec/1.0/types.h",
+ "android/hardware/tv/cec/1.0/IHdmiCec.h",
+ "android/hardware/tv/cec/1.0/IHwHdmiCec.h",
+ "android/hardware/tv/cec/1.0/BnHwHdmiCec.h",
+ "android/hardware/tv/cec/1.0/BpHwHdmiCec.h",
+ "android/hardware/tv/cec/1.0/BsHdmiCec.h",
+ "android/hardware/tv/cec/1.0/IHdmiCecCallback.h",
+ "android/hardware/tv/cec/1.0/IHwHdmiCecCallback.h",
+ "android/hardware/tv/cec/1.0/BnHwHdmiCecCallback.h",
+ "android/hardware/tv/cec/1.0/BpHwHdmiCecCallback.h",
+ "android/hardware/tv/cec/1.0/BsHdmiCecCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tv.cec@1.0",
+ generated_sources: ["android.hardware.tv.cec@1.0_genc++"],
+ generated_headers: ["android.hardware.tv.cec@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.tv.cec@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/tv/cec/1.0/Android.mk b/tv/cec/1.0/Android.mk
new file mode 100644
index 0000000..b08099e
--- /dev/null
+++ b/tv/cec/1.0/Android.mk
@@ -0,0 +1,582 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tv.cec@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (AbortReason)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/AbortReason.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.AbortReason
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecDeviceType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecDeviceType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecDeviceType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecLogicalAddress)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecLogicalAddress.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecLogicalAddress
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecMessage)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecMessage
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecMessageType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HdmiPortInfo)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HdmiPortInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HdmiPortType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HdmiPortType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HotplugEvent)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HotplugEvent.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HotplugEvent
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MaxLength)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/MaxLength.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.MaxLength
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (OptionKey)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/OptionKey.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.OptionKey
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SendMessageResult)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/SendMessageResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.SendMessageResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHdmiCec.hal
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCec.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCec.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::IHdmiCec
+
+$(GEN): $(LOCAL_PATH)/IHdmiCec.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHdmiCecCallback.hal
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCecCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::IHdmiCecCallback
+
+$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tv.cec@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (AbortReason)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/AbortReason.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.AbortReason
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecDeviceType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecDeviceType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecDeviceType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecLogicalAddress)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecLogicalAddress.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecLogicalAddress
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecMessage)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessage.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecMessage
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (CecMessageType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.CecMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HdmiPortInfo)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HdmiPortInfo
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HdmiPortType)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HdmiPortType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (HotplugEvent)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HotplugEvent.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.HotplugEvent
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (MaxLength)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/MaxLength.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.MaxLength
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (OptionKey)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/OptionKey.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.OptionKey
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Result)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/Result.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.Result
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (SendMessageResult)
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/SendMessageResult.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::types.SendMessageResult
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHdmiCec.hal
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCec.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCec.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::IHdmiCec
+
+$(GEN): $(LOCAL_PATH)/IHdmiCec.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IHdmiCecCallback.hal
+#
+GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCecCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCecCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.tv.cec@1.0::IHdmiCecCallback
+
+$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tv/cec/1.0/IHdmiCec.hal b/tv/cec/1.0/IHdmiCec.hal
new file mode 100644
index 0000000..e8db265
--- /dev/null
+++ b/tv/cec/1.0/IHdmiCec.hal
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 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.tv.cec@1.0;
+
+import IHdmiCecCallback;
+
+/*
+ * HDMI-CEC HAL interface definition.
+ */
+interface IHdmiCec {
+ /*
+ * Passes the logical address that must be used in this system.
+ *
+ * HAL must use it to configure the hardware so that the CEC commands
+ * addressed the given logical address can be filtered in. This method must
+ * be able to be called as many times as necessary in order to support
+ * multiple logical devices.
+ *
+ * @param addr Logical address that must be used in this system. It must be
+ * in the range of valid logical addresses for the call to succeed.
+ * @return result Result status of the operation. SUCCESS if successful,
+ * FAILURE_INVALID_ARGS if the given logical address is invalid,
+ * FAILURE_BUSY if device or resource is busy
+ */
+ @callflow(next={"*"})
+ addLogicalAddress(CecLogicalAddress addr) generates (Result result);
+
+ /*
+ * Clears all the logical addresses.
+ *
+ * It is used when the system doesn't need to process CEC command any more,
+ * hence to tell HAL to stop receiving commands from the CEC bus, and change
+ * the state back to the beginning.
+ */
+ @callflow(next="addLogicalAddress")
+ @exit
+ clearLogicalAddress();
+
+ /*
+ * Gets the CEC physical address.
+ *
+ * The physical address depends on the topology of the network formed by
+ * connected HDMI devices. It is therefore likely to change if the cable is
+ * plugged off and on again. It is advised to call getPhysicalAddress to get
+ * the updated address when hot plug event takes place.
+ *
+ * @return result Result status of the operation. SUCCESS if successful,
+ * FAILURE_INVALID_STATE if HAL cannot retrieve the physical
+ * address.
+ * @return addr Physical address of this device.
+ */
+ @callflow(next="*")
+ getPhysicalAddress() generates (Result result, uint16_t addr);
+
+ /*
+ * Transmits HDMI-CEC message to other HDMI device.
+ *
+ * The method must be designed to return in a certain amount of time and not
+ * hanging forever which may happen if CEC signal line is pulled low for
+ * some reason.
+ *
+ * It must try retransmission at least once as specified in the section '7.1
+ * Frame Re-transmissions' of the CEC Spec 1.4b.
+ *
+ * @param message CEC message to be sent to other HDMI device.
+ * @return result Result status of the operation. SUCCESS if successful,
+ * NACK if the sent message is not acknowledged,
+ * BUSY if the CEC bus is busy.
+ */
+ @callflow(next="*")
+ sendMessage(CecMessage message) generates (SendMessageResult result);
+
+ /*
+ * Sets a callback that HDMI-CEC HAL must later use for incoming CEC
+ * messages or internal HDMI events.
+ *
+ * @param callback Callback object to pass hdmi events to the system. The
+ * previously registered callback must be replaced with this one.
+ */
+ @callflow(next={"addLogicalAddress"})
+ @entry
+ setCallback(IHdmiCecCallback callback);
+
+ /*
+ * Returns the CEC version supported by underlying hardware.
+ *
+ * @return version the CEC version supported by underlying hardware.
+ */
+ @callflow(next={"*"})
+ getCecVersion() generates (int32_t version);
+
+ /*
+ * Gets the identifier of the vendor.
+ *
+ * @return vendorId Identifier of the vendor that is the 24-bit unique
+ * company ID obtained from the IEEE Registration Authority
+ * Committee (RAC). The upper 8 bits must be 0.
+ */
+ @callflow(next={"*"})
+ getVendorId() generates (uint32_t vendorId);
+
+ /*
+ * Gets the hdmi port information of underlying hardware.
+ *
+ * @return infos The list of HDMI port information
+ */
+ @callflow(next={"*"})
+ getPortInfo() generates (vec<HdmiPortInfo> infos);
+
+ /*
+ * Sets flags controlling the way HDMI-CEC service works down to HAL
+ * implementation. Those flags must be used in case the feature needs update
+ * in HAL itself, firmware or microcontroller.
+ *
+ * @param key The key of the option to be updated with a new value.
+ * @param value Value to be set.
+ */
+ @callflow(next="*")
+ setOption(OptionKey key, bool value);
+
+ /*
+ * Passes the updated language information of Android system. Contains
+ * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to
+ * respond to <Get Menu Language> while in standby mode.
+ *
+ * @param language Three-letter code defined in ISO/FDIS 639-2. Must be
+ * lowercase letters. (e.g., eng for English)
+ */
+ @callflow(next="*")
+ setLanguage(string language);
+
+ /*
+ * Configures ARC circuit in the hardware logic to start or stop the
+ * feature.
+ *
+ * @param portId Port id to be configured.
+ * @param enable Flag must be either true to start the feature or false to
+ * stop it.
+ */
+ @callflow(next="*")
+ enableAudioReturnChannel(int32_t portId, bool enable);
+
+ /*
+ * Gets the connection status of the specified port.
+ *
+ * @param portId Port id to be inspected for the connection status.
+ * @return status True if a device is connected, otherwise false. The HAL
+ * must watch for +5V power signal to determine the status.
+ */
+ @callflow(next="*")
+ isConnected(int32_t portId) generates (bool status);
+};
diff --git a/tv/cec/1.0/IHdmiCecCallback.hal b/tv/cec/1.0/IHdmiCecCallback.hal
new file mode 100644
index 0000000..4a9d28f
--- /dev/null
+++ b/tv/cec/1.0/IHdmiCecCallback.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.tv.cec@1.0;
+
+interface IHdmiCecCallback {
+ /*
+ * The callback function that must be called by HAL implementation to notify
+ * the system of new CEC message arrival.
+ */
+ oneway onCecMessage(CecMessage message);
+
+ /*
+ * The callback function that must be called by HAL implementation to notify
+ * the system of new hotplug event.
+ */
+ oneway onHotplugEvent(HotplugEvent event);
+};
diff --git a/tv/cec/1.0/default/Android.mk b/tv/cec/1.0/default/Android.mk
new file mode 100644
index 0000000..9d37344
--- /dev/null
+++ b/tv/cec/1.0/default/Android.mk
@@ -0,0 +1,44 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tv.cec@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ HdmiCec.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libbase \
+ libutils \
+ libhardware \
+ android.hardware.tv.cec@1.0 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.tv.cec@1.0-service
+LOCAL_INIT_RC := android.hardware.tv.cec@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.tv.cec@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/tv/cec/1.0/default/HdmiCec.cpp b/tv/cec/1.0/default/HdmiCec.cpp
new file mode 100644
index 0000000..ebe2681
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCec.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec@1.0-impl"
+#include <android-base/logging.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCec.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+static_assert(CEC_DEVICE_INACTIVE == static_cast<int>(CecDeviceType::INACTIVE),
+ "CecDeviceType::INACTIVE must match legacy value.");
+static_assert(CEC_DEVICE_TV == static_cast<int>(CecDeviceType::TV),
+ "CecDeviceType::TV must match legacy value.");
+static_assert(CEC_DEVICE_RECORDER == static_cast<int>(CecDeviceType::RECORDER),
+ "CecDeviceType::RECORDER must match legacy value.");
+static_assert(CEC_DEVICE_TUNER == static_cast<int>(CecDeviceType::TUNER),
+ "CecDeviceType::TUNER must match legacy value.");
+static_assert(CEC_DEVICE_PLAYBACK == static_cast<int>(CecDeviceType::PLAYBACK),
+ "CecDeviceType::PLAYBACK must match legacy value.");
+static_assert(CEC_DEVICE_AUDIO_SYSTEM == static_cast<int>(CecDeviceType::AUDIO_SYSTEM),
+ "CecDeviceType::AUDIO_SYSTEM must match legacy value.");
+static_assert(CEC_DEVICE_MAX == static_cast<int>(CecDeviceType::MAX),
+ "CecDeviceType::MAX must match legacy value.");
+
+static_assert(CEC_ADDR_TV == static_cast<int>(CecLogicalAddress::TV),
+ "CecLogicalAddress::TV must match legacy value.");
+static_assert(CEC_ADDR_RECORDER_1 == static_cast<int>(CecLogicalAddress::RECORDER_1),
+ "CecLogicalAddress::RECORDER_1 must match legacy value.");
+static_assert(CEC_ADDR_RECORDER_2 == static_cast<int>(CecLogicalAddress::RECORDER_2),
+ "CecLogicalAddress::RECORDER_2 must match legacy value.");
+static_assert(CEC_ADDR_TUNER_1 == static_cast<int>(CecLogicalAddress::TUNER_1),
+ "CecLogicalAddress::TUNER_1 must match legacy value.");
+static_assert(CEC_ADDR_PLAYBACK_1 == static_cast<int>(CecLogicalAddress::PLAYBACK_1),
+ "CecLogicalAddress::PLAYBACK_1 must match legacy value.");
+static_assert(CEC_ADDR_AUDIO_SYSTEM == static_cast<int>(CecLogicalAddress::AUDIO_SYSTEM),
+ "CecLogicalAddress::AUDIO_SYSTEM must match legacy value.");
+static_assert(CEC_ADDR_TUNER_2 == static_cast<int>(CecLogicalAddress::TUNER_2),
+ "CecLogicalAddress::TUNER_2 must match legacy value.");
+static_assert(CEC_ADDR_TUNER_3 == static_cast<int>(CecLogicalAddress::TUNER_3),
+ "CecLogicalAddress::TUNER_3 must match legacy value.");
+static_assert(CEC_ADDR_PLAYBACK_2 == static_cast<int>(CecLogicalAddress::PLAYBACK_2),
+ "CecLogicalAddress::PLAYBACK_2 must match legacy value.");
+static_assert(CEC_ADDR_RECORDER_3 == static_cast<int>(CecLogicalAddress::RECORDER_3),
+ "CecLogicalAddress::RECORDER_3 must match legacy value.");
+static_assert(CEC_ADDR_TUNER_4 == static_cast<int>(CecLogicalAddress::TUNER_4),
+ "CecLogicalAddress::TUNER_4 must match legacy value.");
+static_assert(CEC_ADDR_PLAYBACK_3 == static_cast<int>(CecLogicalAddress::PLAYBACK_3),
+ "CecLogicalAddress::PLAYBACK_3 must match legacy value.");
+static_assert(CEC_ADDR_FREE_USE == static_cast<int>(CecLogicalAddress::FREE_USE),
+ "CecLogicalAddress::FREE_USE must match legacy value.");
+static_assert(CEC_ADDR_UNREGISTERED == static_cast<int>(CecLogicalAddress::UNREGISTERED),
+ "CecLogicalAddress::UNREGISTERED must match legacy value.");
+static_assert(CEC_ADDR_BROADCAST == static_cast<int>(CecLogicalAddress::BROADCAST),
+ "CecLogicalAddress::BROADCAST must match legacy value.");
+
+static_assert(CEC_MESSAGE_FEATURE_ABORT == static_cast<int>(CecMessageType::FEATURE_ABORT),
+ "CecMessageType::FEATURE_ABORT must match legacy value.");
+static_assert(CEC_MESSAGE_IMAGE_VIEW_ON == static_cast<int>(CecMessageType::IMAGE_VIEW_ON),
+ "CecMessageType::IMAGE_VIEW_ON must match legacy value.");
+static_assert(CEC_MESSAGE_TUNER_STEP_INCREMENT == static_cast<int>(
+ CecMessageType::TUNER_STEP_INCREMENT),
+ "CecMessageType::TUNER_STEP_INCREMENT must match legacy value.");
+static_assert(CEC_MESSAGE_TUNER_STEP_DECREMENT == static_cast<int>(
+ CecMessageType::TUNER_STEP_DECREMENT),
+ "CecMessageType::TUNER_STEP_DECREMENT must match legacy value.");
+static_assert(CEC_MESSAGE_TUNER_DEVICE_STATUS == static_cast<int>(
+ CecMessageType::TUNER_DEVICE_STATUS),
+ "CecMessageType::TUNER_DEVICE_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_TUNER_DEVICE_STATUS == static_cast<int>(
+ CecMessageType::GIVE_TUNER_DEVICE_STATUS),
+ "CecMessageType::GIVE_TUNER_DEVICE_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_RECORD_ON == static_cast<int>(CecMessageType::RECORD_ON),
+ "CecMessageType::RECORD_ON must match legacy value.");
+static_assert(CEC_MESSAGE_RECORD_STATUS == static_cast<int>(CecMessageType::RECORD_STATUS),
+ "CecMessageType::RECORD_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_RECORD_OFF == static_cast<int>(CecMessageType::RECORD_OFF),
+ "CecMessageType::RECORD_OFF must match legacy value.");
+static_assert(CEC_MESSAGE_TEXT_VIEW_ON == static_cast<int>(CecMessageType::TEXT_VIEW_ON),
+ "CecMessageType::TEXT_VIEW_ON must match legacy value.");
+static_assert(CEC_MESSAGE_RECORD_TV_SCREEN == static_cast<int>(CecMessageType::RECORD_TV_SCREEN),
+ "CecMessageType::RECORD_TV_SCREEN must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_DECK_STATUS == static_cast<int>(CecMessageType::GIVE_DECK_STATUS),
+ "CecMessageType::GIVE_DECK_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_STANDBY == static_cast<int>(CecMessageType::STANDBY),
+ "CecMessageType::STANDBY must match legacy value.");
+static_assert(CEC_MESSAGE_PLAY == static_cast<int>(CecMessageType::PLAY),
+ "CecMessageType::PLAY must match legacy value.");
+static_assert(CEC_MESSAGE_DECK_CONTROL == static_cast<int>(CecMessageType::DECK_CONTROL),
+ "CecMessageType::DECK_CONTROL must match legacy value.");
+static_assert(CEC_MESSAGE_TIMER_CLEARED_STATUS == static_cast<int>(
+ CecMessageType::TIMER_CLEARED_STATUS),
+ "CecMessageType::TIMER_CLEARED_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_USER_CONTROL_PRESSED == static_cast<int>(
+ CecMessageType::USER_CONTROL_PRESSED),
+ "CecMessageType::USER_CONTROL_PRESSED must match legacy value.");
+static_assert(CEC_MESSAGE_USER_CONTROL_RELEASED == static_cast<int>(
+ CecMessageType::USER_CONTROL_RELEASED),
+ "CecMessageType::USER_CONTROL_RELEASED must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_OSD_NAME == static_cast<int>(CecMessageType::GIVE_OSD_NAME),
+ "CecMessageType::GIVE_OSD_NAME must match legacy value.");
+static_assert(CEC_MESSAGE_SET_OSD_NAME == static_cast<int>(CecMessageType::SET_OSD_NAME),
+ "CecMessageType::SET_OSD_NAME must match legacy value.");
+static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_REQUEST == static_cast<int>(
+ CecMessageType::SYSTEM_AUDIO_MODE_REQUEST),
+ "CecMessageType::SYSTEM_AUDIO_MODE_REQUEST must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_AUDIO_STATUS == static_cast<int>(CecMessageType::GIVE_AUDIO_STATUS),
+ "CecMessageType::GIVE_AUDIO_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_SET_SYSTEM_AUDIO_MODE == static_cast<int>(
+ CecMessageType::SET_SYSTEM_AUDIO_MODE),
+ "CecMessageType::SET_SYSTEM_AUDIO_MODE must match legacy value.");
+static_assert(CEC_MESSAGE_REPORT_AUDIO_STATUS == static_cast<int>(
+ CecMessageType::REPORT_AUDIO_STATUS),
+ "CecMessageType::REPORT_AUDIO_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS == static_cast<int>(
+ CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS),
+ "CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_STATUS == static_cast<int>(
+ CecMessageType::SYSTEM_AUDIO_MODE_STATUS),
+ "CecMessageType::SYSTEM_AUDIO_MODE_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_ROUTING_CHANGE == static_cast<int>(CecMessageType::ROUTING_CHANGE),
+ "CecMessageType::ROUTING_CHANGE must match legacy value.");
+static_assert(CEC_MESSAGE_ROUTING_INFORMATION == static_cast<int>(
+ CecMessageType::ROUTING_INFORMATION),
+ "CecMessageType::ROUTING_INFORMATION must match legacy value.");
+static_assert(CEC_MESSAGE_ACTIVE_SOURCE == static_cast<int>(CecMessageType::ACTIVE_SOURCE),
+ "CecMessageType::ACTIVE_SOURCE must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS == static_cast<int>(
+ CecMessageType::GIVE_PHYSICAL_ADDRESS),
+ "CecMessageType::GIVE_PHYSICAL_ADDRESS must match legacy value.");
+static_assert(CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS == static_cast<int>(
+ CecMessageType::REPORT_PHYSICAL_ADDRESS),
+ "CecMessageType::REPORT_PHYSICAL_ADDRESS must match legacy value.");
+static_assert(CEC_MESSAGE_REQUEST_ACTIVE_SOURCE == static_cast<int>(
+ CecMessageType::REQUEST_ACTIVE_SOURCE),
+ "CecMessageType::REQUEST_ACTIVE_SOURCE must match legacy value.");
+static_assert(CEC_MESSAGE_SET_STREAM_PATH == static_cast<int>(CecMessageType::SET_STREAM_PATH),
+ "CecMessageType::SET_STREAM_PATH must match legacy value.");
+static_assert(CEC_MESSAGE_DEVICE_VENDOR_ID == static_cast<int>(CecMessageType::DEVICE_VENDOR_ID),
+ "CecMessageType::DEVICE_VENDOR_ID must match legacy value.");
+static_assert(CEC_MESSAGE_VENDOR_COMMAND == static_cast<int>(CecMessageType::VENDOR_COMMAND),
+ "CecMessageType::VENDOR_COMMAND must match legacy value.");
+static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_DOWN == static_cast<int>(
+ CecMessageType::VENDOR_REMOTE_BUTTON_DOWN),
+ "CecMessageType::VENDOR_REMOTE_BUTTON_DOWN must match legacy value.");
+static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_UP == static_cast<int>(
+ CecMessageType::VENDOR_REMOTE_BUTTON_UP),
+ "CecMessageType::VENDOR_REMOTE_BUTTON_UP must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID == static_cast<int>(
+ CecMessageType::GIVE_DEVICE_VENDOR_ID),
+ "CecMessageType::GIVE_DEVICE_VENDOR_ID must match legacy value.");
+static_assert(CEC_MESSAGE_MENU_REQUEST == static_cast<int>(CecMessageType::MENU_REQUEST),
+ "CecMessageType::MENU_REQUEST must match legacy value.");
+static_assert(CEC_MESSAGE_MENU_STATUS == static_cast<int>(CecMessageType::MENU_STATUS),
+ "CecMessageType::MENU_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS == static_cast<int>(
+ CecMessageType::GIVE_DEVICE_POWER_STATUS),
+ "CecMessageType::GIVE_DEVICE_POWER_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_REPORT_POWER_STATUS == static_cast<int>(
+ CecMessageType::REPORT_POWER_STATUS),
+ "CecMessageType::REPORT_POWER_STATUS must match legacy value.");
+static_assert(CEC_MESSAGE_GET_MENU_LANGUAGE == static_cast<int>(CecMessageType::GET_MENU_LANGUAGE),
+ "CecMessageType::GET_MENU_LANGUAGE must match legacy value.");
+static_assert(CEC_MESSAGE_SELECT_ANALOG_SERVICE == static_cast<int>(
+ CecMessageType::SELECT_ANALOG_SERVICE),
+ "CecMessageType::SELECT_ANALOG_SERVICE must match legacy value.");
+static_assert(CEC_MESSAGE_SELECT_DIGITAL_SERVICE == static_cast<int>(
+ CecMessageType::SELECT_DIGITAL_SERVICE),
+ "CecMessageType::SELECT_DIGITAL_SERVICE must match legacy value.");
+static_assert(CEC_MESSAGE_SET_DIGITAL_TIMER == static_cast<int>(CecMessageType::SET_DIGITAL_TIMER),
+ "CecMessageType::SET_DIGITAL_TIMER must match legacy value.");
+static_assert(CEC_MESSAGE_CLEAR_DIGITAL_TIMER == static_cast<int>(
+ CecMessageType::CLEAR_DIGITAL_TIMER),
+ "CecMessageType::CLEAR_DIGITAL_TIMER must match legacy value.");
+static_assert(CEC_MESSAGE_SET_AUDIO_RATE == static_cast<int>(CecMessageType::SET_AUDIO_RATE),
+ "CecMessageType::SET_AUDIO_RATE must match legacy value.");
+static_assert(CEC_MESSAGE_INACTIVE_SOURCE == static_cast<int>(CecMessageType::INACTIVE_SOURCE),
+ "CecMessageType::INACTIVE_SOURCE must match legacy value.");
+static_assert(CEC_MESSAGE_CEC_VERSION == static_cast<int>(CecMessageType::CEC_VERSION),
+ "CecMessageType::CEC_VERSION must match legacy value.");
+static_assert(CEC_MESSAGE_GET_CEC_VERSION == static_cast<int>(CecMessageType::GET_CEC_VERSION),
+ "CecMessageType::GET_CEC_VERSION must match legacy value.");
+static_assert(CEC_MESSAGE_VENDOR_COMMAND_WITH_ID == static_cast<int>(
+ CecMessageType::VENDOR_COMMAND_WITH_ID),
+ "CecMessageType::VENDOR_COMMAND_WITH_ID must match legacy value.");
+static_assert(CEC_MESSAGE_CLEAR_EXTERNAL_TIMER == static_cast<int>(
+ CecMessageType::CLEAR_EXTERNAL_TIMER),
+ "CecMessageType::CLEAR_EXTERNAL_TIMER must match legacy value.");
+static_assert(CEC_MESSAGE_SET_EXTERNAL_TIMER == static_cast<int>(
+ CecMessageType::SET_EXTERNAL_TIMER),
+ "CecMessageType::SET_EXTERNAL_TIMER must match legacy value.");
+static_assert(CEC_MESSAGE_INITIATE_ARC == static_cast<int>(CecMessageType::INITIATE_ARC),
+ "CecMessageType::INITIATE_ARC must match legacy value.");
+static_assert(CEC_MESSAGE_REPORT_ARC_INITIATED == static_cast<int>(
+ CecMessageType::REPORT_ARC_INITIATED),
+ "CecMessageType::REPORT_ARC_INITIATED must match legacy value.");
+static_assert(CEC_MESSAGE_REPORT_ARC_TERMINATED == static_cast<int>(
+ CecMessageType::REPORT_ARC_TERMINATED),
+ "CecMessageType::REPORT_ARC_TERMINATED must match legacy value.");
+static_assert(CEC_MESSAGE_REQUEST_ARC_INITIATION == static_cast<int>(
+ CecMessageType::REQUEST_ARC_INITIATION),
+ "CecMessageType::REQUEST_ARC_INITIATION must match legacy value.");
+static_assert(CEC_MESSAGE_REQUEST_ARC_TERMINATION == static_cast<int>(
+ CecMessageType::REQUEST_ARC_TERMINATION),
+ "CecMessageType::REQUEST_ARC_TERMINATION must match legacy value.");
+static_assert(CEC_MESSAGE_TERMINATE_ARC == static_cast<int>(CecMessageType::TERMINATE_ARC),
+ "CecMessageType::TERMINATE_ARC must match legacy value.");
+static_assert(CEC_MESSAGE_ABORT == static_cast<int>(CecMessageType::ABORT),
+ "CecMessageType::ABORT must match legacy value.");
+
+static_assert(ABORT_UNRECOGNIZED_MODE == static_cast<int>(AbortReason::UNRECOGNIZED_MODE),
+ "AbortReason::UNRECOGNIZED_MODE must match legacy value.");
+static_assert(ABORT_NOT_IN_CORRECT_MODE == static_cast<int>(AbortReason::NOT_IN_CORRECT_MODE),
+ "AbortReason::NOT_IN_CORRECT_MODE must match legacy value.");
+static_assert(ABORT_CANNOT_PROVIDE_SOURCE == static_cast<int>(AbortReason::CANNOT_PROVIDE_SOURCE),
+ "AbortReason::CANNOT_PROVIDE_SOURCE must match legacy value.");
+static_assert(ABORT_INVALID_OPERAND == static_cast<int>(AbortReason::INVALID_OPERAND),
+ "AbortReason::INVALID_OPERAND must match legacy value.");
+static_assert(ABORT_REFUSED == static_cast<int>(AbortReason::REFUSED),
+ "AbortReason::REFUSED must match legacy value.");
+static_assert(ABORT_UNABLE_TO_DETERMINE == static_cast<int>(AbortReason::UNABLE_TO_DETERMINE),
+ "AbortReason::UNABLE_TO_DETERMINE must match legacy value.");
+
+static_assert(HDMI_RESULT_SUCCESS == static_cast<int>(SendMessageResult::SUCCESS),
+ "SendMessageResult::SUCCESS must match legacy value.");
+static_assert(HDMI_RESULT_NACK == static_cast<int>(SendMessageResult::NACK),
+ "SendMessageResult::NACK must match legacy value.");
+static_assert(HDMI_RESULT_BUSY == static_cast<int>(SendMessageResult::BUSY),
+ "SendMessageResult::BUSY must match legacy value.");
+static_assert(HDMI_RESULT_FAIL == static_cast<int>(SendMessageResult::FAIL),
+ "SendMessageResult::FAIL must match legacy value.");
+
+static_assert(HDMI_INPUT == static_cast<int>(HdmiPortType::INPUT),
+ "HdmiPortType::INPUT must match legacy value.");
+static_assert(HDMI_OUTPUT == static_cast<int>(HdmiPortType::OUTPUT),
+ "HdmiPortType::OUTPUT must match legacy value.");
+
+static_assert(HDMI_OPTION_WAKEUP == static_cast<int>(OptionKey::WAKEUP),
+ "OptionKey::WAKEUP must match legacy value.");
+static_assert(HDMI_OPTION_ENABLE_CEC == static_cast<int>(OptionKey::ENABLE_CEC),
+ "OptionKey::ENABLE_CEC must match legacy value.");
+static_assert(HDMI_OPTION_SYSTEM_CEC_CONTROL == static_cast<int>(OptionKey::SYSTEM_CEC_CONTROL),
+ "OptionKey::SYSTEM_CEC_CONTROL must match legacy value.");
+
+sp<IHdmiCecCallback> HdmiCec::mCallback = nullptr;
+
+HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) {
+}
+
+// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+Return<Result> HdmiCec::addLogicalAddress(CecLogicalAddress addr) {
+ int ret = mDevice->add_logical_address(mDevice, static_cast<cec_logical_address_t>(addr));
+ switch (ret) {
+ case 0:
+ return Result::SUCCESS;
+ case -EINVAL:
+ return Result::FAILURE_INVALID_ARGS;
+ case -ENOTSUP:
+ return Result::FAILURE_NOT_SUPPORTED;
+ case -EBUSY:
+ return Result::FAILURE_BUSY;
+ default:
+ return Result::FAILURE_UNKNOWN;
+ }
+}
+
+Return<void> HdmiCec::clearLogicalAddress() {
+ mDevice->clear_logical_address(mDevice);
+ return Void();
+}
+
+Return<void> HdmiCec::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) {
+ uint16_t addr;
+ int ret = mDevice->get_physical_address(mDevice, &addr);
+ switch (ret) {
+ case 0:
+ _hidl_cb(Result::SUCCESS, addr);
+ break;
+ case -EBADF:
+ _hidl_cb(Result::FAILURE_INVALID_STATE, addr);
+ break;
+ default:
+ _hidl_cb(Result::FAILURE_UNKNOWN, addr);
+ break;
+ }
+ return Void();
+}
+
+Return<SendMessageResult> HdmiCec::sendMessage(const CecMessage& message) {
+ cec_message_t legacyMessage {
+ .initiator = static_cast<cec_logical_address_t>(message.initiator),
+ .destination = static_cast<cec_logical_address_t>(message.destination),
+ .length = message.body.size(),
+ };
+ for (size_t i = 0; i < message.body.size(); ++i) {
+ legacyMessage.body[i] = static_cast<unsigned char>(message.body[i]);
+ }
+ return static_cast<SendMessageResult>(mDevice->send_message(mDevice, &legacyMessage));
+}
+
+Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) {
+ mCallback = callback;
+ mDevice->register_event_callback(mDevice, eventCallback, nullptr);
+ return Void();
+}
+
+Return<int32_t> HdmiCec::getCecVersion() {
+ int version;
+ mDevice->get_version(mDevice, &version);
+ return static_cast<int32_t>(version);
+}
+
+Return<uint32_t> HdmiCec::getVendorId() {
+ uint32_t vendor_id;
+ mDevice->get_vendor_id(mDevice, &vendor_id);
+ return vendor_id;
+}
+
+Return<void> HdmiCec::getPortInfo(getPortInfo_cb _hidl_cb) {
+ struct hdmi_port_info* legacyPorts;
+ int numPorts;
+ hidl_vec<HdmiPortInfo> portInfos;
+ mDevice->get_port_info(mDevice, &legacyPorts, &numPorts);
+ portInfos.resize(numPorts);
+ for (int i = 0; i < numPorts; ++i) {
+ portInfos[i] = {
+ .type = static_cast<HdmiPortType>(legacyPorts[i].type),
+ .portId = static_cast<uint32_t>(legacyPorts[i].port_id),
+ .cecSupported = legacyPorts[i].cec_supported != 0,
+ .arcSupported = legacyPorts[i].arc_supported != 0,
+ .physicalAddress = legacyPorts[i].physical_address
+ };
+ }
+ _hidl_cb(portInfos);
+ return Void();
+}
+
+Return<void> HdmiCec::setOption(OptionKey key, bool value) {
+ mDevice->set_option(mDevice, static_cast<int>(key), value ? 1 : 0);
+ return Void();
+}
+
+Return<void> HdmiCec::setLanguage(const hidl_string& language) {
+ if (language.size() != 3) {
+ LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+ << ".";
+ return Void();
+ }
+ const char *languageStr = language.c_str();
+ int convertedLanguage = ((languageStr[0] & 0xFF) << 16)
+ | ((languageStr[1] & 0xFF) << 8)
+ | (languageStr[2] & 0xFF);
+ mDevice->set_option(mDevice, HDMI_OPTION_SET_LANG, convertedLanguage);
+ return Void();
+}
+
+Return<void> HdmiCec::enableAudioReturnChannel(int32_t portId, bool enable) {
+ mDevice->set_audio_return_channel(mDevice, portId, enable ? 1 : 0);
+ return Void();
+}
+
+Return<bool> HdmiCec::isConnected(int32_t portId) {
+ return mDevice->is_connected(mDevice, portId) > 0;
+}
+
+
+IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) {
+ hdmi_cec_device_t* hdmi_cec_device;
+ int ret = 0;
+ const hw_module_t* hw_module = nullptr;
+
+ ret = hw_get_module (HDMI_CEC_HARDWARE_MODULE_ID, &hw_module);
+ if (ret == 0) {
+ ret = hdmi_cec_open (hw_module, &hdmi_cec_device);
+ if (ret != 0) {
+ LOG(ERROR) << "hdmi_cec_open " << hal << " failed: " << ret;
+ }
+ } else {
+ LOG(ERROR) << "hw_get_module " << hal << " failed: " << ret;
+ }
+
+ if (ret == 0) {
+ return new HdmiCec(hdmi_cec_device);
+ } else {
+ LOG(ERROR) << "Passthrough failed to load legacy HAL.";
+ return nullptr;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/cec/1.0/default/HdmiCec.h b/tv/cec/1.0/default/HdmiCec.h
new file mode 100644
index 0000000..34a3bb0
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCec.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
+#define ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
+
+#include <algorithm>
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hidl/Status.h>
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct HdmiCec : public IHdmiCec {
+ HdmiCec(hdmi_cec_device_t* device);
+ // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+ Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
+ Return<void> clearLogicalAddress() override;
+ Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
+ Return<SendMessageResult> sendMessage(const CecMessage& message) override;
+ Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override;
+ Return<int32_t> getCecVersion() override;
+ Return<uint32_t> getVendorId() override;
+ Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
+ Return<void> setOption(OptionKey key, bool value) override;
+ Return<void> setLanguage(const hidl_string& language) override;
+ Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
+ Return<bool> isConnected(int32_t portId) override;
+
+ static void eventCallback(const hdmi_event_t* event, void* /* arg */) {
+ if (mCallback != nullptr && event != nullptr) {
+ if (event->type == HDMI_EVENT_CEC_MESSAGE) {
+ size_t length = std::min(event->cec.length,
+ static_cast<size_t>(MaxLength::MESSAGE_BODY));
+ CecMessage cecMessage {
+ .initiator = static_cast<CecLogicalAddress>(event->cec.initiator),
+ .destination = static_cast<CecLogicalAddress>(event->cec.destination),
+ };
+ cecMessage.body.resize(length);
+ for (size_t i = 0; i < length; ++i) {
+ cecMessage.body[i] = static_cast<uint8_t>(event->cec.body[i]);
+ }
+ mCallback->onCecMessage(cecMessage);
+ } else if (event->type == HDMI_EVENT_HOT_PLUG) {
+ HotplugEvent hotplugEvent {
+ .connected = event->hotplug.connected > 0,
+ .portId = static_cast<uint32_t>(event->hotplug.port_id)
+ };
+ mCallback->onHotplugEvent(hotplugEvent);
+ }
+ }
+ }
+
+private:
+ static sp<IHdmiCecCallback> mCallback;
+ const hdmi_cec_device_t* mDevice;
+};
+
+extern "C" IHdmiCec* HIDL_FETCH_IHdmiCec(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
new file mode 100644
index 0000000..9c80094
--- /dev/null
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
@@ -0,0 +1,4 @@
+service cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
+ class hal
+ user system
+ group system
diff --git a/tv/cec/1.0/default/service.cpp b/tv/cec/1.0/default/service.cpp
new file mode 100644
index 0000000..74b1f62
--- /dev/null
+++ b/tv/cec/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec@1.0-service"
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::tv::cec::V1_0::IHdmiCec;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IHdmiCec>();
+}
diff --git a/tv/cec/1.0/types.hal b/tv/cec/1.0/types.hal
new file mode 100644
index 0000000..ec2e373
--- /dev/null
+++ b/tv/cec/1.0/types.hal
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2016 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.tv.cec@1.0;
+
+enum MaxLength : int32_t {
+ MESSAGE_BODY = 15,
+};
+
+enum CecDeviceType : int32_t {
+ INACTIVE = -1,
+ TV = 0,
+ RECORDER = 1,
+ TUNER = 3,
+ PLAYBACK = 4,
+ AUDIO_SYSTEM = 5,
+ MAX = AUDIO_SYSTEM,
+};
+
+enum CecLogicalAddress : int32_t {
+ TV = 0,
+ RECORDER_1 = 1,
+ RECORDER_2 = 2,
+ TUNER_1 = 3,
+ PLAYBACK_1 = 4,
+ AUDIO_SYSTEM = 5,
+ TUNER_2 = 6,
+ TUNER_3 = 7,
+ PLAYBACK_2 = 8,
+ RECORDER_3 = 9,
+ TUNER_4 = 10,
+ PLAYBACK_3 = 11,
+ FREE_USE = 14,
+ UNREGISTERED = 15, // as Initiator address
+ BROADCAST = 15, // as Destination address
+};
+
+/*
+ * HDMI CEC message types. The assigned values represent opcode used in CEC
+ * frame as specified in CEC Table 8-26 of the CEC Spec 1.4b.
+ */
+enum CecMessageType : int32_t {
+ FEATURE_ABORT = 0x00,
+ IMAGE_VIEW_ON = 0x04,
+ TUNER_STEP_INCREMENT = 0x05,
+ TUNER_STEP_DECREMENT = 0x06,
+ TUNER_DEVICE_STATUS = 0x07,
+ GIVE_TUNER_DEVICE_STATUS = 0x08,
+ RECORD_ON = 0x09,
+ RECORD_STATUS = 0x0A,
+ RECORD_OFF = 0x0B,
+ TEXT_VIEW_ON = 0x0D,
+ RECORD_TV_SCREEN = 0x0F,
+ GIVE_DECK_STATUS = 0x1A,
+ DECK_STATUS = 0x1B,
+ SET_MENU_LANGUAGE = 0x32,
+ CLEAR_ANALOG_TIMER = 0x33,
+ SET_ANALOG_TIMER = 0x34,
+ TIMER_STATUS = 0x35,
+ STANDBY = 0x36,
+ PLAY = 0x41,
+ DECK_CONTROL = 0x42,
+ TIMER_CLEARED_STATUS = 0x43,
+ USER_CONTROL_PRESSED = 0x44,
+ USER_CONTROL_RELEASED = 0x45,
+ GIVE_OSD_NAME = 0x46,
+ SET_OSD_NAME = 0x47,
+ SET_OSD_STRING = 0x64,
+ SET_TIMER_PROGRAM_TITLE = 0x67,
+ SYSTEM_AUDIO_MODE_REQUEST = 0x70,
+ GIVE_AUDIO_STATUS = 0x71,
+ SET_SYSTEM_AUDIO_MODE = 0x72,
+ REPORT_AUDIO_STATUS = 0x7A,
+ GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
+ SYSTEM_AUDIO_MODE_STATUS = 0x7E,
+ ROUTING_CHANGE = 0x80,
+ ROUTING_INFORMATION = 0x81,
+ ACTIVE_SOURCE = 0x82,
+ GIVE_PHYSICAL_ADDRESS = 0x83,
+ REPORT_PHYSICAL_ADDRESS = 0x84,
+ REQUEST_ACTIVE_SOURCE = 0x85,
+ SET_STREAM_PATH = 0x86,
+ DEVICE_VENDOR_ID = 0x87,
+ VENDOR_COMMAND = 0x89,
+ VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
+ VENDOR_REMOTE_BUTTON_UP = 0x8B,
+ GIVE_DEVICE_VENDOR_ID = 0x8C,
+ MENU_REQUEST = 0x8D,
+ MENU_STATUS = 0x8E,
+ GIVE_DEVICE_POWER_STATUS = 0x8F,
+ REPORT_POWER_STATUS = 0x90,
+ GET_MENU_LANGUAGE = 0x91,
+ SELECT_ANALOG_SERVICE = 0x92,
+ SELECT_DIGITAL_SERVICE = 0x93,
+ SET_DIGITAL_TIMER = 0x97,
+ CLEAR_DIGITAL_TIMER = 0x99,
+ SET_AUDIO_RATE = 0x9A,
+ INACTIVE_SOURCE = 0x9D,
+ CEC_VERSION = 0x9E,
+ GET_CEC_VERSION = 0x9F,
+ VENDOR_COMMAND_WITH_ID = 0xA0,
+ CLEAR_EXTERNAL_TIMER = 0xA1,
+ SET_EXTERNAL_TIMER = 0xA2,
+ INITIATE_ARC = 0xC0,
+ REPORT_ARC_INITIATED = 0xC1,
+ REPORT_ARC_TERMINATED = 0xC2,
+ REQUEST_ARC_INITIATION = 0xC3,
+ REQUEST_ARC_TERMINATION = 0xC4,
+ TERMINATE_ARC = 0xC5,
+ ABORT = 0xFF,
+};
+
+/*
+ * Operand description [Abort Reason]
+ */
+enum AbortReason : int32_t {
+ UNRECOGNIZED_MODE = 0,
+ NOT_IN_CORRECT_MODE = 1,
+ CANNOT_PROVIDE_SOURCE = 2,
+ INVALID_OPERAND = 3,
+ REFUSED = 4,
+ UNABLE_TO_DETERMINE = 5,
+};
+
+enum Result : int32_t {
+ SUCCESS = 0,
+ FAILURE_UNKNOWN = 1,
+ FAILURE_INVALID_ARGS = 2,
+ FAILURE_INVALID_STATE = 3,
+ FAILURE_NOT_SUPPORTED = 4,
+ FAILURE_BUSY = 5,
+};
+
+/*
+ * error code used for send_message.
+ */
+enum SendMessageResult : int32_t {
+ SUCCESS = 0,
+ NACK = 1, // not acknowledged
+ BUSY = 2, // bus is busy
+ FAIL = 3,
+};
+
+/*
+ * HDMI port type.
+ */
+enum HdmiPortType : int32_t {
+ INPUT = 0,
+ OUTPUT = 1,
+};
+
+/*
+ * Options used for IHdmiCec.setOption()
+ */
+enum OptionKey : int32_t {
+ /* When set to false, HAL does not wake up the system upon receiving <Image
+ * View On> or <Text View On>. Used when user changes the TV settings to
+ * disable the auto TV on functionality.
+ * True by default.
+ */
+ WAKEUP = 1,
+
+ /* When set to false, all the CEC commands are discarded. Used when user
+ * changes the TV settings to disable CEC functionality.
+ * True by default.
+ */
+ ENABLE_CEC = 2,
+
+ /* Setting this flag to false means Android system must stop handling CEC
+ * service and yield the control over to the microprocessor that is powered
+ * on through the standby mode. When set to true, the system must gain the
+ * control over, hence telling the microprocessor to stop handling the CEC
+ * commands. For example, this may be called when system goes in and out of
+ * standby mode to notify the microprocessor that it should start/stop
+ * handling CEC commands on behalf of the system.
+ * False by default.
+ */
+ SYSTEM_CEC_CONTROL = 3,
+
+ /* Option 4 not used */
+};
+
+struct CecMessage {
+ /* logical address of sender */
+ CecLogicalAddress initiator;
+
+ /* logical address of receiver */
+ CecLogicalAddress destination;
+
+ /* The maximum size of body is 15 (MaxLength::MESSAGE_BODY) as specified in
+ * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored. */
+ vec<uint8_t> body;
+};
+
+struct HotplugEvent {
+ bool connected;
+ uint32_t portId;
+};
+
+/*
+ * HDMI port descriptor
+ */
+struct HdmiPortInfo {
+ HdmiPortType type;
+ uint32_t portId; // Should start from 1 which corresponds to HDMI "port 1".
+ bool cecSupported;
+ bool arcSupported;
+ uint16_t physicalAddress;
+};
diff --git a/tv/cec/Android.mk b/tv/cec/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tv/cec/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tv/input/1.0/Android.bp b/tv/input/1.0/Android.bp
new file mode 100644
index 0000000..ae5e3de
--- /dev/null
+++ b/tv/input/1.0/Android.bp
@@ -0,0 +1,71 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.tv.input@1.0_hal",
+ srcs: [
+ "types.hal",
+ "ITvInput.hal",
+ "ITvInputCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.input@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0",
+ srcs: [
+ ":android.hardware.tv.input@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/types.cpp",
+ "android/hardware/tv/input/1.0/TvInputAll.cpp",
+ "android/hardware/tv/input/1.0/TvInputCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.input@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0",
+ srcs: [
+ ":android.hardware.tv.input@1.0_hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/types.h",
+ "android/hardware/tv/input/1.0/ITvInput.h",
+ "android/hardware/tv/input/1.0/IHwTvInput.h",
+ "android/hardware/tv/input/1.0/BnHwTvInput.h",
+ "android/hardware/tv/input/1.0/BpHwTvInput.h",
+ "android/hardware/tv/input/1.0/BsTvInput.h",
+ "android/hardware/tv/input/1.0/ITvInputCallback.h",
+ "android/hardware/tv/input/1.0/IHwTvInputCallback.h",
+ "android/hardware/tv/input/1.0/BnHwTvInputCallback.h",
+ "android/hardware/tv/input/1.0/BpHwTvInputCallback.h",
+ "android/hardware/tv/input/1.0/BsTvInputCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tv.input@1.0",
+ generated_sources: ["android.hardware.tv.input@1.0_genc++"],
+ generated_headers: ["android.hardware.tv.input@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.tv.input@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/tv/input/1.0/Android.mk b/tv/input/1.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tv/input/1.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/tv/input/1.0/ITvInput.hal b/tv/input/1.0/ITvInput.hal
new file mode 100644
index 0000000..43de276
--- /dev/null
+++ b/tv/input/1.0/ITvInput.hal
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.tv.input@1.0;
+
+import ITvInputCallback;
+
+interface ITvInput {
+ /*
+ * Sets a callback for events.
+ *
+ * Note that initially no device is available in the client side, so the
+ * implementation must notify all the currently available devices including
+ * static devices via callback once callback is set.
+ *
+ * @param callback Callback object to pass events.
+ */
+ @entry
+ @exit
+ @callflow(next={"getStreamConfigurations"})
+ setCallback(ITvInputCallback callback);
+
+ /*
+ * Gets stream configurations for a specific device.
+ *
+ * The configs object is valid only until the next
+ * STREAM_CONFIGURATIONS_CHANGED event.
+ *
+ * @param deviceId Device ID for the configurations.
+ * @return result OK upon success. Otherwise,
+ * INVALID_ARGUMENTS if the given device ID is not valid.
+ * @return configurations An array of available configurations.
+ */
+ @callflow(next={"openStream", "getStreamConfigurations", "closeStream"})
+ getStreamConfigurations(int32_t deviceId)
+ generates (Result result, vec<TvStreamConfig> configurations);
+
+ /*
+ * Opens a specific stream in a device.
+ *
+ * @param deviceId Device ID for the steam to open.
+ * @param streamId Steam ID for the steam to open. Must be one of the
+ * stream IDs returned from getStreamConfigurations().
+ * @return result OK upon success. Otherwise,
+ * INVALID_ARGUMENTS if any of given IDs are not valid;
+ * INVALID_STATE if the stream with the given ID is already open;
+ * NO_RESOURCE if the client must close other streams to open the
+ * stream.
+ * @return sidebandStream handle for sideband stream.
+ */
+ @callflow(next={"closeStream", "getStreamConfigurations", "openStream"})
+ openStream(int32_t deviceId, int32_t streamId)
+ generates (Result result, handle sidebandStream);
+
+ /*
+ * Closes a specific stream in a device.
+ *
+ * @param deviceId Device ID for the steam to open.
+ * @param streamId Steam ID for the steam to open.
+ * @return result OK upon success. Otherwise,
+ * INVALID_ARGUMENTS if any of given IDs are not valid;
+ * INVALID_STATE if the stream with the given ID is not open.
+ */
+ @callflow(next={"getStreamConfigurations", "openStream", "closeStream"})
+ closeStream(int32_t deviceId, int32_t streamId) generates (Result result);
+};
diff --git a/tv/input/1.0/ITvInputCallback.hal b/tv/input/1.0/ITvInputCallback.hal
new file mode 100644
index 0000000..f2f07a0
--- /dev/null
+++ b/tv/input/1.0/ITvInputCallback.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.tv.input@1.0;
+
+interface ITvInputCallback {
+ /*
+ * Notifies the client that an event has occured. For possible event types,
+ * check TvInputEventType.
+ *
+ * @param event Event passed to the client.
+ */
+ notify(TvInputEvent event);
+};
diff --git a/tv/input/1.0/default/Android.mk b/tv/input/1.0/default/Android.mk
new file mode 100644
index 0000000..210da86
--- /dev/null
+++ b/tv/input/1.0/default/Android.mk
@@ -0,0 +1,46 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.tv.input@1.0-impl
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ TvInput.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ liblog \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ libutils \
+ android.hardware.audio.common@2.0 \
+ android.hardware.tv.input@1.0 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.tv.input@1.0-service
+LOCAL_INIT_RC := android.hardware.tv.input@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.audio.common@2.0 \
+ android.hardware.tv.input@1.0 \
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/tv/input/1.0/default/TvInput.cpp b/tv/input/1.0/default/TvInput.cpp
new file mode 100644
index 0000000..0bc6401
--- /dev/null
+++ b/tv/input/1.0/default/TvInput.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.tv.input@1.0-service"
+#include <android-base/logging.h>
+
+#include "TvInput.h"
+
+const native_handle_t kNullNativeHandle{sizeof(native_handle_t), 0, 0, {}};
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+namespace V1_0 {
+namespace implementation {
+
+static_assert(TV_INPUT_TYPE_OTHER_HARDWARE == static_cast<int>(TvInputType::OTHER),
+ "TvInputType::OTHER must match legacy value.");
+static_assert(TV_INPUT_TYPE_TUNER == static_cast<int>(TvInputType::TUNER),
+ "TvInputType::TUNER must match legacy value.");
+static_assert(TV_INPUT_TYPE_COMPOSITE == static_cast<int>(TvInputType::COMPOSITE),
+ "TvInputType::COMPOSITE must match legacy value.");
+static_assert(TV_INPUT_TYPE_SVIDEO == static_cast<int>(TvInputType::SVIDEO),
+ "TvInputType::SVIDEO must match legacy value.");
+static_assert(TV_INPUT_TYPE_SCART == static_cast<int>(TvInputType::SCART),
+ "TvInputType::SCART must match legacy value.");
+static_assert(TV_INPUT_TYPE_COMPONENT == static_cast<int>(TvInputType::COMPONENT),
+ "TvInputType::COMPONENT must match legacy value.");
+static_assert(TV_INPUT_TYPE_VGA == static_cast<int>(TvInputType::VGA),
+ "TvInputType::VGA must match legacy value.");
+static_assert(TV_INPUT_TYPE_DVI == static_cast<int>(TvInputType::DVI),
+ "TvInputType::DVI must match legacy value.");
+static_assert(TV_INPUT_TYPE_HDMI == static_cast<int>(TvInputType::HDMI),
+ "TvInputType::HDMI must match legacy value.");
+static_assert(TV_INPUT_TYPE_DISPLAY_PORT == static_cast<int>(TvInputType::DISPLAY_PORT),
+ "TvInputType::DISPLAY_PORT must match legacy value.");
+
+static_assert(TV_INPUT_EVENT_DEVICE_AVAILABLE == static_cast<int>(
+ TvInputEventType::DEVICE_AVAILABLE),
+ "TvInputEventType::DEVICE_AVAILABLE must match legacy value.");
+static_assert(TV_INPUT_EVENT_DEVICE_UNAVAILABLE == static_cast<int>(
+ TvInputEventType::DEVICE_UNAVAILABLE),
+ "TvInputEventType::DEVICE_UNAVAILABLE must match legacy value.");
+static_assert(TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED == static_cast<int>(
+ TvInputEventType::STREAM_CONFIGURATIONS_CHANGED),
+ "TvInputEventType::STREAM_CONFIGURATIONS_CHANGED must match legacy value.");
+
+sp<ITvInputCallback> TvInput::mCallback = nullptr;
+
+TvInput::TvInput(tv_input_device_t* device) : mDevice(device) {
+ mCallbackOps.notify = &TvInput::notify;
+}
+
+TvInput::~TvInput() {
+ if (mDevice != nullptr) {
+ free(mDevice);
+ }
+}
+
+// Methods from ::android::hardware::tv_input::V1_0::ITvInput follow.
+Return<void> TvInput::setCallback(const sp<ITvInputCallback>& callback) {
+ mCallback = callback;
+ if (mCallback != nullptr) {
+ mDevice->initialize(mDevice, &mCallbackOps, nullptr);
+ }
+ return Void();
+}
+
+Return<void> TvInput::getStreamConfigurations(int32_t deviceId, getStreamConfigurations_cb cb) {
+ int32_t configCount = 0;
+ const tv_stream_config_t* configs = nullptr;
+ int ret = mDevice->get_stream_configurations(mDevice, deviceId, &configCount, &configs);
+ Result res = Result::UNKNOWN;
+ hidl_vec<TvStreamConfig> tvStreamConfigs;
+ if (ret == 0) {
+ res = Result::OK;
+ tvStreamConfigs.resize(getSupportedConfigCount(configCount, configs));
+ int32_t pos = 0;
+ for (int32_t i = 0; i < configCount; ++i) {
+ if (isSupportedStreamType(configs[i].type)) {
+ tvStreamConfigs[pos].streamId = configs[i].stream_id;
+ tvStreamConfigs[pos].maxVideoWidth = configs[i].max_video_width;
+ tvStreamConfigs[pos].maxVideoHeight = configs[i].max_video_height;
+ ++pos;
+ }
+ }
+ } else if (ret == -EINVAL) {
+ res = Result::INVALID_ARGUMENTS;
+ }
+ cb(res, tvStreamConfigs);
+ return Void();
+}
+
+Return<void> TvInput::openStream(int32_t deviceId, int32_t streamId, openStream_cb cb) {
+ tv_stream_t stream;
+ stream.stream_id = streamId;
+ int ret = mDevice->open_stream(mDevice, deviceId, &stream);
+ Result res = Result::UNKNOWN;
+ native_handle_t* sidebandStream = nullptr;
+ if (ret == 0) {
+ if (isSupportedStreamType(stream.type)) {
+ res = Result::OK;
+ sidebandStream = stream.sideband_stream_source_handle;
+ }
+ } else {
+ // TODO(b/30814137)
+ sidebandStream = const_cast<native_handle_t*>(&kNullNativeHandle);
+ if (ret == -EBUSY) {
+ res = Result::NO_RESOURCE;
+ } else if (ret == -EEXIST) {
+ res = Result::INVALID_STATE;
+ } else if (ret == -EINVAL) {
+ res = Result::INVALID_ARGUMENTS;
+ }
+ }
+ cb(res, sidebandStream);
+ return Void();
+}
+
+Return<Result> TvInput::closeStream(int32_t deviceId, int32_t streamId) {
+ int ret = mDevice->close_stream(mDevice, deviceId, streamId);
+ Result res = Result::UNKNOWN;
+ if (ret == 0) {
+ res = Result::OK;
+ } else if (ret == -ENOENT) {
+ res = Result::INVALID_STATE;
+ } else if (ret == -EINVAL) {
+ res = Result::INVALID_ARGUMENTS;
+ }
+ return res;
+}
+
+// static
+void TvInput::notify(struct tv_input_device* __unused, tv_input_event_t* event,
+ void* __unused) {
+ if (mCallback != nullptr && event != nullptr) {
+ // Capturing is no longer supported.
+ if (event->type >= TV_INPUT_EVENT_CAPTURE_SUCCEEDED) {
+ return;
+ }
+ TvInputEvent tvInputEvent;
+ tvInputEvent.type = static_cast<TvInputEventType>(event->type);
+ tvInputEvent.deviceInfo.deviceId = event->device_info.device_id;
+ tvInputEvent.deviceInfo.type = static_cast<TvInputType>(
+ event->device_info.type);
+ tvInputEvent.deviceInfo.portId = event->device_info.hdmi.port_id;
+ tvInputEvent.deviceInfo.cableConnectionStatus = CableConnectionStatus::UNKNOWN;
+ // TODO: Ensure the legacy audio type code is the same once audio HAL default
+ // implementation is ready.
+ tvInputEvent.deviceInfo.audioType = static_cast<AudioDevice>(
+ event->device_info.audio_type);
+ memset(tvInputEvent.deviceInfo.audioAddress.data(), 0,
+ tvInputEvent.deviceInfo.audioAddress.size());
+ const char* address = event->device_info.audio_address;
+ if (address != nullptr) {
+ size_t size = strlen(address);
+ if (size > tvInputEvent.deviceInfo.audioAddress.size()) {
+ LOG(ERROR) << "Audio address is too long. Address:" << address << "";
+ return;
+ }
+ for (size_t i = 0; i < size; ++i) {
+ tvInputEvent.deviceInfo.audioAddress[i] =
+ static_cast<uint8_t>(event->device_info.audio_address[i]);
+ }
+ }
+ mCallback->notify(tvInputEvent);
+ }
+}
+
+// static
+uint32_t TvInput::getSupportedConfigCount(uint32_t configCount,
+ const tv_stream_config_t* configs) {
+ uint32_t supportedConfigCount = 0;
+ for (uint32_t i = 0; i < configCount; ++i) {
+ if (isSupportedStreamType(configs[i].type)) {
+ supportedConfigCount++;
+ }
+ }
+ return supportedConfigCount;
+}
+
+// static
+bool TvInput::isSupportedStreamType(int type) {
+ // Buffer producer type is no longer supported.
+ return type != TV_STREAM_TYPE_BUFFER_PRODUCER;
+}
+
+ITvInput* HIDL_FETCH_ITvInput(const char* /* name */) {
+ int ret = 0;
+ const hw_module_t* hw_module = nullptr;
+ tv_input_device_t* input_device;
+ ret = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID, &hw_module);
+ if (ret == 0 && hw_module->methods->open != nullptr) {
+ ret = hw_module->methods->open(hw_module, TV_INPUT_DEFAULT_DEVICE,
+ reinterpret_cast<hw_device_t**>(&input_device));
+ if (ret == 0) {
+ return new TvInput(input_device);
+ }
+ else {
+ LOG(ERROR) << "Passthrough failed to load legacy HAL.";
+ return nullptr;
+ }
+ }
+ else {
+ LOG(ERROR) << "hw_get_module " << TV_INPUT_HARDWARE_MODULE_ID
+ << " failed: " << ret;
+ return nullptr;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/input/1.0/default/TvInput.h b/tv/input/1.0/default/TvInput.h
new file mode 100644
index 0000000..beb69f5
--- /dev/null
+++ b/tv/input/1.0/default/TvInput.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H
+#define ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H
+
+#include <android/hardware/tv/input/1.0/ITvInput.h>
+#include <hidl/Status.h>
+#include <hardware/tv_input.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::tv::input::V1_0::ITvInput;
+using ::android::hardware::tv::input::V1_0::ITvInputCallback;
+using ::android::hardware::tv::input::V1_0::Result;
+using ::android::hardware::tv::input::V1_0::TvInputEvent;
+using ::android::hardware::tv::input::V1_0::TvStreamConfig;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct TvInput : public ITvInput {
+ TvInput(tv_input_device_t* device);
+ ~TvInput();
+ Return<void> setCallback(const sp<ITvInputCallback>& callback) override;
+ Return<void> getStreamConfigurations(int32_t deviceId,
+ getStreamConfigurations_cb _hidl_cb) override;
+ Return<void> openStream(int32_t deviceId, int32_t streamId,
+ openStream_cb _hidl_cb) override;
+ Return<Result> closeStream(int32_t deviceId, int32_t streamId) override;
+
+ static void notify(struct tv_input_device* __unused, tv_input_event_t* event,
+ void* __unused);
+ static uint32_t getSupportedConfigCount(uint32_t configCount,
+ const tv_stream_config_t* configs);
+ static bool isSupportedStreamType(int type);
+
+ private:
+ static sp<ITvInputCallback> mCallback;
+ tv_input_callback_ops_t mCallbackOps;
+ tv_input_device_t* mDevice;
+};
+
+extern "C" ITvInput* HIDL_FETCH_ITvInput(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H
diff --git a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
new file mode 100644
index 0000000..9edeba6
--- /dev/null
+++ b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
@@ -0,0 +1,4 @@
+service tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service
+ class hal
+ user system
+ group system readproc
diff --git a/tv/input/1.0/default/service.cpp b/tv/input/1.0/default/service.cpp
new file mode 100644
index 0000000..d904d0b
--- /dev/null
+++ b/tv/input/1.0/default/service.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "android.hardware.tv_input@1.0-service"
+
+#include <android/hardware/tv/input/1.0/ITvInput.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::sp;
+
+// Generated HIDL files
+using android::hardware::tv::input::V1_0::ITvInput;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<ITvInput>();
+}
diff --git a/tv/input/1.0/types.hal b/tv/input/1.0/types.hal
new file mode 100644
index 0000000..55eb6ad
--- /dev/null
+++ b/tv/input/1.0/types.hal
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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.tv.input@1.0;
+
+import android.hardware.audio.common@2.0;
+
+enum Result : int32_t {
+ OK,
+ UNKNOWN,
+ NO_RESOURCE,
+ INVALID_ARGUMENTS,
+ INVALID_STATE,
+};
+
+/* Type of physical TV input. */
+enum TvInputType : int32_t {
+ OTHER = 1, // Generic hardware.
+ TUNER = 2, // Tuner. e.g. built-in terrestrial tuner
+ COMPOSITE = 3,
+ SVIDEO = 4,
+ SCART = 5,
+ COMPONENT = 6,
+ VGA = 7,
+ DVI = 8,
+ HDMI = 9, // Physical HDMI port. e.g. HDMI 1
+ DISPLAY_PORT = 10,
+};
+
+/*
+ * Status of cable connection.
+ * This status is for devices having availability to detect the cable in a mechanical way,
+ * regardless of whether the connected external device is electrically on or not.
+ * If the device does not have such capability, you must use UNKNOWN.
+ */
+enum CableConnectionStatus : int32_t {
+ UNKNOWN = 0,
+ CONNECTED = 1,
+ DISCONNECTED = 2,
+};
+
+struct TvInputDeviceInfo {
+ int32_t deviceId;
+ TvInputType type;
+ uint32_t portId; // HDMI port ID number. e.g. 2 for HDMI 2
+ CableConnectionStatus cableConnectionStatus; // Cable connection status.
+ AudioDevice audioType; // Audio device type. e.g AudioDevice::IN_HDMI
+ uint8_t[32] audioAddress; // Audio device address. "" if N/A. If the text
+ // length is less than 32, the remaining part
+ // must be filled with 0s.
+};
+
+enum TvInputEventType : int32_t {
+ /*
+ * Hardware notifies the framework that a device is available.
+ *
+ * Note that DEVICE_AVAILABLE and DEVICE_UNAVAILABLE events do not represent
+ * hotplug events (i.e. plugging cable into or out of the physical port).
+ * These events notify the framework whether the port is available or not.
+ * For a concrete example, when a user plugs in or pulls out the HDMI cable
+ * from a HDMI port, it does not generate DEVICE_AVAILABLE and/or
+ * DEVICE_UNAVAILABLE events. However, if a user inserts a pluggable USB
+ * tuner into the Android device, it must generate a DEVICE_AVAILABLE event
+ * and when the port is removed, it must generate a DEVICE_UNAVAILABLE
+ * event.
+ *
+ * For hotplug events, please see STREAM_CONFIGURATION_CHANGED for more
+ * details.
+ *
+ * HAL implementation must register devices by using this event when the
+ * device boots up. The framework must recognize device reported via this
+ * event only.
+ */
+ DEVICE_AVAILABLE = 1,
+
+ /*
+ * Hardware notifies the framework that a device is unavailable.
+ *
+ * HAL implementation must generate this event when a device registered
+ * by DEVICE_AVAILABLE is no longer available. For example,
+ * the event can indicate that a USB tuner is plugged out from the Android
+ * device.
+ *
+ * Note that this event is not for indicating cable plugged out of the port;
+ * for that purpose, the implementation must use
+ * STREAM_CONFIGURATION_CHANGED event. This event represents the port itself
+ * being no longer available.
+ */
+ DEVICE_UNAVAILABLE = 2,
+
+ /*
+ * Stream configurations are changed. Client must regard all open streams
+ * at the specific device are closed, and must call
+ * getStreamConfigurations() again, opening some of them if necessary.
+ *
+ * HAL implementation must generate this event when the available stream
+ * configurations change for any reason. A typical use case of this event
+ * is to notify the framework that the input signal has changed resolution,
+ * or that the cable is plugged out so that the number of available streams
+ * is 0.
+ *
+ * The implementation must use this event to indicate hotplug status of the
+ * port. the framework regards input devices with no available streams as
+ * disconnected, so the implementation can generate this event with no
+ * available streams to indicate that this device is disconnected, and vice
+ * versa.
+ */
+ STREAM_CONFIGURATIONS_CHANGED = 3,
+};
+
+struct TvInputEvent {
+ TvInputEventType type;
+ /*
+ * DEVICE_AVAILABLE: all fields are relevant.
+ * DEVICE_UNAVAILABLE: only deviceId is relevant.
+ * STREAM_CONFIGURATIONS_CHANGED: only deviceId is relevant.
+ */
+ TvInputDeviceInfo deviceInfo;
+};
+
+struct TvStreamConfig {
+ int32_t streamId;
+ uint32_t maxVideoWidth; // Max width of the stream.
+ uint32_t maxVideoHeight; // Max height of the stream.
+};
diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..c862429
--- /dev/null
+++ b/tv/input/1.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalTvInputV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalTvInputV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.tv.input@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
+
diff --git a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
new file mode 100644
index 0000000..0d5110e
--- /dev/null
+++ b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "tv_input_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/tv/input/1.0/types.h>
+#include <android/hardware/tv/input/1.0/ITvInput.h>
+#include <android/hardware/tv/input/1.0/ITvInputCallback.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <utils/KeyedVector.h>
+#include <mutex>
+#include <vector>
+
+using ::android::hardware::tv::input::V1_0::ITvInput;
+using ::android::hardware::tv::input::V1_0::ITvInputCallback;
+using ::android::hardware::tv::input::V1_0::Result;
+using ::android::hardware::tv::input::V1_0::TvInputType;
+using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
+using ::android::hardware::tv::input::V1_0::TvInputEventType;
+using ::android::hardware::tv::input::V1_0::TvInputEvent;
+using ::android::hardware::tv::input::V1_0::TvStreamConfig;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+#define WAIT_FOR_EVENT_TIMEOUT 5
+#define DEFAULT_ID INT32_MIN
+
+/* The main test class for TV Input HIDL HAL. */
+class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>();
+ ASSERT_NE(tv_input_, nullptr);
+ tv_input_callback_ = new TvInputCallback(*this);
+ ASSERT_NE(tv_input_callback_, nullptr);
+ tv_input_->setCallback(tv_input_callback_);
+ // All events received within the timeout should be handled.
+ sleep(WAIT_FOR_EVENT_TIMEOUT);
+ }
+
+ virtual void TearDown() override {}
+
+ /* Called when a DEVICE_AVAILABLE event is received. */
+ void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
+ device_info_.add(deviceInfo.deviceId, deviceInfo);
+ }
+
+ /* Called when a DEVICE_UNAVAILABLE event is received. */
+ void onDeviceUnavailable(int32_t deviceId) {
+ device_info_.removeItem(deviceId);
+ }
+
+ /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
+ Result onStreamConfigurationsChanged(int32_t deviceId) {
+ return updateStreamConfigurations(deviceId);
+ }
+
+ /* Gets and updates the stream configurations for a device. */
+ Result updateStreamConfigurations(int32_t deviceId) {
+ stream_config_.removeItem(deviceId);
+ Result result = Result::UNKNOWN;
+ hidl_vec<TvStreamConfig> list;
+ tv_input_->getStreamConfigurations(deviceId,
+ [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
+ result = res;
+ if (res == Result::OK) {
+ list = configs;
+ }
+ });
+ if (result == Result::OK) {
+ stream_config_.add(deviceId, list);
+ }
+ return result;
+ }
+
+ /* Gets and updates the stream configurations for all existing devices. */
+ void updateAllStreamConfigurations() {
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ int32_t device_id = device_info_.keyAt(i);
+ updateStreamConfigurations(device_id);
+ }
+ }
+
+ /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
+ std::vector<size_t> getConfigIndices() {
+ std::vector<size_t> indices;
+ for (size_t i = 0; i < stream_config_.size(); i++) {
+ if (stream_config_.valueAt(i).size() != 0) {
+ indices.push_back(i);
+ }
+ }
+ return indices;
+ }
+
+ /*
+ * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
+ * Otherwise, returns the smallest missing non-negative integer.
+ */
+ int32_t getNumNotIn(std::vector<int32_t>& nums) {
+ int32_t result = DEFAULT_ID;
+ int32_t size = static_cast<int32_t>(nums.size());
+ for (int32_t i = 0; i < size; i++) {
+ // Put every element to its target position, if possible.
+ int32_t target_pos = nums[i];
+ while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) {
+ std::swap(nums[i], nums[target_pos]);
+ target_pos = nums[i];
+ }
+ }
+
+ for (int32_t i = 0; i < size; i++) {
+ if (nums[i] != i) {
+ return i;
+ }
+ }
+ return result;
+ }
+
+ /* A simple test implementation of TvInputCallback for TV Input Events. */
+ class TvInputCallback : public ITvInputCallback {
+ public:
+ TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
+
+ virtual ~TvInputCallback() = default;
+
+ /*
+ * Notifies the client that an event has occured. For possible event types,
+ * check TvInputEventType.
+ */
+ Return<void> notify(const TvInputEvent& event) override {
+ std::unique_lock<std::mutex> lock(parent_.mutex_);
+ switch(event.type) {
+ case TvInputEventType::DEVICE_AVAILABLE:
+ parent_.onDeviceAvailable(event.deviceInfo);
+ break;
+ case TvInputEventType::DEVICE_UNAVAILABLE:
+ parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
+ break;
+ case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
+ parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
+ break;
+ }
+ return Void();
+ };
+ private:
+ /* The test contains this callback instance. */
+ TvInputHidlTest& parent_;
+ };
+
+ /* The TvInput used for the test. */
+ sp<ITvInput> tv_input_;
+
+ /* The TvInputCallback used for the test. */
+ sp<ITvInputCallback> tv_input_callback_;
+
+ /*
+ * A KeyedVector stores device information of every available device.
+ * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
+ */
+ android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
+
+ /*
+ * A KeyedVector stores a list of stream configurations of every available device.
+ * A key is a device ID and the corresponding value is the stream configuration list.
+ */
+ android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
+
+ /* The mutex controls the access of shared data. */
+ std::mutex mutex_;
+};
+
+
+/* A class for test environment setup. */
+class TvInputHidlEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ private:
+};
+
+/*
+ * GetStreamConfigTest:
+ * Calls updateStreamConfigurations() for each existing device
+ * Checks returned results
+ */
+TEST_F(TvInputHidlTest, GetStreamConfigTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ int32_t device_id = device_info_.keyAt(i);
+ Result result = updateStreamConfigurations(device_id);
+ EXPECT_EQ(Result::OK, result);
+ }
+}
+
+/*
+ * OpenAndCloseStreamTest:
+ * Calls openStream() and then closeStream() for each existing stream
+ * Checks returned results
+ */
+TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ updateAllStreamConfigurations();
+ for (size_t j = 0; j < stream_config_.size(); j++) {
+ int32_t device_id = stream_config_.keyAt(j);
+ hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
+ for (size_t i = 0; i < config.size(); i++) {
+ Result result = Result::UNKNOWN;
+ int32_t stream_id = config[i].streamId;
+ tv_input_->openStream(device_id, stream_id,
+ [&result](Result res, const native_handle_t*) {
+ result = res;
+ });
+ EXPECT_EQ(Result::OK, result);
+
+ result = Result::UNKNOWN;
+ result = tv_input_->closeStream(device_id, stream_id);
+ EXPECT_EQ(Result::OK, result);
+ }
+ }
+}
+
+/*
+ * InvalidDeviceIdTest:
+ * Calls updateStreamConfigurations(), openStream(), and closeStream()
+ * for a non-existing device
+ * Checks returned results
+ * The results should be Result::INVALID_ARGUMENTS
+ */
+TEST_F(TvInputHidlTest, InvalidDeviceIdTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ std::vector<int32_t> device_ids;
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ device_ids.push_back(device_info_.keyAt(i));
+ }
+ // Get a non-existing device ID.
+ int32_t id = getNumNotIn(device_ids);
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
+
+ Result result = Result::UNKNOWN;
+ int32_t stream_id = 0;
+ tv_input_->openStream(id, stream_id,
+ [&result](Result res, const native_handle_t*) {
+ result = res;
+ });
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+
+ result = Result::UNKNOWN;
+ result = tv_input_->closeStream(id, stream_id);
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+/*
+ * InvalidStreamIdTest:
+ * Calls openStream(), and closeStream() for a non-existing stream
+ * Checks returned results
+ * The results should be Result::INVALID_ARGUMENTS
+ */
+TEST_F(TvInputHidlTest, InvalidStreamIdTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (device_info_.isEmpty()) {
+ return;
+ }
+ updateAllStreamConfigurations();
+
+ int32_t device_id = device_info_.keyAt(0);
+ // Get a non-existing stream ID.
+ int32_t id = DEFAULT_ID;
+ if (stream_config_.indexOfKey(device_id) >= 0) {
+ std::vector<int32_t> stream_ids;
+ hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
+ for (size_t i = 0; i < config.size(); i++) {
+ stream_ids.push_back(config[i].streamId);
+ }
+ id = getNumNotIn(stream_ids);
+ }
+
+ Result result = Result::UNKNOWN;
+ tv_input_->openStream(device_id, id,
+ [&result](Result res, const native_handle_t*) {
+ result = res;
+ });
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+
+ result = Result::UNKNOWN;
+ result = tv_input_->closeStream(device_id, id);
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+/*
+ * OpenAnOpenedStreamsTest:
+ * Calls openStream() twice for a stream (if any)
+ * Checks returned results
+ * The result of the second call should be Result::INVALID_STATE
+ */
+TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ updateAllStreamConfigurations();
+ std::vector<size_t> indices = getConfigIndices();
+ if (indices.empty()) {
+ return;
+ }
+ int32_t device_id = stream_config_.keyAt(indices[0]);
+ int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+
+ Result result = Result::UNKNOWN;
+ tv_input_->openStream(device_id, stream_id,
+ [&result](Result res, const native_handle_t*) {
+ result = res;
+ });
+ EXPECT_EQ(Result::OK, result);
+
+ tv_input_->openStream(device_id, stream_id,
+ [&result](Result res, const native_handle_t*) {
+ result = res;
+ });
+ EXPECT_EQ(Result::INVALID_STATE, result);
+}
+
+/*
+ * CloseStreamBeforeOpenTest:
+ * Calls closeStream() without calling openStream() for a stream (if any)
+ * Checks the returned result
+ * The result should be Result::INVALID_STATE
+ */
+TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ updateAllStreamConfigurations();
+ std::vector<size_t> indices = getConfigIndices();
+ if (indices.empty()) {
+ return;
+ }
+ int32_t device_id = stream_config_.keyAt(indices[0]);
+ int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+ EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(new TvInputHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
+
diff --git a/tv/input/Android.mk b/tv/input/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/tv/input/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/update-base-files.sh b/update-base-files.sh
new file mode 100755
index 0000000..1eb6b51
--- /dev/null
+++ b/update-base-files.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+if [ ! -d hardware/interfaces ] ; then
+ echo "Where is hardware/interfaces?";
+ exit 1;
+fi
+
+if [ ! -d system/libhidl/transport ] ; then
+ echo "Where is system/libhidl/transport?";
+ exit 1;
+fi
+
+echo "WARNING: This script changes files in many places."
+
+# These files only exist to facilitate the easy transition to hidl.
+
+options="-Lexport-header \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport"
+
+# hardware/libhardware
+hidl-gen $options \
+ -o hardware/libhardware/include/hardware/sensors-base.h \
+ android.hardware.sensors@1.0
+hidl-gen $options \
+ -o hardware/libhardware/include/hardware/nfc-base.h \
+ android.hardware.nfc@1.0
+hidl-gen $options \
+ -o hardware/libhardware/include/hardware/gnss-base.h \
+ android.hardware.gnss@1.0
+
+# system/core
+hidl-gen $options \
+ -o system/core/include/system/graphics-base.h \
+ android.hardware.graphics.common@1.0
+
+# system/media
+hidl-gen $options \
+ -o system/media/audio/include/system/audio-base.h \
+ android.hardware.audio.common@2.0
+hidl-gen $options \
+ -o system/media/audio/include/system/audio_effect-base.h \
+ android.hardware.audio.effect@2.0
diff --git a/usb/1.0/Android.bp b/usb/1.0/Android.bp
new file mode 100644
index 0000000..0b641f1
--- /dev/null
+++ b/usb/1.0/Android.bp
@@ -0,0 +1,69 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.usb@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IUsb.hal",
+ "IUsbCallback.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.usb@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.usb@1.0",
+ srcs: [
+ ":android.hardware.usb@1.0_hal",
+ ],
+ out: [
+ "android/hardware/usb/1.0/types.cpp",
+ "android/hardware/usb/1.0/UsbAll.cpp",
+ "android/hardware/usb/1.0/UsbCallbackAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.usb@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.usb@1.0",
+ srcs: [
+ ":android.hardware.usb@1.0_hal",
+ ],
+ out: [
+ "android/hardware/usb/1.0/types.h",
+ "android/hardware/usb/1.0/IUsb.h",
+ "android/hardware/usb/1.0/IHwUsb.h",
+ "android/hardware/usb/1.0/BnHwUsb.h",
+ "android/hardware/usb/1.0/BpHwUsb.h",
+ "android/hardware/usb/1.0/BsUsb.h",
+ "android/hardware/usb/1.0/IUsbCallback.h",
+ "android/hardware/usb/1.0/IHwUsbCallback.h",
+ "android/hardware/usb/1.0/BnHwUsbCallback.h",
+ "android/hardware/usb/1.0/BpHwUsbCallback.h",
+ "android/hardware/usb/1.0/BsUsbCallback.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.usb@1.0",
+ generated_sources: ["android.hardware.usb@1.0_genc++"],
+ generated_headers: ["android.hardware.usb@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.usb@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/usb/1.0/Android.mk b/usb/1.0/Android.mk
new file mode 100644
index 0000000..7be7147
--- /dev/null
+++ b/usb/1.0/Android.mk
@@ -0,0 +1,427 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.usb@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (PortDataRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortDataRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortDataRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortMode)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortPowerRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortPowerRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortPowerRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortRoleType)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortRoleType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortRoleType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortStatus)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IUsb.hal
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/IUsb.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsb.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::IUsb
+
+$(GEN): $(LOCAL_PATH)/IUsb.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IUsbCallback.hal
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/IUsbCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::IUsbCallback
+
+$(GEN): $(LOCAL_PATH)/IUsbCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.usb@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (PortDataRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortDataRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortDataRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortMode)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortMode.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortMode
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortPowerRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortPowerRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortPowerRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortRole)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortRole.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortRole
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortRoleType)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortRoleType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortRoleType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (PortStatus)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/PortStatus.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.PortStatus
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IUsb.hal
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/IUsb.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsb.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::IUsb
+
+$(GEN): $(LOCAL_PATH)/IUsb.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IUsbCallback.hal
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/IUsbCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsbCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0::IUsbCallback
+
+$(GEN): $(LOCAL_PATH)/IUsbCallback.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.usb@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/usb/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IUsb.hal
+$(GEN): $(LOCAL_PATH)/IUsbCallback.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.usb@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/usb/1.0/IUsb.hal b/usb/1.0/IUsb.hal
new file mode 100644
index 0000000..965326a
--- /dev/null
+++ b/usb/1.0/IUsb.hal
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.usb@1.0;
+
+import IUsbCallback;
+
+interface IUsb {
+ /*
+ * This function is used to change the port role of a specific port.
+ * For example, when PD_SWAP or PR_SWAP is supported.
+ * This is function is asynchronous. The status of the role switch
+ * will be informed through IUsbCallback object's notifyPortStatusChange
+ * method.
+ *
+ * @param portName name of the port for which the role has to be changed
+ * @param role the new port role.
+ */
+ oneway switchRole(string portName, PortRole role);
+
+ /*
+ * This function is used to register a callback function which is
+ * called by the HAL whenever there is a change in the port state.
+ * i.e. DATA_ROLE, POWER_ROLE or MODE.
+ *
+ * Also the same callback object would be called to inform the caller
+ * of the roleSwitch status.
+ *
+ * @param callback IUsbCallback object used to convey status to the
+ * userspace.
+ */
+ oneway setCallback(IUsbCallback callback);
+
+ /*
+ * This functions is used to request the hal for the current status
+ * status of the Type-C ports. This method is async/oneway. The result of the
+ * query would be sent through the IUsbCallback object's notifyRoleSwitchStatus
+ * to the caller. This api would would let the caller know of the number
+ * of type-c ports that are present and their connection status through the
+ * PortStatus type.
+ */
+ oneway queryPortStatus();
+};
+
diff --git a/usb/1.0/IUsbCallback.hal b/usb/1.0/IUsbCallback.hal
new file mode 100644
index 0000000..b665ba3
--- /dev/null
+++ b/usb/1.0/IUsbCallback.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.usb@1.0;
+
+/*
+ * Callback object used for all the IUsb async methods which expects a result.
+ * Caller is expected to register the callback object using setCallback method
+ * to receive updates on the PortStatus.
+ */
+interface IUsbCallback {
+ /*
+ * Used to convey the current port status to the caller.
+ * Called either when PortState changes due to the port partner (or)
+ * when caller requested for the PortStatus update through queryPortStatus.
+ *
+ * @param currentPortStatus vector object of current status of all the
+ * typeC ports in the device.
+ * @param retval SUCCESS when query was done successfully.
+ * ERROR otherwise.
+ */
+ oneway notifyPortStatusChange(vec<PortStatus> currentPortStatus, Status retval);
+
+ /*
+ * Used to notify the result of the switchRole call to the caller.
+ *
+ * @param portName name of the port for which the roleswap is requested.
+ * @param newRole the new role requested by the caller.
+ * @param retval SUCCESS if the role switch succeeded. FAILURE otherwise.
+ */
+ oneway notifyRoleSwitchStatus(string portName, PortRole newRole, Status retval);
+};
diff --git a/usb/1.0/default/Android.mk b/usb/1.0/default/Android.mk
new file mode 100644
index 0000000..afd53cf
--- /dev/null
+++ b/usb/1.0/default/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE := android.hardware.usb@1.0-service
+LOCAL_INIT_RC := android.hardware.usb@1.0-service.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+ Usb.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ libhardware \
+ android.hardware.usb@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/usb/1.0/default/Usb.cpp b/usb/1.0/default/Usb.cpp
new file mode 100644
index 0000000..6eb8842
--- /dev/null
+++ b/usb/1.0/default/Usb.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#include <assert.h>
+#include <dirent.h>
+#include <iostream>
+#include <fstream>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "Usb.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace V1_0 {
+namespace implementation {
+
+// Set by the signal handler to destroy the thread
+volatile bool destroyThread;
+
+int32_t readFile(std::string filename, std::string& contents) {
+ std::ifstream file(filename);
+
+ if (file.is_open()) {
+ getline(file, contents);
+ file.close();
+ return 0;
+ }
+ return -1;
+}
+
+std::string appendRoleNodeHelper(const std::string portName, PortRoleType type) {
+ std::string node("/sys/class/dual_role_usb/" + portName);
+
+ switch(type) {
+ case PortRoleType::DATA_ROLE:
+ return node + "/data_role";
+ case PortRoleType::POWER_ROLE:
+ return node + "/power_role";
+ default:
+ return node + "/mode";
+ }
+}
+
+std::string convertRoletoString(PortRole role) {
+ if (role.type == PortRoleType::POWER_ROLE) {
+ if (role.role == static_cast<uint32_t> (PortPowerRole::SOURCE))
+ return "source";
+ else if (role.role == static_cast<uint32_t> (PortPowerRole::SINK))
+ return "sink";
+ } else if (role.type == PortRoleType::DATA_ROLE) {
+ if (role.role == static_cast<uint32_t> (PortDataRole::HOST))
+ return "host";
+ if (role.role == static_cast<uint32_t> (PortDataRole::DEVICE))
+ return "device";
+ } else if (role.type == PortRoleType::MODE) {
+ if (role.role == static_cast<uint32_t> (PortMode::UFP))
+ return "ufp";
+ if (role.role == static_cast<uint32_t> (PortMode::DFP))
+ return "dfp";
+ }
+ return "none";
+}
+
+Return<void> Usb::switchRole(const hidl_string& portName,
+ const PortRole& newRole) {
+ std::string filename = appendRoleNodeHelper(std::string(portName.c_str()),
+ newRole.type);
+ std::ofstream file(filename);
+ std::string written;
+
+ ALOGI("filename write: %s role:%d", filename.c_str(), newRole.role);
+
+ if (file.is_open()) {
+ file << convertRoletoString(newRole).c_str();
+ file.close();
+ if (!readFile(filename, written)) {
+ ALOGI("written: %s", written.c_str());
+ if (written == convertRoletoString(newRole)) {
+ ALOGI("Role switch successfull");
+ Return<void> ret =
+ mCallback->notifyRoleSwitchStatus(portName, newRole,
+ Status::SUCCESS);
+ if (!ret.isOk())
+ ALOGE("RoleSwitchStatus error %s",
+ ret.description().c_str());
+ }
+ }
+ }
+
+ Return<void> ret = mCallback->notifyRoleSwitchStatus(portName, newRole, Status::ERROR);
+ if (!ret.isOk())
+ ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
+
+ return Void();
+}
+
+Status getCurrentRoleHelper(std::string portName,
+ PortRoleType type, uint32_t ¤tRole) {
+ std::string filename;
+ std::string roleName;
+
+ if (type == PortRoleType::POWER_ROLE) {
+ filename = "/sys/class/dual_role_usb/" +
+ portName + "/power_role";
+ currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
+ } else if (type == PortRoleType::DATA_ROLE) {
+ filename = "/sys/class/dual_role_usb/" +
+ portName + "/data_role";
+ currentRole = static_cast<uint32_t> (PortDataRole::NONE);
+ } else if (type == PortRoleType::MODE) {
+ filename = "/sys/class/dual_role_usb/" +
+ portName + "/mode";
+ currentRole = static_cast<uint32_t> (PortMode::NONE);
+ }
+
+ if (readFile(filename, roleName)) {
+ ALOGE("getCurrentRole: Failed to open filesystem node");
+ return Status::ERROR;
+ }
+
+ if (roleName == "dfp")
+ currentRole = static_cast<uint32_t> (PortMode::DFP);
+ else if (roleName == "ufp")
+ currentRole = static_cast<uint32_t> (PortMode::UFP);
+ else if (roleName == "source")
+ currentRole = static_cast<uint32_t> (PortPowerRole::SOURCE);
+ else if (roleName == "sink")
+ currentRole = static_cast<uint32_t> (PortPowerRole::SINK);
+ else if (roleName == "host")
+ currentRole = static_cast<uint32_t> (PortDataRole::HOST);
+ else if (roleName == "device")
+ currentRole = static_cast<uint32_t> (PortDataRole::DEVICE);
+ else if (roleName != "none") {
+ /* case for none has already been addressed.
+ * so we check if the role isnt none.
+ */
+ return Status::UNRECOGNIZED_ROLE;
+ }
+ return Status::SUCCESS;
+}
+
+Status getTypeCPortNamesHelper(std::vector<std::string>& names) {
+ DIR *dp;
+
+ dp = opendir("/sys/class/dual_role_usb");
+ if (dp != NULL)
+ {
+rescan:
+ int32_t ports = 0;
+ int32_t current = 0;
+ struct dirent *ep;
+
+ while ((ep = readdir (dp))) {
+ if (ep->d_type == DT_LNK) {
+ ports++;
+ }
+ }
+
+ if (ports == 0) {
+ closedir(dp);
+ return Status::SUCCESS;
+ }
+
+ names.resize(ports);
+ rewinddir(dp);
+
+ while ((ep = readdir (dp))) {
+ if (ep->d_type == DT_LNK) {
+ /* Check to see if new ports were added since the first pass. */
+ if (current >= ports) {
+ rewinddir(dp);
+ goto rescan;
+ }
+ names[current++] = ep->d_name;
+ }
+ }
+
+ closedir (dp);
+ return Status::SUCCESS;
+ }
+
+ ALOGE("Failed to open /sys/class/dual_role_usb");
+ return Status::ERROR;
+}
+
+bool canSwitchRoleHelper(const std::string portName, PortRoleType type) {
+ std::string filename = appendRoleNodeHelper(portName, type);
+ std::ofstream file(filename);
+
+ if (file.is_open()) {
+ file.close();
+ return true;
+ }
+ return false;
+}
+
+Status getPortModeHelper(const std::string portName, PortMode& portMode) {
+ std::string filename = "/sys/class/dual_role_usb/" +
+ std::string(portName.c_str()) + "/supported_modes";
+ std::string modes;
+
+ if (readFile(filename, modes)) {
+ ALOGE("getSupportedRoles: Failed to open filesystem node");
+ return Status::ERROR;
+ }
+
+ if (modes == "ufp dfp")
+ portMode = PortMode::DRP;
+ else if (modes == "ufp")
+ portMode = PortMode::UFP;
+ else if (modes == "dfp")
+ portMode = PortMode::DFP;
+ else
+ return Status::UNRECOGNIZED_ROLE;
+
+ return Status::SUCCESS;
+}
+
+Status getPortStatusHelper (hidl_vec<PortStatus>& currentPortStatus) {
+ std::vector<std::string> names;
+ Status result = getTypeCPortNamesHelper(names);
+
+ if (result == Status::SUCCESS) {
+ currentPortStatus.resize(names.size());
+ for(std::vector<std::string>::size_type i = 0; i < names.size(); i++) {
+ ALOGI("%s", names[i].c_str());
+ currentPortStatus[i].portName = names[i];
+
+ uint32_t currentRole;
+ if (getCurrentRoleHelper(names[i], PortRoleType::POWER_ROLE,
+ currentRole) == Status::SUCCESS) {
+ currentPortStatus[i].currentPowerRole =
+ static_cast<PortPowerRole> (currentRole);
+ } else {
+ ALOGE("Error while retreiving portNames");
+ goto done;
+ }
+
+ if (getCurrentRoleHelper(names[i],
+ PortRoleType::DATA_ROLE, currentRole) == Status::SUCCESS) {
+ currentPortStatus[i].currentDataRole =
+ static_cast<PortDataRole> (currentRole);
+ } else {
+ ALOGE("Error while retreiving current port role");
+ goto done;
+ }
+
+ if (getCurrentRoleHelper(names[i], PortRoleType::MODE,
+ currentRole) == Status::SUCCESS) {
+ currentPortStatus[i].currentMode =
+ static_cast<PortMode> (currentRole);
+ } else {
+ ALOGE("Error while retreiving current data role");
+ goto done;
+ }
+
+ currentPortStatus[i].canChangeMode =
+ canSwitchRoleHelper(names[i], PortRoleType::MODE);
+ currentPortStatus[i].canChangeDataRole =
+ canSwitchRoleHelper(names[i], PortRoleType::DATA_ROLE);
+ currentPortStatus[i].canChangePowerRole =
+ canSwitchRoleHelper(names[i], PortRoleType::POWER_ROLE);
+
+ ALOGI("canChangeMode: %d canChagedata: %d canChangePower:%d",
+ currentPortStatus[i].canChangeMode,
+ currentPortStatus[i].canChangeDataRole,
+ currentPortStatus[i].canChangePowerRole);
+
+ if (getPortModeHelper(names[i], currentPortStatus[i].supportedModes)
+ != Status::SUCCESS) {
+ ALOGE("Error while retrieving port modes");
+ goto done;
+ }
+ }
+ return Status::SUCCESS;
+ }
+done:
+ return Status::ERROR;
+}
+
+Return<void> Usb::queryPortStatus() {
+ hidl_vec<PortStatus> currentPortStatus;
+ Status status;
+
+ status = getPortStatusHelper(currentPortStatus);
+ Return<void> ret = mCallback->notifyPortStatusChange(currentPortStatus,
+ status);
+ if (!ret.isOk())
+ ALOGE("queryPortStatus error %s", ret.description().c_str());
+
+ return Void();
+}
+struct data {
+ int uevent_fd;
+ android::hardware::usb::V1_0::implementation::Usb *usb;
+};
+
+static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
+ char msg[UEVENT_MSG_LEN + 2];
+ char *cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
+ if (n <= 0)
+ return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n + 1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (!strcmp(cp, "SUBSYSTEM=dual_role_usb")) {
+ ALOGE("uevent received %s", cp);
+ if (payload->usb->mCallback != NULL) {
+ hidl_vec<PortStatus> currentPortStatus;
+ Status status = getPortStatusHelper(currentPortStatus);
+ Return<void> ret =
+ payload->usb->mCallback->notifyPortStatusChange(currentPortStatus, status);
+ if (!ret.isOk())
+ ALOGE("error %s", ret.description().c_str());
+ }
+ break;
+ }
+ /* advance to after the next \0 */
+ while (*cp++);
+ }
+}
+
+void* work(void* param) {
+ int epoll_fd, uevent_fd;
+ struct epoll_event ev;
+ int nevents = 0;
+ struct data payload;
+
+ ALOGE("creating thread");
+
+ uevent_fd = uevent_open_socket(64*1024, true);
+
+ if (uevent_fd < 0) {
+ ALOGE("uevent_init: uevent_open_socket failed\n");
+ return NULL;
+ }
+
+ payload.uevent_fd = uevent_fd;
+ payload.usb = (android::hardware::usb::V1_0::implementation::Usb *)param;
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+
+ ev.events = EPOLLIN;
+ ev.data.ptr = (void *)uevent_event;
+
+ epoll_fd = epoll_create(64);
+ if (epoll_fd == -1) {
+ ALOGE("epoll_create failed; errno=%d", errno);
+ goto error;
+ }
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
+ ALOGE("epoll_ctl failed; errno=%d", errno);
+ goto error;
+ }
+
+ while (!destroyThread) {
+ struct epoll_event events[64];
+
+ nevents = epoll_wait(epoll_fd, events, 64, -1);
+ if (nevents == -1) {
+ if (errno == EINTR)
+ continue;
+ ALOGE("usb epoll_wait failed; errno=%d", errno);
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr)
+ (*(void (*)(int, struct data *payload))events[n].data.ptr)
+ (events[n].events, &payload);
+ }
+ }
+
+ ALOGI("exiting worker thread");
+error:
+ close(uevent_fd);
+
+ if (epoll_fd >= 0)
+ close(epoll_fd);
+
+ return NULL;
+}
+
+void sighandler(int sig)
+{
+ if (sig == SIGUSR1) {
+ destroyThread = true;
+ ALOGI("destroy set");
+ return;
+ }
+ signal(SIGUSR1, sighandler);
+}
+
+Return<void> Usb::setCallback(const sp<IUsbCallback>& callback) {
+
+ pthread_mutex_lock(&mLock);
+ if ((mCallback == NULL && callback == NULL) ||
+ (mCallback != NULL && callback != NULL)) {
+ mCallback = callback;
+ pthread_mutex_unlock(&mLock);
+ return Void();
+ }
+
+ mCallback = callback;
+ ALOGI("registering callback");
+
+ if (mCallback == NULL) {
+ if (!pthread_kill(mPoll, SIGUSR1)) {
+ pthread_join(mPoll, NULL);
+ ALOGI("pthread destroyed");
+ }
+ pthread_mutex_unlock(&mLock);
+ return Void();
+ }
+
+ destroyThread = false;
+ signal(SIGUSR1, sighandler);
+
+ if (pthread_create(&mPoll, NULL, work, this)) {
+ ALOGE("pthread creation failed %d", errno);
+ mCallback = NULL;
+ }
+ pthread_mutex_unlock(&mLock);
+ return Void();
+}
+
+// Protects *usb assignment
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+Usb *usb;
+
+Usb::Usb() {
+ pthread_mutex_lock(&lock);
+ // Make this a singleton class
+ assert(usb == NULL);
+ usb = this;
+ pthread_mutex_unlock(&lock);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace usb
+} // namespace hardware
+} // namespace android
diff --git a/usb/1.0/default/Usb.h b/usb/1.0/default/Usb.h
new file mode 100644
index 0000000..c34d080
--- /dev/null
+++ b/usb/1.0/default/Usb.h
@@ -0,0 +1,52 @@
+#ifndef ANDROID_HARDWARE_USB_V1_0_USB_H
+#define ANDROID_HARDWARE_USB_V1_0_USB_H
+
+#include <android/hardware/usb/1.0/IUsb.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Log.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "android.hardware.usb@1.0-service"
+#define UEVENT_MSG_LEN 2048
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::usb::V1_0::IUsb;
+using ::android::hardware::usb::V1_0::IUsbCallback;
+using ::android::hardware::usb::V1_0::PortRole;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Usb : public IUsb {
+ Usb();
+ Return<void> switchRole(const hidl_string& portName, const PortRole& role) override;
+ Return<void> setCallback(const sp<IUsbCallback>& callback) override;
+ Return<void> queryPortStatus() override;
+
+ sp<IUsbCallback> mCallback;
+ private:
+ pthread_t mPoll;
+ pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace usb
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_USB_V1_0_USB_H
diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.rc b/usb/1.0/default/android.hardware.usb@1.0-service.rc
new file mode 100644
index 0000000..6ea0720
--- /dev/null
+++ b/usb/1.0/default/android.hardware.usb@1.0-service.rc
@@ -0,0 +1,4 @@
+service usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service
+ class hal
+ user system
+ group system
diff --git a/usb/1.0/default/service.cpp b/usb/1.0/default/service.cpp
new file mode 100644
index 0000000..4605a4c
--- /dev/null
+++ b/usb/1.0/default/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <hidl/HidlTransportSupport.h>
+#include "Usb.h"
+
+using android::sp;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::usb::V1_0::IUsb;
+using android::hardware::usb::V1_0::implementation::Usb;
+
+int main() {
+
+ android::sp<IUsb> service = new Usb();
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+ service->registerAsService();
+
+ ALOGI("USB HAL Ready.");
+ joinRpcThreadpool();
+}
diff --git a/usb/1.0/types.hal b/usb/1.0/types.hal
new file mode 100644
index 0000000..17cd8c7
--- /dev/null
+++ b/usb/1.0/types.hal
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2016 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.usb@1.0;
+
+
+enum Status : uint32_t {
+ SUCCESS = 0,
+
+ /*
+ * error value when the HAL operation fails for reasons not listed here.
+ */
+ ERROR = 1,
+
+ /*
+ * error value returned when input argument is invalid.
+ */
+ INVALID_ARGUMENT = 2,
+
+ /*
+ * error value returned when role string is unrecognized.
+ */
+ UNRECOGNIZED_ROLE = 3,
+};
+
+/*
+ * Denotes the Port role type.
+ * Passed as an argument for functions used to query or change port roles.
+ */
+enum PortRoleType : uint32_t {
+ /*
+ * Denotes the data role of the port.
+ * The port can either be a "host" or a "device" for data.
+ * This maps to the PortDataRole enum.
+ */
+ DATA_ROLE = 0,
+
+ /*
+ * Denotes the power role of the port.
+ * The port can either be a "source" or "sink" for power.
+ * This maps to PortPowerRole enum.
+ */
+ POWER_ROLE = 1,
+
+ /*
+ * USB ports can be a pure DFP port which can only act
+ * as a host. A UFP port which can only act as a device.
+ * Or a dual role ports which can either can as a host or
+ * a device. This property is used to mention them.
+ */
+ MODE = 2,
+};
+
+@export
+enum PortDataRole : uint32_t {
+ /*
+ * Indicates that the port does not have a data role.
+ * In case of DRP, the current data role of the port is only resolved
+ * when the type-c handshake happens.
+ */
+ NONE = 0,
+
+ /*
+ * Indicates that the port is acting as a host for data.
+ */
+ HOST = 1,
+
+ /*
+ * Indicated that the port is acting as a device for data.
+ */
+ DEVICE = 2,
+
+ NUM_DATA_ROLES = 3,
+};
+
+@export
+enum PortPowerRole : uint32_t {
+ /*
+ * Indicates that the port does not have a power role.
+ * In case of DRP, the current power role of the port is only resolved
+ * when the type-c handshake happens.
+ */
+ NONE = 0,
+
+ /*
+ * Indicates that the port is supplying power to the other port.
+ */
+ SOURCE = 1,
+
+ /*
+ * Indicates that the port is sinking power from the other port.
+ */
+ SINK = 2,
+
+ NUM_POWER_ROLES = 3,
+};
+
+@export
+enum PortMode : uint32_t {
+ /*
+ * Indicates that the port does not have a mode.
+ * In case of DRP, the current mode of the port is only resolved
+ * when the type-c handshake happens.
+ */
+ NONE = 0,
+ /*
+ * Indicates that port can only act as device for data and sink for power.
+ */
+ UFP = 1,
+
+ /*
+ * Indicates the port can only act as host for data and source for power.
+ */
+ DFP = 2,
+
+ /*
+ * Indicates can either act as UFP or DFP at a given point of time.
+ */
+ DRP = 3,
+
+ NUM_MODES = 4,
+};
+
+/*
+ * Used as a container to send port role information.
+ */
+struct PortRole {
+ /*
+ * Indicates the type of Port Role.
+ * Maps to the PortRoleType enum.
+ */
+ PortRoleType type;
+
+ /*
+ * when type is HAL_USB_DATA_ROLE pass values from enum PortDataRole.
+ * when type is HAL_USB_POWER_ROLE pass values from enum PortPowerRole.
+ * when type is HAL_USB_MODE pass values from enum PortMode.
+ */
+ uint32_t role;
+};
+
+/*
+ * Used as the container to report data back to the caller.
+ * Represents the current connection status of a single USB port.
+ */
+struct PortStatus {
+ /*
+ * Name of the port.
+ * Used as the port's id by the caller.
+ */
+ string portName;
+
+ /*
+ * Data role of the port.
+ */
+ PortDataRole currentDataRole;
+
+ /*
+ * Power Role of thte port.
+ */
+ PortPowerRole currentPowerRole;
+
+ /*
+ * Mode in which the port is connected.
+ * Can be UFP or DFP.
+ */
+ PortMode currentMode;
+
+ /*
+ * True indicates that the port's mode can
+ * be changed. False otherwise.
+ */
+ bool canChangeMode;
+
+ /*
+ * True indicates that the port's data role
+ * can be changed. False otherwise.
+ * For example, true if Type-C PD PD_SWAP
+ * is supported.
+ */
+ bool canChangeDataRole;
+
+ /*
+ * True indicates that the port's power role
+ * can be changed. False otherwise.
+ * For example, true if Type-C PD PR_SWAP
+ * is supported.
+ */
+ bool canChangePowerRole;
+
+ /*
+ * Identifies the type of the local port.
+ *
+ * UFP - Indicates that port can only act as device for
+ * data and sink for power.
+ * DFP - Indicates the port can only act as host for data
+ * and source for power.
+ * DRP - Indicates can either act as UFP or DFP at a
+ * given point of time.
+ */
+ PortMode supportedModes;
+};
diff --git a/usb/1.0/vts/functional/Android.bp b/usb/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..7438bc7
--- /dev/null
+++ b/usb/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalUsbV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalUsbV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.usb@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
new file mode 100644
index 0000000..ea6d4a9
--- /dev/null
+++ b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "VtsHalUsbV1_0TargetTest"
+#include <android-base/logging.h>
+
+#include <android/hardware/usb/1.0/IUsb.h>
+#include <android/hardware/usb/1.0/IUsbCallback.h>
+#include <android/hardware/usb/1.0/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <stdlib.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#define TIMEOUT_PERIOD 10
+
+using ::android::hardware::usb::V1_0::IUsbCallback;
+using ::android::hardware::usb::V1_0::IUsb;
+using ::android::hardware::usb::V1_0::PortDataRole;
+using ::android::hardware::usb::V1_0::PortMode;
+using ::android::hardware::usb::V1_0::PortPowerRole;
+using ::android::hardware::usb::V1_0::PortRole;
+using ::android::hardware::usb::V1_0::PortRoleType;
+using ::android::hardware::usb::V1_0::PortStatus;
+using ::android::hardware::usb::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for the USB hidl HAL
+class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ // Callback class for the USB HIDL hal.
+ // Usb Hal will call this object upon role switch or port query.
+ class UsbCallback : public IUsbCallback {
+ UsbHidlTest& parent_;
+ int cookie;
+
+ public:
+ UsbCallback(UsbHidlTest& parent, int cookie)
+ : parent_(parent), cookie(cookie){};
+
+ virtual ~UsbCallback() = default;
+
+ // Callback method for the port status.
+ Return<void> notifyPortStatusChange(
+ const hidl_vec<PortStatus>& currentPortStatus, Status retval) override {
+ if (retval == Status::SUCCESS) {
+ parent_.usb_last_port_status.portName =
+ currentPortStatus[0].portName.c_str();
+ parent_.usb_last_port_status.currentDataRole =
+ currentPortStatus[0].currentDataRole;
+ parent_.usb_last_port_status.currentPowerRole =
+ currentPortStatus[0].currentPowerRole;
+ parent_.usb_last_port_status.currentMode =
+ currentPortStatus[0].currentMode;
+ }
+ parent_.usb_last_cookie = cookie;
+ parent_.notify();
+ return Void();
+ };
+
+ // Callback method for the status of role switch operation.
+ Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/,
+ const PortRole& newRole,
+ Status retval) override {
+ parent_.usb_last_status = retval;
+ parent_.usb_last_cookie = cookie;
+ parent_.usb_last_port_role = newRole;
+ parent_.usb_role_switch_done = true;
+ parent_.notify();
+ return Void();
+ };
+ };
+
+ virtual void SetUp() override {
+ ALOGI("Setup");
+ usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>();
+ ASSERT_NE(usb, nullptr);
+
+ usb_cb_2 = new UsbCallback(*this, 2);
+ ASSERT_NE(usb_cb_2, nullptr);
+ Return<void> ret = usb->setCallback(usb_cb_2);
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ virtual void TearDown() override { ALOGI("Teardown"); }
+
+ // Used as a mechanism to inform the test about data/event callback.
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(usb_mtx);
+ usb_count++;
+ usb_cv.notify_one();
+ }
+
+ // Test code calls this function to wait for data/event callback.
+ inline std::cv_status wait() {
+ std::unique_lock<std::mutex> lock(usb_mtx);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (usb_count == 0) {
+ status =
+ usb_cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ ALOGI("timeout");
+ return status;
+ }
+ }
+ usb_count--;
+ return status;
+ }
+
+ // USB hidl hal Proxy
+ sp<IUsb> usb;
+
+ // Callback objects for usb hidl
+ // Methods of these objects are called to notify port status updates.
+ sp<IUsbCallback> usb_cb_1, usb_cb_2;
+
+ // The last conveyed status of the USB ports.
+ // Stores information of currentt_data_role, power_role for all the USB ports
+ PortStatus usb_last_port_status;
+
+ // Status of the last role switch operation.
+ Status usb_last_status;
+
+ // Port role information of the last role switch operation.
+ PortRole usb_last_port_role;
+
+ // Flag to indicate the invocation of role switch callback.
+ bool usb_role_switch_done;
+
+ // Identifier for the usb callback object.
+ // Stores the cookie of the last invoked usb callback object.
+ int usb_last_cookie;
+
+ // synchronization primitives to coordinate between main test thread
+ // and the callback thread.
+ std::mutex usb_mtx;
+ std::condition_variable usb_cv;
+ int usb_count;
+};
+
+/*
+ * Test to see if setCallback succeeds.
+ * Callback oject is created and registered.
+ * Check to see if the hidl transaction succeeded.
+ */
+TEST_F(UsbHidlTest, setCallback) {
+ usb_cb_1 = new UsbCallback(*this, 1);
+ ASSERT_NE(usb_cb_1, nullptr);
+ Return<void> ret = usb->setCallback(usb_cb_1);
+ ASSERT_TRUE(ret.isOk());
+}
+
+/*
+ * Check to see if querying type-c
+ * port status succeeds.
+ */
+TEST_F(UsbHidlTest, queryPortStatus) {
+ Return<void> ret = usb->queryPortStatus();
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(2, usb_last_cookie);
+ ALOGI("rightafter: %s", usb_last_port_status.portName.c_str());
+}
+
+/*
+ * Trying to switch a non-existent port should fail.
+ * This test case tried to switch the port with empty
+ * name which is expected to fail.
+ */
+TEST_F(UsbHidlTest, switchEmptyPort) {
+ struct PortRole role;
+ role.type = PortRoleType::DATA_ROLE;
+
+ Return<void> ret = usb->switchRole("", role);
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(Status::ERROR, usb_last_status);
+ EXPECT_EQ(2, usb_last_cookie);
+}
+
+/*
+ * Test switching the mode of usb port.
+ * Test case queries the usb ports present in device.
+ * If there is atleast one usb port, a mode switch
+ * to DFP is attempted for the port.
+ * The callback parametes are checked to see if the mode
+ * switch was successfull. Upon success, Status::SUCCESS
+ * is expected to be returned.
+ */
+TEST_F(UsbHidlTest, switchModetoDFP) {
+ struct PortRole role;
+ role.type = PortRoleType::MODE;
+ role.role = static_cast<uint32_t>(PortMode::DFP);
+
+ Return<void> ret = usb->queryPortStatus();
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(2, usb_last_cookie);
+
+ if (!usb_last_port_status.portName.empty()) {
+ hidl_string portBeingSwitched = usb_last_port_status.portName;
+ ALOGI("mode portname:%s", portBeingSwitched.c_str());
+ usb_role_switch_done = false;
+ Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
+ ASSERT_TRUE(ret.isOk());
+
+ std::cv_status waitStatus = wait();
+ while (waitStatus == std::cv_status::no_timeout &&
+ usb_role_switch_done == false)
+ waitStatus = wait();
+
+ EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
+ EXPECT_EQ(2, usb_last_cookie);
+
+ EXPECT_EQ(static_cast<uint32_t>(PortRoleType::MODE),
+ static_cast<uint32_t>(usb_last_port_role.type));
+ if (usb_last_status == Status::SUCCESS) {
+ EXPECT_EQ(static_cast<uint32_t>(PortMode::DFP),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ } else {
+ EXPECT_NE(static_cast<uint32_t>(PortMode::UFP),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ }
+ }
+}
+
+/*
+ * Test switching the power role of usb port.
+ * Test case queries the usb ports present in device.
+ * If there is atleast one usb port, a power role switch
+ * to SOURCE is attempted for the port.
+ * The callback parametes are checked to see if the power role
+ * switch was successfull. Upon success, Status::SUCCESS
+ * is expected to be returned.
+ */
+
+TEST_F(UsbHidlTest, switchPowerRole) {
+ struct PortRole role;
+ role.type = PortRoleType::POWER_ROLE;
+ role.role = static_cast<uint32_t>(PortPowerRole::SOURCE);
+
+ Return<void> ret = usb->queryPortStatus();
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(2, usb_last_cookie);
+
+ if (!usb_last_port_status.portName.empty()) {
+ hidl_string portBeingSwitched = usb_last_port_status.portName;
+ ALOGI("switchPower role portname:%s", portBeingSwitched.c_str());
+ usb_role_switch_done = false;
+ Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
+ ASSERT_TRUE(ret.isOk());
+
+ std::cv_status waitStatus = wait();
+ while (waitStatus == std::cv_status::no_timeout &&
+ usb_role_switch_done == false)
+ waitStatus = wait();
+
+ EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
+ EXPECT_EQ(2, usb_last_cookie);
+
+ EXPECT_EQ(static_cast<uint32_t>(PortRoleType::POWER_ROLE),
+ static_cast<uint32_t>(usb_last_port_role.type));
+ if (usb_last_status == Status::SUCCESS) {
+ EXPECT_EQ(static_cast<uint32_t>(PortPowerRole::SOURCE),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ } else {
+ EXPECT_NE(static_cast<uint32_t>(PortPowerRole::SINK),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ }
+ }
+}
+
+/*
+ * Test switching the data role of usb port.
+ * Test case queries the usb ports present in device.
+ * If there is atleast one usb port, a power role switch
+ * to HOST is attempted for the port.
+ * The callback parametes are checked to see if the power role
+ * switch was successfull. Upon success, Status::SUCCESS
+ * is expected to be returned.
+ */
+TEST_F(UsbHidlTest, switchDataRole) {
+ struct PortRole role;
+ role.type = PortRoleType::DATA_ROLE;
+ role.role = static_cast<uint32_t>(PortDataRole::HOST);
+
+ Return<void> ret = usb->queryPortStatus();
+ ASSERT_TRUE(ret.isOk());
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(2, usb_last_cookie);
+
+ if (!usb_last_port_status.portName.empty()) {
+ hidl_string portBeingSwitched = usb_last_port_status.portName;
+ ALOGI("portname:%s", portBeingSwitched.c_str());
+ usb_role_switch_done = false;
+ Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
+ ASSERT_TRUE(ret.isOk());
+
+ std::cv_status waitStatus = wait();
+ while (waitStatus == std::cv_status::no_timeout &&
+ usb_role_switch_done == false)
+ waitStatus = wait();
+
+ EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
+ EXPECT_EQ(2, usb_last_cookie);
+
+ EXPECT_EQ(static_cast<uint32_t>(PortRoleType::DATA_ROLE),
+ static_cast<uint32_t>(usb_last_port_role.type));
+ if (usb_last_status == Status::SUCCESS) {
+ EXPECT_EQ(static_cast<uint32_t>(PortDataRole::HOST),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ } else {
+ EXPECT_NE(static_cast<uint32_t>(PortDataRole::DEVICE),
+ static_cast<uint32_t>(usb_last_port_role.role));
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/usb/Android.bp b/usb/Android.bp
new file mode 100644
index 0000000..33f70eb
--- /dev/null
+++ b/usb/Android.bp
@@ -0,0 +1,5 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/vts/functional",
+]
diff --git a/vibrator/1.0/Android.bp b/vibrator/1.0/Android.bp
new file mode 100644
index 0000000..d6813ea
--- /dev/null
+++ b/vibrator/1.0/Android.bp
@@ -0,0 +1,62 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.vibrator@1.0_hal",
+ srcs: [
+ "types.hal",
+ "IVibrator.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.vibrator@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vibrator@1.0",
+ srcs: [
+ ":android.hardware.vibrator@1.0_hal",
+ ],
+ out: [
+ "android/hardware/vibrator/1.0/types.cpp",
+ "android/hardware/vibrator/1.0/VibratorAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.vibrator@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vibrator@1.0",
+ srcs: [
+ ":android.hardware.vibrator@1.0_hal",
+ ],
+ out: [
+ "android/hardware/vibrator/1.0/types.h",
+ "android/hardware/vibrator/1.0/IVibrator.h",
+ "android/hardware/vibrator/1.0/IHwVibrator.h",
+ "android/hardware/vibrator/1.0/BnHwVibrator.h",
+ "android/hardware/vibrator/1.0/BpHwVibrator.h",
+ "android/hardware/vibrator/1.0/BsVibrator.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.vibrator@1.0",
+ generated_sources: ["android.hardware.vibrator@1.0_genc++"],
+ generated_headers: ["android.hardware.vibrator@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.vibrator@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/vibrator/1.0/Android.mk b/vibrator/1.0/Android.mk
new file mode 100644
index 0000000..d921a7e
--- /dev/null
+++ b/vibrator/1.0/Android.mk
@@ -0,0 +1,190 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vibrator@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build types.hal (Effect)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Effect.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::types.Effect
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVibrator.hal
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/IVibrator.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVibrator.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::IVibrator
+
+$(GEN): $(LOCAL_PATH)/IVibrator.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vibrator@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build types.hal (Effect)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Effect.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::types.Effect
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IVibrator.hal
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/IVibrator.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVibrator.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0::IVibrator
+
+$(GEN): $(LOCAL_PATH)/IVibrator.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vibrator@1.0-java-constants
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(local-generated-sources-dir)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+#
+GEN := $(intermediates)/android/hardware/vibrator/V1_0/Constants.java
+$(GEN): $(HIDL)
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/IVibrator.hal
+
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava-constants \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vibrator@1.0
+
+$(GEN):
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+# Avoid dependency cycle of framework.jar -> this-library -> framework.jar
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/vibrator/1.0/IVibrator.hal b/vibrator/1.0/IVibrator.hal
new file mode 100644
index 0000000..757ad0d
--- /dev/null
+++ b/vibrator/1.0/IVibrator.hal
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 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.vibrator@1.0;
+
+interface IVibrator {
+ /**
+ * Turn on vibrator
+ *
+ * This function must only be called after the previous timeout has expired or
+ * was canceled (through off()).
+ * @param timeout_ms number of milliseconds to vibrate.
+ * @return vibratorOnRet whether vibrator command was successful or not.
+ */
+ on(uint32_t timeoutMs) generates (Status vibratorOnRet);
+
+ /**
+ * Turn off vibrator
+ *
+ * Cancel a previously-started vibration, if any.
+ * @return vibratorOffRet whether vibrator command was successful or not.
+ */
+ off() generates (Status vibratorOffRet);
+
+ /**
+ * Returns whether the vibrator supports changes to its vibrational amplitude.
+ */
+ supportsAmplitudeControl() generates (bool supports);
+
+ /**
+ * Sets the motor's vibrational amplitude.
+ *
+ * Changes the force being produced by the underlying motor.
+ *
+ * @param amplitude The unitless force setting. Note that this number must
+ * be between 1 and 255, inclusive. If the motor does not
+ * have exactly 255 steps, it must do it's best to map it
+ * onto the number of steps it does have.
+ * @return status Whether the command was successful or not. Must return
+ * Status::UNSUPPORTED_OPERATION if setting the amplitude is
+ * not supported by the device.
+ */
+ setAmplitude(uint8_t amplitude) generates (Status status);
+
+ /**
+ * Fire off a predefined haptic event.
+ *
+ * @param event The type of haptic event to trigger.
+ * @return status Whether the effect was successfully performed or not. Must
+ * return Status::UNSUPPORTED_OPERATION is the effect is not
+ * supported.
+ * @return lengthMs The length of time the event is expected to take in
+ * milliseconds. This doesn't need to be perfectly accurate,
+ * but should be a reasonable approximation. Should be a
+ * positive, non-zero value if the returned status is
+ * Status::OK, and set to 0 otherwise.
+ */
+ perform(Effect effect, EffectStrength strength) generates (Status status, uint32_t lengthMs);
+};
diff --git a/vibrator/1.0/default/Android.bp b/vibrator/1.0/default/Android.bp
new file mode 100644
index 0000000..d4200da
--- /dev/null
+++ b/vibrator/1.0/default/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2016 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.
+
+cc_library_shared {
+ name: "android.hardware.vibrator@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Vibrator.cpp"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.vibrator@1.0",
+ ],
+}
diff --git a/vibrator/1.0/default/Android.mk b/vibrator/1.0/default/Android.mk
new file mode 100644
index 0000000..af4a955
--- /dev/null
+++ b/vibrator/1.0/default/Android.mk
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2016 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vibrator@1.0-service
+LOCAL_INIT_RC := android.hardware.vibrator@1.0-service.rc
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils \
+ libhardware \
+ android.hardware.vibrator@1.0
+
+include $(BUILD_EXECUTABLE)
diff --git a/vibrator/1.0/default/Vibrator.cpp b/vibrator/1.0/default/Vibrator.cpp
new file mode 100644
index 0000000..19cf3dc
--- /dev/null
+++ b/vibrator/1.0/default/Vibrator.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "VibratorService"
+
+#include <inttypes.h>
+
+#include <log/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/vibrator.h>
+
+#include "Vibrator.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_0 {
+namespace implementation {
+
+Vibrator::Vibrator(vibrator_device_t *device) : mDevice(device) {}
+
+// Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
+Return<Status> Vibrator::on(uint32_t timeout_ms) {
+ int32_t ret = mDevice->vibrator_on(mDevice, timeout_ms);
+ if (ret != 0) {
+ ALOGE("on command failed : %s", strerror(-ret));
+ return Status::UNKNOWN_ERROR;
+ }
+ return Status::OK;
+}
+
+Return<Status> Vibrator::off() {
+ int32_t ret = mDevice->vibrator_off(mDevice);
+ if (ret != 0) {
+ ALOGE("off command failed : %s", strerror(-ret));
+ return Status::UNKNOWN_ERROR;
+ }
+ return Status::OK;
+}
+
+Return<bool> Vibrator::supportsAmplitudeControl() {
+ return false;
+}
+
+Return<Status> Vibrator::setAmplitude(uint8_t) {
+ return Status::UNSUPPORTED_OPERATION;
+}
+
+Return<void> Vibrator::perform(Effect, EffectStrength, perform_cb _hidl_cb) {
+ _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+ return Void();
+}
+
+IVibrator* HIDL_FETCH_IVibrator(const char * /*hal*/) {
+ vibrator_device_t *vib_device;
+ const hw_module_t *hw_module = nullptr;
+
+ int ret = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, &hw_module);
+ if (ret == 0) {
+ ret = vibrator_open(hw_module, &vib_device);
+ if (ret != 0) {
+ ALOGE("vibrator_open failed: %d", ret);
+ }
+ } else {
+ ALOGE("hw_get_module %s failed: %d", VIBRATOR_HARDWARE_MODULE_ID, ret);
+ }
+
+ if (ret == 0) {
+ return new Vibrator(vib_device);
+ } else {
+ ALOGE("Passthrough failed to open legacy HAL.");
+ return nullptr;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/1.0/default/Vibrator.h b/vibrator/1.0/default/Vibrator.h
new file mode 100644
index 0000000..bea6ea8
--- /dev/null
+++ b/vibrator/1.0/default/Vibrator.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H
+
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_0 {
+namespace implementation {
+
+struct Vibrator : public IVibrator {
+ Vibrator(vibrator_device_t *device);
+
+ // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
+ Return<Status> on(uint32_t timeoutMs) override;
+ Return<Status> off() override;
+ Return<bool> supportsAmplitudeControl() override;
+ Return<Status> setAmplitude(uint8_t amplitude) override;
+ Return<void> perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+
+private:
+ vibrator_device_t *mDevice;
+};
+
+extern "C" IVibrator* HIDL_FETCH_IVibrator(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H
diff --git a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
new file mode 100644
index 0000000..4153c44
--- /dev/null
+++ b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
@@ -0,0 +1,4 @@
+service vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service
+ class hal
+ user system
+ group system readproc
diff --git a/vibrator/1.0/default/service.cpp b/vibrator/1.0/default/service.cpp
new file mode 100644
index 0000000..7cc0744
--- /dev/null
+++ b/vibrator/1.0/default/service.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.vibrator@1.0-service"
+
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::vibrator::V1_0::IVibrator;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IVibrator>();
+}
diff --git a/vibrator/1.0/types.hal b/vibrator/1.0/types.hal
new file mode 100644
index 0000000..a080c07
--- /dev/null
+++ b/vibrator/1.0/types.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.vibrator@1.0;
+
+enum Status : uint32_t {
+ OK,
+ UNKNOWN_ERROR,
+ BAD_VALUE,
+ UNSUPPORTED_OPERATION
+};
+
+@export
+enum Effect : uint32_t {
+ /**
+ * A single click effect.
+ *
+ * This effect should produce a sharp, crisp click sensation.
+ */
+ CLICK,
+ /**
+ * A double click effect.
+ *
+ * This effect should produce two sequential sharp, crisp click sensations with a minimal
+ * amount of time between them.
+ */
+ DOUBLE_CLICK
+};
+
+@export
+enum EffectStrength : uint8_t {
+ LIGHT,
+ MEDIUM,
+ STRONG
+};
diff --git a/radio/1.0/vts/Android.mk b/vibrator/1.0/vts/Android.mk
similarity index 100%
copy from radio/1.0/vts/Android.mk
copy to vibrator/1.0/vts/Android.mk
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..9e25def
--- /dev/null
+++ b/vibrator/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalVibratorV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalVibratorV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.vibrator@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
diff --git a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
new file mode 100644
index 0000000..f415ad5
--- /dev/null
+++ b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "vibrator_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <android/hardware/vibrator/1.0/types.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <unistd.h>
+
+using ::android::hardware::vibrator::V1_0::Effect;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::IVibrator;
+using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for VIBRATOR HIDL HAL.
+class VibratorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>();
+ ASSERT_NE(vibrator, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IVibrator> vibrator;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class VibratorHidlEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ private:
+};
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+ ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+ if (status == Status::OK) {
+ ASSERT_GT(lengthMs, static_cast<uint32_t>(0));
+ } else {
+ ASSERT_EQ(lengthMs, static_cast<uint32_t>(0));
+ }
+}
+
+TEST_F(VibratorHidlTest, OnThenOffBeforeTimeout) {
+ EXPECT_EQ(Status::OK, vibrator->on(2000));
+ sleep(1);
+ EXPECT_EQ(Status::OK, vibrator->off());
+}
+
+TEST_F(VibratorHidlTest, PerformEffect) {
+ vibrator->perform(Effect::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
+ vibrator->perform(Effect::DOUBLE_CLICK, EffectStrength::LIGHT, validatePerformEffect);
+}
+
+TEST_F(VibratorHidlTest, ChangeVibrationalAmplitude) {
+ if (vibrator->supportsAmplitudeControl()) {
+ EXPECT_EQ(Status::OK, vibrator->setAmplitude(1));
+ EXPECT_EQ(Status::OK, vibrator->on(2000));
+ EXPECT_EQ(Status::OK, vibrator->setAmplitude(128));
+ sleep(1);
+ EXPECT_EQ(Status::OK, vibrator->setAmplitude(255));
+ sleep(1);
+ }
+}
+
+TEST_F(VibratorHidlTest, AmplitudeOutsideRangeFails) {
+ if (vibrator->supportsAmplitudeControl()) {
+ EXPECT_EQ(Status::BAD_VALUE, vibrator->setAmplitude(0));
+ }
+}
+
+TEST_F(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
+ if (!vibrator->supportsAmplitudeControl()) {
+ EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setAmplitude(1));
+ }
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(new VibratorHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/vibrator/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]
diff --git a/vr/1.0/Android.bp b/vr/1.0/Android.bp
new file mode 100644
index 0000000..b48d010
--- /dev/null
+++ b/vr/1.0/Android.bp
@@ -0,0 +1,59 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.vr@1.0_hal",
+ srcs: [
+ "IVr.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.vr@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vr@1.0",
+ srcs: [
+ ":android.hardware.vr@1.0_hal",
+ ],
+ out: [
+ "android/hardware/vr/1.0/VrAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.vr@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vr@1.0",
+ srcs: [
+ ":android.hardware.vr@1.0_hal",
+ ],
+ out: [
+ "android/hardware/vr/1.0/IVr.h",
+ "android/hardware/vr/1.0/IHwVr.h",
+ "android/hardware/vr/1.0/BnHwVr.h",
+ "android/hardware/vr/1.0/BpHwVr.h",
+ "android/hardware/vr/1.0/BsVr.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.vr@1.0",
+ generated_sources: ["android.hardware.vr@1.0_genc++"],
+ generated_headers: ["android.hardware.vr@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.vr@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/vr/1.0/Android.mk b/vr/1.0/Android.mk
new file mode 100644
index 0000000..0fbdaf7
--- /dev/null
+++ b/vr/1.0/Android.mk
@@ -0,0 +1,76 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vr@1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java \
+
+
+#
+# Build IVr.hal
+#
+GEN := $(intermediates)/android/hardware/vr/V1_0/IVr.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVr.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vr@1.0::IVr
+
+$(GEN): $(LOCAL_PATH)/IVr.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.vr@1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hidl.base@1.0-java-static \
+
+
+#
+# Build IVr.hal
+#
+GEN := $(intermediates)/android/hardware/vr/V1_0/IVr.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVr.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+ $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+ -Ljava \
+ -randroid.hardware:hardware/interfaces \
+ -randroid.hidl:system/libhidl/transport \
+ android.hardware.vr@1.0::IVr
+
+$(GEN): $(LOCAL_PATH)/IVr.hal
+ $(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/vr/1.0/IVr.hal b/vr/1.0/IVr.hal
new file mode 100644
index 0000000..1f996e9
--- /dev/null
+++ b/vr/1.0/IVr.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.vr@1.0;
+
+interface IVr {
+ /**
+ * Convenience method to set up any state needed at runtime startup. This is
+ * called once from the VrManagerService during its boot phase.
+ */
+ @callflow(next={"*"})
+ @entry
+ @exit
+ init();
+
+ /**
+ * Set the VR mode state. Possible states of the enabled parameter are:
+ * false - VR mode is disabled, turn off all VR-specific settings.
+ * true - VR mode is enabled, turn on all VR-specific settings.
+ *
+ * This must be called whenever the the Android system enters or leaves VR
+ * mode. This will typically occur when the user switches to or from a VR
+ * application that is doing stereoscopic rendering.
+ */
+ @callflow(next={"*"})
+ @exit
+ setVrMode(bool enabled);
+};
diff --git a/vr/1.0/default/Android.bp b/vr/1.0/default/Android.bp
new file mode 100644
index 0000000..ddc1bfb
--- /dev/null
+++ b/vr/1.0/default/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+ name: "android.hardware.vr@1.0-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["Vr.cpp"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.vr@1.0",
+ ],
+}
+
+cc_binary {
+ relative_install_path: "hw",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ name: "android.hardware.vr@1.0-service",
+ init_rc: ["android.hardware.vr@1.0-service.rc"],
+ srcs: ["service.cpp"],
+ shared_libs: [
+ "liblog",
+ "libdl",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.vr@1.0",
+ ],
+}
diff --git a/vr/1.0/default/Vr.cpp b/vr/1.0/default/Vr.cpp
new file mode 100644
index 0000000..4bba9eb
--- /dev/null
+++ b/vr/1.0/default/Vr.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "VrService"
+
+#include <log/log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/vr.h>
+
+#include "Vr.h"
+
+namespace android {
+namespace hardware {
+namespace vr {
+namespace V1_0 {
+namespace implementation {
+
+Vr::Vr(vr_module_t *device) : mDevice(device) {}
+
+// Methods from ::android::hardware::vr::V1_0::IVr follow.
+Return<void> Vr::init() {
+ mDevice->init(mDevice);
+ return Void();
+}
+
+Return<void> Vr::setVrMode(bool enabled) {
+ mDevice->set_vr_mode(mDevice, enabled);
+ return Void();
+}
+
+IVr* HIDL_FETCH_IVr(const char * /*name*/) {
+ const hw_module_t *hw_module = NULL;
+
+ int ret = hw_get_module(VR_HARDWARE_MODULE_ID, &hw_module);
+ if (ret == 0) {
+ return new Vr(reinterpret_cast<vr_module_t*>(
+ const_cast<hw_module_t*>(hw_module)));
+ } else {
+ ALOGE("hw_get_module %s failed: %d", VR_HARDWARE_MODULE_ID, ret);
+ return nullptr;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace vr
+} // namespace hardware
+} // namespace android
diff --git a/vr/1.0/default/Vr.h b/vr/1.0/default/Vr.h
new file mode 100644
index 0000000..dd5e764
--- /dev/null
+++ b/vr/1.0/default/Vr.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#ifndef ANDROID_HARDWARE_VR_V1_0_VR_H
+#define ANDROID_HARDWARE_VR_V1_0_VR_H
+
+#include <android/hardware/vr/1.0/IVr.h>
+#include <hardware/vr.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace vr {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::vr::V1_0::IVr;
+using ::android::hardware::Return;
+
+struct Vr : public IVr {
+ Vr(vr_module_t *device);
+
+ // Methods from ::android::hardware::vr::V1_0::IVr follow.
+ Return<void> init() override;
+ Return<void> setVrMode(bool enabled) override;
+
+ private:
+ vr_module_t *mDevice;
+};
+
+extern "C" IVr* HIDL_FETCH_IVr(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace vr
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_VR_V1_0_VR_H
diff --git a/vr/1.0/default/android.hardware.vr@1.0-service.rc b/vr/1.0/default/android.hardware.vr@1.0-service.rc
new file mode 100644
index 0000000..ba43302
--- /dev/null
+++ b/vr/1.0/default/android.hardware.vr@1.0-service.rc
@@ -0,0 +1,4 @@
+service vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service
+ class hal
+ user system
+ group system readproc
diff --git a/vr/1.0/default/service.cpp b/vr/1.0/default/service.cpp
new file mode 100644
index 0000000..22fb7d1
--- /dev/null
+++ b/vr/1.0/default/service.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#define LOG_TAG "android.hardware.vr@1.0-service"
+
+#include <android/hardware/vr/1.0/IVr.h>
+#include <hidl/LegacySupport.h>
+
+// Generated HIDL files
+using android::hardware::vr::V1_0::IVr;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IVr>();
+}
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..5d5a99a
--- /dev/null
+++ b/vr/1.0/vts/functional/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalVrV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalVrV1_0TargetTest.cpp"],
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libutils",
+ "android.hardware.vr@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ]
+}
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
new file mode 100644
index 0000000..a983731
--- /dev/null
+++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "vr_hidl_hal_test"
+#include <android-base/logging.h>
+#include <android/hardware/vr/1.0/IVr.h>
+#include <android/log.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <hardware/vr.h>
+
+using ::android::hardware::vr::V1_0::IVr;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for VR HIDL HAL.
+class VrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ vr = ::testing::VtsHalHidlTargetTestBase::getService<IVr>();
+ ASSERT_NE(vr, nullptr);
+ }
+
+ void TearDown() override {}
+
+ sp<IVr> vr;
+};
+
+
+// A class for test environment setup (kept since this file is a template).
+class VrHidlEnvironment : public ::testing::Environment {
+ public:
+ void SetUp() {}
+ void TearDown() {}
+
+ private:
+};
+
+// Sanity check that Vr::init does not crash.
+TEST_F(VrHidlTest, Init) {
+ EXPECT_TRUE(vr->init().isOk());
+}
+
+// Sanity check Vr::setVrMode is able to enable and disable VR mode.
+TEST_F(VrHidlTest, SetVrMode) {
+ EXPECT_TRUE(vr->init().isOk());
+ EXPECT_TRUE(vr->setVrMode(true).isOk());
+ EXPECT_TRUE(vr->setVrMode(false).isOk());
+}
+
+// Sanity check that Vr::init and Vr::setVrMode can be used in any order.
+TEST_F(VrHidlTest, ReInit) {
+ EXPECT_TRUE(vr->init().isOk());
+ EXPECT_TRUE(vr->setVrMode(true).isOk());
+ EXPECT_TRUE(vr->init().isOk());
+ EXPECT_TRUE(vr->setVrMode(false).isOk());
+ EXPECT_TRUE(vr->init().isOk());
+ EXPECT_TRUE(vr->setVrMode(false).isOk());
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(new VrHidlEnvironment);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/vr/Android.bp b/vr/Android.bp
new file mode 100644
index 0000000..ed19a37
--- /dev/null
+++ b/vr/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+ "1.0",
+ "1.0/default",
+ "1.0/vts/functional",
+]