Initialize capture templates.

As part of this, refactored characteristic initialization into its own
function so it can be used by both templates and static info.

BUG: 29221795

Change-Id: I88bb2e6a96256e3641c7c5d387769880b260535f
diff --git a/modules/camera/3_4/ArrayVector.h b/modules/camera/3_4/ArrayVector.h
new file mode 100644
index 0000000..53d09c5
--- /dev/null
+++ b/modules/camera/3_4/ArrayVector.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ARRAY_VECTOR_H
+#define ARRAY_VECTOR_H
+
+#include <array>
+#include <vector>
+
+namespace v4l2_camera_hal {
+// ArrayVector behaves like a std::vector of fixed length C arrays,
+// with push_back accepting std::arrays to standardize length.
+// Specific methods to get number of arrays/number of elements
+// are provided and an ambiguous "size" is not, to avoid accidental
+// incorrect use.
+template <class T, int N>
+class ArrayVector {
+public:
+  const T* data() const { return mItems.data(); }
+  // The number of arrays.
+  size_t num_arrays() const { return mItems.size() / N; }
+  // The number of elements amongst all arrays.
+  size_t total_num_elements() const { return mItems.size(); }
+
+  // Access the ith array.
+  const T* operator[](int i) const { return mItems.data() + (i * N); }
+  T* operator[](int i) { return mItems.data() + (i * N); }
+
+  void push_back(const std::array<T, N>& values) {
+    mItems.insert(mItems.end(), values.begin(), values.end());
+  }
+
+private:
+  std::vector<T> mItems;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // ARRAY_VECTOR_H
diff --git a/modules/camera/3_4/Camera.cpp b/modules/camera/3_4/Camera.cpp
index 0014a39..bbcdf7e 100644
--- a/modules/camera/3_4/Camera.cpp
+++ b/modules/camera/3_4/Camera.cpp
@@ -331,6 +331,9 @@
         ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type);
         return NULL;
     }
+
+    // Will return NULL (indicating unsupported) if the template is not
+    // initialized.
     return mTemplates[type];
 }
 
@@ -559,7 +562,7 @@
     return camdev_to_camera(dev)->configureStreams(stream_list);
 }
 
-  // TODO: remove
+// TODO(b/29221641): remove
 static int register_stream_buffers(const camera3_device_t *dev,
         const camera3_stream_buffer_set_t *buffer_set)
 {
diff --git a/modules/camera/3_4/V4L2Camera.cpp b/modules/camera/3_4/V4L2Camera.cpp
index 80e635a..cb310a7 100644
--- a/modules/camera/3_4/V4L2Camera.cpp
+++ b/modules/camera/3_4/V4L2Camera.cpp
@@ -17,9 +17,12 @@
 #include "V4L2Camera.h"
 
 #include <fcntl.h>
+#include <linux/videodev2.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include <cstdlib>
+
 #include <camera/CameraMetadata.h>
 #include <hardware/camera3.h>
 #include <nativehelper/ScopedFd.h>
@@ -31,7 +34,10 @@
 namespace v4l2_camera_hal {
 
 V4L2Camera::V4L2Camera(int id, std::string path)
-    : default_camera_hal::Camera(id), mDevicePath(std::move(path)) {
+    : default_camera_hal::Camera(id),
+      mDevicePath(std::move(path)),
+      mTemplatesInitialized(false),
+      mCharacteristicsInitialized(false) {
   HAL_LOG_ENTER();
 }
 
@@ -55,21 +61,21 @@
   mDeviceFd.reset(fd);
 
   // TODO(b/29185945): confirm this is a supported device.
-  //   This is checked by the HAL, but the device at mDevicePath may
-  //   not be the same one that was there when the HAL was loaded.
-  //   (Alternatively, better hotplugging support may make this unecessary
-  //   by disabling cameras that get disconnected and checking newly connected
-  //   cameras, so connect() is never called on an unsupported camera)
+  // This is checked by the HAL, but the device at mDevicePath may
+  // not be the same one that was there when the HAL was loaded.
+  // (Alternatively, better hotplugging support may make this unecessary
+  // by disabling cameras that get disconnected and checking newly connected
+  // cameras, so connect() is never called on an unsupported camera)
 
   // TODO(b/29158098): Inform service of any flashes that are no longer available
-  //   because this camera is in use.
+  // because this camera is in use.
   return 0;
 }
 
 void V4L2Camera::disconnect() {
   HAL_LOG_ENTER();
   // TODO(b/29158098): Inform service of any flashes that are available again
-  //   because this camera is no longer in use.
+  // because this camera is no longer in use.
 
   mDeviceFd.reset();
 }
@@ -77,19 +83,28 @@
 int V4L2Camera::initStaticInfo(camera_metadata_t** out) {
   HAL_LOG_ENTER();
 
+  android::status_t res;
+  // Device characteristics need to be queried prior
+  // to static info setup.
+  if (!mCharacteristicsInitialized) {
+    res = initCharacteristics();
+    if (res) {
+      return res;
+    }
+  }
+
   android::CameraMetadata info;
 
   std::vector<int32_t> avail_characteristics_keys;
-  android::status_t res;
 
-#define ADD_STATIC_ENTRY(name, varptr, count)   \
+#define ADD_STATIC_ENTRY(name, varptr, count) \
   avail_characteristics_keys.push_back(name); \
-  res = info.update(name, varptr, count);     \
+  res = info.update(name, varptr, count); \
   if (res != android::OK) return res
 
   // Static metadata characteristics from /system/media/camera/docs/docs.html.
 
-  /* android.color. */
+  /* android.colorCorrection. */
 
   // No easy way to turn chromatic aberration correction OFF in v4l2,
   // though this may be supportable via a collection of other user controls.
@@ -103,77 +118,42 @@
 
   /*   3As */
 
-  // TODO(b/29394024): query V4L2_CID_POWER_LINE_FREQUENCY
-  uint8_t avail_ae_antibanding_modes[] = {
-    ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
-                   avail_ae_antibanding_modes,
-                   ARRAY_SIZE(avail_ae_antibanding_modes));
+                   mAeAntibandingModes.data(), mAeAntibandingModes.size());
 
-  // TODO(b/29394024): query V4L2_CID_EXPOSURE_AUTO for ae modes.
-  uint8_t avail_ae_modes[] = {
-    ANDROID_CONTROL_AE_MODE_ON};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_MODES,
-                   avail_ae_modes, ARRAY_SIZE(avail_ae_modes));
+                   mAeModes.data(), mAeModes.size());
 
-  // TODO(b/29394034): query available YUV_420_888 frame rates.
-  //   This should be {mi, ma, ma, ma} where mi is min(15, min frame rate),
-  //   and ma is max frame rate (for YUV_420_888).
-  int32_t avail_fps_ranges[] = {
-    15, 30,
-    30, 30};
+  // Flatten mFpsRanges.
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
-                   avail_fps_ranges, ARRAY_SIZE(avail_fps_ranges));
+                   mFpsRanges.data(), mFpsRanges.total_num_elements());
 
-  // TODO(b/29394024): query V4L2_CID_EXPOSURE_BIAS.
-  int32_t ae_comp_range[] = {0, 0};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
-                   ae_comp_range, ARRAY_SIZE(ae_comp_range));
+                   mAeCompensationRange.data(), mAeCompensationRange.size());
 
-  // TODO(b/29394024): set based on V4L2_CID_EXPOSURE_BIAS step size.
-  camera_metadata_rational ae_comp_step = {1, 1};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_STEP,
-                   &ae_comp_step, 1);
+                   &mAeCompensationStep, 1);
 
-  // TODO(b/29394024): query V4L2_CID_FOCUS_AUTO for
-  //   CONTINUOUS_VIDEO/CONTINUOUS_PICTURE. V4L2_CID_AUTO_FOCUS_START
-  //   supports what Android thinks of as auto focus (single auto focus).
-  //   V4L2_CID_AUTO_FOCUS_RANGE allows MACRO.
-  uint8_t avail_af_modes[] = {
-    ANDROID_CONTROL_AF_MODE_OFF};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES,
-                   avail_af_modes, ARRAY_SIZE(avail_af_modes));
+                   mAfModes.data(), mAfModes.size());
 
-  // TODO(b/29394024): query V4L2_CID_AUTO_WHITE_BALANCE, or
-  //   V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE if available.
-  // If manual is supported, must look at android.colorCorrection
-  //   transform and gains for the manual control. Not sure if this
-  //   is supported by V4L2 or not, or if this is even a HAL job.
-  uint8_t avail_awb_modes[] = {
-    ANDROID_CONTROL_AWB_MODE_AUTO};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
-                   avail_awb_modes, ARRAY_SIZE(avail_awb_modes));
+                   mAwbModes.data(), mAwbModes.size());
 
   // Couldn't find any V4L2 support for regions, though maybe it's out there.
   int32_t max_regions[] = {/*AE*/ 0,/*AWB*/ 0,/*AF*/ 0};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_MAX_REGIONS,
                    max_regions, ARRAY_SIZE(max_regions));
 
-  // TODO(b/29394024): query V4L2_CID_3A_LOCK.
-  uint8_t ae_lock_avail = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
-                   &ae_lock_avail, 1);
-  uint8_t awb_lock_avail = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+                   &mAeLockAvailable, 1);
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
-                   &awb_lock_avail, 1);
+                   &mAwbLockAvailable, 1);
 
   /*   Scene modes. */
 
-  // TODO(b/29394024): query V4L2_CID_SCENE_MODE.
-  uint8_t avail_scene_modes[] = {
-    ANDROID_CONTROL_SCENE_MODE_DISABLED};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
-                   avail_scene_modes, ARRAY_SIZE(avail_scene_modes));
+                   mSceneModes.data(), mSceneModes.size());
 
   // A 3-tuple of AE, AWB, AF overrides for each scene mode.
   // Ignored for DISABLED, FACE_PRIORITY and FACE_PRIORITY_LOW_LIGHT.
@@ -184,25 +164,17 @@
 
   /*   Top level 3A/Scenes switch. */
 
-  // TODO(b/29394024): Add USE_SCENE_MODE if scene modes are enabled.
-  uint8_t avail_modes[] = {
-    ANDROID_CONTROL_MODE_AUTO};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_MODES,
-                   avail_modes, ARRAY_SIZE(avail_modes));
+                   mControlModes.data(), mControlModes.size());
 
   /*   Other android.control configuration. */
 
-  // TODO(b/29394024): query V4L2_CID_IMAGE_STABILIZATION.
-  uint8_t avail_stabilization[] = {
-    ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
-                   avail_stabilization, ARRAY_SIZE(avail_stabilization));
+                   mVideoStabilizationModes.data(),
+                   mVideoStabilizationModes.size());
 
-  // TODO(b/29394024): query V4L2_CID_COLORFX.
-  uint8_t avail_effects[] = {
-    ANDROID_CONTROL_EFFECT_MODE_OFF};
   ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_EFFECTS,
-                   avail_effects, ARRAY_SIZE(avail_effects));
+                   mEffects.data(), mEffects.size());
 
   // AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS only necessary
   // for devices supporting CONSTRAINED_HIGH_SPEED_VIDEO,
@@ -223,10 +195,8 @@
 
   /* android.flash. */
 
-  // TODO(b/29394024): query V4L2_CID_FLASH_LED_MODE.
-  uint8_t flash_avail = 0;
   ADD_STATIC_ENTRY(ANDROID_FLASH_INFO_AVAILABLE,
-                   &flash_avail, 1);
+                   &mFlashAvailable, 1);
 
   // info.chargeDuration, color.Temperature, maxEnergy marked FUTURE.
 
@@ -244,7 +214,7 @@
 
   // For now, no thumbnails available (only [0,0], the "no thumbnail" size).
   // TODO(b/29580107): Could end up with a mismatch between request & result,
-  //   since V4L2 doesn't actually allow for thumbnail size control.
+  // since V4L2 doesn't actually allow for thumbnail size control.
   int32_t thumbnail_sizes[] = {
     0, 0};
   ADD_STATIC_ENTRY(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
@@ -259,23 +229,15 @@
 
   /*   Misc. lens control. */
 
-  // No way to actually get the f-value in V4L2, but it's a required key,
-  // so we just fake it. Raspberry Pi camera v2 is f/2.0.
-  float avail_apertures[] = {2.0};
   ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
-                   avail_apertures, ARRAY_SIZE(avail_apertures));
+                   &mAperture, 1);
 
-  // No known V4L2 neutral density filter control.
-  float avail_filter_densities[] = {0.0};
   ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
-                   avail_filter_densities, ARRAY_SIZE(avail_filter_densities));
+                   &mFilterDensity, 1);
 
-  // TODO(b/29394024): query V4L2_CID_IMAGE_STABILIZATION.
-  uint8_t avail_optical_stabilization[] = {
-    ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF};
   ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
-                   avail_optical_stabilization,
-                   ARRAY_SIZE(avail_optical_stabilization));
+                   mOpticalStabilizationModes.data(),
+                   mOpticalStabilizationModes.size());
 
   // No known V4L2 shading map info.
   int32_t shading_map_size[] = {1, 1};
@@ -289,12 +251,9 @@
   /*   Zoom/Focus. */
 
   // No way to actually get the focal length in V4L2, but it's a required key,
-  // so we just fake it. Raspberry Pi camera v2 is 3.04mm.
-  // Note: unlike f values, this key is actually used in calculations
-  //   (field of view), so other cameras may see inaccurate results.
-  float focal_length = 3.04;
+  // so we just fake it.
   ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
-                   &focal_length, 1);
+                   &mFocalLength, 1);
 
   // V4L2 focal units do not correspond to a particular physical unit.
   uint8_t focus_calibration =
@@ -304,26 +263,22 @@
 
   // info.hyperfocalDistance not required for UNCALIBRATED.
 
-  // TODO(b/29394024): query V4L2_CID_ZOOM_ABSOLUTE for focus range.
-  // 0 is fixed focus.
-  float min_focus_distance = 0.0;
   ADD_STATIC_ENTRY(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
-                   &min_focus_distance, 1);
+                   &mFocusDistance, 1);
 
   /*   Depth. */
 
   // DEPTH capability not supported by this HAL. Not implemented:
-  //   poseRotation
-  //   poseTranslation
-  //   intrinsicCalibration
-  //   radialDistortion
+  // poseRotation
+  // poseTranslation
+  // intrinsicCalibration
+  // radialDistortion
 
   /* anroid.noise. */
 
   // Unable to control noise reduction in V4L2 devices,
   // but FAST is allowed to be the same as OFF.
-  uint8_t avail_noise_reduction_modes[] = {
-    ANDROID_NOISE_REDUCTION_MODE_FAST};
+  uint8_t avail_noise_reduction_modes[] = {ANDROID_NOISE_REDUCTION_MODE_FAST};
   ADD_STATIC_ENTRY(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
                    avail_noise_reduction_modes,
                    ARRAY_SIZE(avail_noise_reduction_modes));
@@ -353,83 +308,47 @@
 
   /*   Cropping. */
 
-  // TODO(b/29394024): query VIDIOC_CROPCAP to get cropping ranges,
-  //   and VIDIOC_G_CROP to determine if cropping is supported.
-  //   If the ioctl isn't available (or cropping has non-square pixelaspect),
-  //   assume no cropping/scaling.
-  //   May need to try setting some crops to determine what the driver actually
-  //   supports (including testing center vs freeform).
-  float max_zoom = 1;
   ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
-                   &max_zoom, 1);
+                   &mMaxZoom, 1);
 
-  // V4L2 VIDIOC_CROPCAP doesn't give a way to query this;
-  //   it's driver dependent. For now, assume freeform, and
-  //   some cameras may just behave badly.
-  // TODO(b/29579652): Figure out a way to determine this.
-  uint8_t crop_type = ANDROID_SCALER_CROPPING_TYPE_FREEFORM;
-  ADD_STATIC_ENTRY(ANDROID_SCALER_CROPPING_TYPE, &crop_type, 1);
+  ADD_STATIC_ENTRY(ANDROID_SCALER_CROPPING_TYPE, &mCropType, 1);
 
   /*   Streams. */
 
   // availableInputOutputFormatsMap only required for reprocessing capability.
 
-  // TODO(b/29394024): query VIDIOC_ENUM_FMT to get pixel formats, pull out
-  //   YUV_420_888 and JPEG, query VIDIOC_ENUM_FRAMESIZES on those.
-  // TODO(b/29581206): Need behavior if YUV_420_888 and JPEG aren't available.
-  // For now, just 640x480 JPEG.
-  int32_t avail_stream_configs[] = {
-    HAL_PIXEL_FORMAT_BLOB, 640, 480,
-    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT};
+  // Flatten mStreamConfigs.
   ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-                   avail_stream_configs, ARRAY_SIZE(avail_stream_configs));
+                   mStreamConfigs.data(),
+                   mStreamConfigs.total_num_elements());
 
-  // Per format and size, minimum frame duration (max frame rate).
-  // For now, just 30 fps = 1/30 spf ~= 33333333 ns.
-  //   For whatever reason the goldfish/qcom cameras report this as
-  //   33331760, so copying that.
-  // TODO(b/29394024): query the available format frame rates.
-  int64_t avail_min_frame_durations[] = {
-    HAL_PIXEL_FORMAT_BLOB, 640, 480, 33331760};
+  // Flatten mMinFrameDurations.
   ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
-                   avail_min_frame_durations,
-                   ARRAY_SIZE(avail_min_frame_durations));
+                   mMinFrameDurations.data(),
+                   mMinFrameDurations.total_num_elements());
 
-  // Per format and size, usually 0 for non-jpeg, non-zero for JPEG.
-  // Randomly choosing absurdly long 1 sec for JPEG. Unsure what this breaks.
-  int64_t avail_stall_durations[] = {
-    HAL_PIXEL_FORMAT_BLOB, 640, 480, 1000000000};
+  // Flatten mStallDurations.
   ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
-                   avail_stall_durations, ARRAY_SIZE(avail_stall_durations));
+                   mStallDurations.data(),
+                   mStallDurations.total_num_elements());
 
   /* android.sensor. */
 
   /*   Sizes. */
 
-  // Spoof as 640 x 480 for now.
-  // TODO(b/29394024): query VIDIOC_CROPCAP to get pixel rectangle.
-  int32_t array_rect[] = {
-    /*xmin*/0, /*ymin*/0, /*width*/640, /*height*/480};
   ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
-                   array_rect, ARRAY_SIZE(array_rect));
+                   mPixelArraySize.data(), mPixelArraySize.size());
   // No V4L2 way to differentiate active vs. inactive parts of the rectangle.
   ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
-                   array_rect, ARRAY_SIZE(array_rect));
+                   mPixelArraySize.data(), mPixelArraySize.size());
 
-  // No way to get actual physical size from V4L2. Field of view/pixel pitch
-  // calculations will be off. Using Raspberry Pi camera v2 measurements
-  // (3.674 x 2.760 mm).
-  float physical_size[] = {3.674, 2.760};
   ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
-                   physical_size, ARRAY_SIZE(physical_size));
+                   mPhysicalSize.data(), mPhysicalSize.size());
 
   /*   Misc sensor information. */
 
-  // For now, using the emulator value of .3 sec.
-  // TODO(b/29394024): query for min frame rate.
-  int64_t max_frame_duration = 300000000;
   ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
-                   &max_frame_duration, 1);
+                   &mMaxFrameDuration, 1);
 
   // HAL uses BOOTTIME timestamps.
   // TODO(b/29457051): make sure timestamps are consistent throughout the HAL.
@@ -438,20 +357,19 @@
                    &timestamp_source, 1);
 
   // As in initDeviceInfo, no way to actually get orientation.
-  int32_t orientation = 0;
-  ADD_STATIC_ENTRY(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
+  ADD_STATIC_ENTRY(ANDROID_SENSOR_ORIENTATION, &mOrientation, 1);
 
   // availableTestPatternModes just defaults to OFF, which is fine.
 
   // info.exposureTimeRange, info.sensitivityRange:
-  //   exposure/sensitivity manual control not supported.
-  //   Could query V4L2_CID_ISO_SENSITIVITY to support sensitivity if desired.
+  // exposure/sensitivity manual control not supported.
+  // Could query V4L2_CID_ISO_SENSITIVITY to support sensitivity if desired.
 
   // info.whiteLevel, info.lensShadingApplied,
-  //   info.preCorrectionActiveArraySize, referenceIlluminant1/2,
-  //   calibrationTransform1/2, colorTransform1/2, forwardMatrix1/2,
-  //   blackLevelPattern, profileHueSatMapDimensions
-  //   all only necessary for RAW.
+  // info.preCorrectionPixelArraySize, referenceIlluminant1/2,
+  // calibrationTransform1/2, colorTransform1/2, forwardMatrix1/2,
+  // blackLevelPattern, profileHueSatMapDimensions
+  // all only necessary for RAW.
 
   // baseGainFactor marked FUTURE.
 
@@ -461,6 +379,16 @@
 
   // opaqueRawSize not necessary since RAW_OPAQUE format not supported.
 
+  /* android.shading */
+
+  // No known V4L2 lens shading. But it might be happening,
+  // so we report FAST/HIGH_QUALITY.
+  uint8_t avail_shading_modes[] = {
+    ANDROID_SHADING_MODE_FAST,
+    ANDROID_SHADING_MODE_HIGH_QUALITY};
+  ADD_STATIC_ENTRY(ANDROID_SHADING_AVAILABLE_MODES,
+                   avail_shading_modes, ARRAY_SIZE(avail_shading_modes));
+
   /* android.statistics */
 
   // Face detection not supported.
@@ -475,7 +403,7 @@
                    &max_face_count, 1);
 
   // info.histogramBucketCount, info.maxHistogramCount,
-  //   info.maxSharpnessMapValue, info.sharpnessMapSizemarked FUTURE.
+  // info.maxSharpnessMapValue, info.sharpnessMapSizemarked FUTURE.
 
   // ON only needs to be supported for RAW capable devices.
   uint8_t avail_hot_pixel_map_modes[] = {
@@ -497,17 +425,18 @@
 
   /* android.led. */
 
-  // availableLeds: for now, none available, so no need to set.
-  // TODO(b/29394024): query V4L2_CID_FLASH_INDICATOR_INTENSITY?
-  //   if it's there, assume indicator exists?
+  // May or may not have LEDs available.
+  if (!mLeds.empty()) {
+    ADD_STATIC_ENTRY(ANDROID_LED_AVAILABLE_LEDS, mLeds.data(), mLeds.size());
+  }
 
   /* android.sync. */
 
   // "LIMITED devices are strongly encouraged to use a non-negative value.
-  //   If UNKNOWN is used here then app developers do not have a way to know
-  //   when sensor settings have been applied." - Unfortunately, V4L2 doesn't
-  //   really help here either. Could even be that adjusting settings mid-stream
-  //   blocks in V4L2, and should be avoided.
+  // If UNKNOWN is used here then app developers do not have a way to know
+  // when sensor settings have been applied." - Unfortunately, V4L2 doesn't
+  // really help here either. Could even be that adjusting settings mid-stream
+  // blocks in V4L2, and should be avoided.
   int32_t max_latency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
   ADD_STATIC_ENTRY(ANDROID_SYNC_MAX_LATENCY,
                    &max_latency, 1);
@@ -531,15 +460,45 @@
   ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
                    capabilities, ARRAY_SIZE(capabilities));
 
-  // TODO(b/29221795): available request keys
-  //   (fill in when writing default requests).
+  // Scan a default request template for included request keys.
+  if (!mTemplatesInitialized) {
+    res = initTemplates();
+    if (res) {
+      return res;
+    }
+  }
+  std::vector<int32_t> avail_request_keys;
+  const camera_metadata_t *preview_request = nullptr;
+  // Search templates from the beginning for a supported one.
+  for (uint8_t template_id = 1; template_id < CAMERA3_TEMPLATE_COUNT;
+       ++template_id) {
+    preview_request = constructDefaultRequestSettings(template_id);
+    if (preview_request != nullptr) {
+      break;
+    }
+  }
+  if (preview_request == nullptr) {
+    HAL_LOGE("No valid templates, can't get request keys.");
+    return -ENODEV;
+  }
+  size_t num_entries = get_camera_metadata_entry_count(preview_request);
+  for (size_t i = 0; i < num_entries; ++i) {
+    camera_metadata_ro_entry_t entry;
+    get_camera_metadata_ro_entry(preview_request, i, &entry);
+    avail_request_keys.push_back(entry.tag);
+  }
+  ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
+                   avail_request_keys.data(), avail_request_keys.size());
 
-  // TODO(b/29335262): available result keys
-  //   (fill in when writing actual result capture).
+  // Result keys will be duplicated from the request, plus a few extras.
+  // TODO(b/29335262): additonal available result keys.
+  std::vector<int32_t> avail_result_keys(avail_request_keys);
+  ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
+                   avail_result_keys.data(), avail_result_keys.size());
 
   // Last thing, once all the available characteristics have been added.
   info.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
-              &avail_characteristics_keys[0],
+              avail_characteristics_keys.data(),
               avail_characteristics_keys.size());
 
   *out = info.release();
@@ -551,7 +510,7 @@
 
   // For now, just constants.
   info->facing = CAMERA_FACING_EXTERNAL;
-  info->orientation = 0;
+  info->orientation = mOrientation;
   info->resource_cost = 100;
   info->conflicting_devices = nullptr;
   info->conflicting_devices_length = 0;
@@ -559,16 +518,548 @@
 
 int V4L2Camera::initDevice() {
   HAL_LOG_ENTER();
+  int res;
 
-  // TODO(b/29221795): fill in templates, etc.
+  // Templates should be set up if they haven't already been.
+  if (!mTemplatesInitialized) {
+    res = initTemplates();
+    if (res) {
+      return res;
+    }
+  }
+
+  return 0;
+}
+
+int V4L2Camera::initTemplates() {
+  HAL_LOG_ENTER();
+  int res;
+
+  // Device characteristics need to be queried prior
+  // to template setup.
+  if (!mCharacteristicsInitialized) {
+    res = initCharacteristics();
+    if (res) {
+      return res;
+    }
+  }
+
+  // Note: static metadata expects all templates/requests
+  // to provide values for all supported keys.
+
+  android::CameraMetadata template_metadata;
+#define ADD_REQUEST_ENTRY(name, varptr, count) \
+  res = template_metadata.update(name, varptr, count); \
+  if (res != android::OK) return res
+
+  // Start with defaults for all templates.
+
+  /* android.colorCorrection. */
+
+  uint8_t aberration_mode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+                    &aberration_mode, 1);
+
+  uint8_t color_correction_mode = ANDROID_COLOR_CORRECTION_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_COLOR_CORRECTION_MODE,
+                    &color_correction_mode, 1);
+
+  // transform and gains are for the unsupported MANUAL_POST_PROCESSING only.
+
+  /* android.control. */
+
+  /*   AE. */
+  uint8_t ae_antibanding_mode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+                    &ae_antibanding_mode, 1);
+
+  // Only matters if AE_MODE = OFF
+  int32_t ae_exposure_compensation = 0;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+                    &ae_exposure_compensation, 1);
+
+  uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+  uint8_t ae_mode = ANDROID_CONTROL_AE_MODE_ON;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_MODE, &ae_mode, 1);
+
+  // AE regions not supported.
+
+  // FPS set per-template.
+
+  uint8_t ae_precapture_trigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+                    &ae_precapture_trigger, 1);
+
+  /*   AF. */
+
+  // AF mode set per-template.
+
+  // AF regions not supported.
+
+  uint8_t af_trigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AF_TRIGGER, &af_trigger, 1);
+
+  /*   AWB. */
+
+  // Priority: auto > off > Whatever is available.
+  uint8_t default_awb_mode = mAwbModes[0];
+  if (std::count(mAwbModes.begin(), mAwbModes.end(),
+                ANDROID_CONTROL_AWB_MODE_AUTO)) {
+    default_awb_mode = ANDROID_CONTROL_AWB_MODE_AUTO;
+  } else if (std::count(mAwbModes.begin(), mAwbModes.end(),
+                       ANDROID_CONTROL_AWB_MODE_OFF)) {
+    default_awb_mode = ANDROID_CONTROL_AWB_MODE_OFF;
+  }
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_AWB_MODE, &default_awb_mode, 1);
+
+  // AWB regions not supported.
+
+  /*   Other controls. */
+
+  uint8_t effect_mode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_EFFECT_MODE, &effect_mode, 1);
+
+  uint8_t control_mode = ANDROID_CONTROL_MODE_AUTO;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_MODE, &control_mode, 1);
+
+  uint8_t scene_mode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_SCENE_MODE,
+                    &scene_mode, 1);
+
+  uint8_t video_stabilization = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                    &video_stabilization, 1);
+
+  // postRawSensitivityBoost: RAW not supported, leave null.
+
+  /* android.demosaic. */
+
+  // mode marked FUTURE.
+
+  /* android.edge. */
+
+  uint8_t edge_mode = ANDROID_EDGE_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_EDGE_MODE, &edge_mode, 1);
+
+  // strength marked FUTURE.
+
+  /* android.flash. */
+
+  // firingPower, firingTime marked FUTURE.
+
+  uint8_t flash_mode = ANDROID_FLASH_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_FLASH_MODE, &flash_mode, 1);
+
+  /* android.hotPixel. */
+
+  uint8_t hp_mode = ANDROID_HOT_PIXEL_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_HOT_PIXEL_MODE, &hp_mode, 1);
+
+  /* android.jpeg. */
+
+  double gps_coords[] = {/*latitude*/0, /*longitude*/0, /*altitude*/0};
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_GPS_COORDINATES, gps_coords, 3);
+
+  uint8_t gps_processing_method[] = "none";
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_GPS_PROCESSING_METHOD,
+                    gps_processing_method, ARRAY_SIZE(gps_processing_method));
+
+  int64_t gps_timestamp = 0;
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_GPS_TIMESTAMP, &gps_timestamp, 1);
+
+  // JPEG orientation is relative to sensor orientation (mOrientation).
+  int32_t jpeg_orientation = 0;
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_ORIENTATION, &jpeg_orientation, 1);
+
+  // 1-100, larger is higher quality.
+  uint8_t jpeg_quality = 80;
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_QUALITY, &jpeg_quality, 1);
+
+  // TODO(b/29580107): If thumbnail quality actually matters/can be adjusted,
+  // adjust this.
+  uint8_t thumbnail_quality = 80;
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnail_quality, 1);
+
+  // TODO(b/29580107): Choose a size matching the resolution.
+  int32_t thumbnail_size[] = {0, 0};
+  ADD_REQUEST_ENTRY(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnail_size, 2);
+
+  /* android.lens. */
+
+  // Fixed values.
+  ADD_REQUEST_ENTRY(ANDROID_LENS_APERTURE, &mAperture, 1);
+  ADD_REQUEST_ENTRY(ANDROID_LENS_FILTER_DENSITY, &mFilterDensity, 1);
+  ADD_REQUEST_ENTRY(ANDROID_LENS_FOCAL_LENGTH, &mFocalLength, 1);
+  ADD_REQUEST_ENTRY(ANDROID_LENS_FOCUS_DISTANCE, &mFocusDistance, 1);
+
+  uint8_t optical_stabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+                    &optical_stabilization, 1);
+
+  /* android.noiseReduction. */
+
+  uint8_t noise_reduction_mode = ANDROID_NOISE_REDUCTION_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_NOISE_REDUCTION_MODE, &noise_reduction_mode, 1);
+
+  // strength marked FUTURE.
+
+  /* android.request. */
+
+  // Request Id unused by the HAL for now, and these are just
+  // templates, so just fill it in with a dummy.
+  int32_t id = 0;
+  ADD_REQUEST_ENTRY(ANDROID_REQUEST_ID, &id, 1);
+
+  // metadataMode marked FUTURE.
+
+  /* android.scaler. */
+
+  // No cropping by default; use the full active array.
+  ADD_REQUEST_ENTRY(ANDROID_SCALER_CROP_REGION, mPixelArraySize.data(),
+                    mPixelArraySize.size());
+
+  /* android.sensor. */
+
+  // exposureTime, sensitivity, testPattern[Data,Mode] not supported.
+
+  // Ignored when AE is OFF.
+  int64_t frame_duration = 33333333L; // 1/30 s.
+  ADD_REQUEST_ENTRY(ANDROID_SENSOR_FRAME_DURATION, &frame_duration, 1);
+
+  /* android.shading. */
+
+  uint8_t shading_mode = ANDROID_SHADING_MODE_FAST;
+  ADD_REQUEST_ENTRY(ANDROID_SHADING_MODE, &shading_mode, 1);
+
+  /* android.statistics. */
+
+  uint8_t face_detect_mode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_STATISTICS_FACE_DETECT_MODE, &face_detect_mode, 1);
+
+  // histogramMode, sharpnessMapMode marked FUTURE.
+
+  uint8_t hp_map_mode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hp_map_mode, 1);
+
+  uint8_t lens_shading_map_mode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+  ADD_REQUEST_ENTRY(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+                    &lens_shading_map_mode, 1);
+
+  /* android.tonemap. */
+
+  // Tonemap only required for MANUAL_POST_PROCESSING capability.
+
+  /* android.led. */
+
+  uint8_t transmit = ANDROID_LED_TRANSMIT_ON;
+  ADD_REQUEST_ENTRY(ANDROID_LED_TRANSMIT, &transmit, 1);
+
+  /* android.reprocess */
+
+  // Only needed for REPROCESS capability.
+
+
+  /* Template variable values. */
+
+  // Find the FPS ranges "closest" to a desired range
+  // (minimum abs distance from min to min and max to max).
+  // Find both a fixed rate and a variable rate, for different purposes.
+  std::array<int32_t, 2> desired_flat_fps_range = {{30, 30}};
+  std::array<int32_t, 2> desired_variable_fps_range = {{5, 30}};
+  std::array<int32_t, 2> flat_fps_range;
+  std::array<int32_t, 2> variable_fps_range;
+  int32_t best_flat_distance = std::numeric_limits<int32_t>::max();
+  int32_t best_variable_distance = std::numeric_limits<int32_t>::max();
+  size_t num_fps_ranges = mFpsRanges.num_arrays();
+  for (size_t i = 0; i < num_fps_ranges; ++i) {
+    const int32_t* range = mFpsRanges[i];
+    // Variable fps.
+    int32_t distance = std::abs(range[0] - desired_variable_fps_range[0]) +
+        std::abs(range[1] - desired_variable_fps_range[1]);
+    if (distance < best_variable_distance) {
+      variable_fps_range[0] = range[0];
+      variable_fps_range[1] = range[1];
+      best_variable_distance = distance;
+    }
+    // Flat fps. Only do if range is actually flat.
+    // Note at least one flat range is required,
+    // so something will always be filled in.
+    if (range[0] == range[1]) {
+      distance = std::abs(range[0] - desired_flat_fps_range[0]) +
+          std::abs(range[1] - desired_flat_fps_range[1]);
+      if (distance < best_flat_distance) {
+        flat_fps_range[0] = range[0];
+        flat_fps_range[1] = range[1];
+        best_flat_distance = distance;
+      }
+    }
+  }
+
+  // Priority: continuous > auto > off > whatever is available.
+  bool continuous_still_avail = std::count(
+      mAfModes.begin(), mAfModes.end(),
+      ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+  bool continuous_video_avail = std::count(
+      mAfModes.begin(), mAfModes.end(),
+      ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO);
+  uint8_t non_continuous_af_mode = mAfModes[0];
+  if (std::count(mAfModes.begin(), mAfModes.end(),
+                       ANDROID_CONTROL_AF_MODE_AUTO)) {
+    non_continuous_af_mode = ANDROID_CONTROL_AF_MODE_AUTO;
+  } else if (std::count(mAfModes.begin(), mAfModes.end(),
+                       ANDROID_CONTROL_AF_MODE_OFF)) {
+    non_continuous_af_mode = ANDROID_CONTROL_AF_MODE_OFF;
+  }
+  uint8_t still_af_mode = continuous_still_avail ?
+      ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE : non_continuous_af_mode;
+  uint8_t video_af_mode =  continuous_video_avail ?
+      ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO : non_continuous_af_mode;
+
+  // Copy our base metadata (note: we do it in this direction so we don't have
+  // to redefine our ADD_REQUEST_ENTRY macro).
+  android::CameraMetadata base_metadata(template_metadata);
+
+  for (uint8_t template_id = 1; template_id < CAMERA3_TEMPLATE_COUNT; ++template_id) {
+    // General differences/support.
+    uint8_t intent;
+    uint8_t af_mode;
+    std::array<int32_t, 2> fps_range;
+    switch(template_id) {
+      case CAMERA3_TEMPLATE_PREVIEW:
+        intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+        af_mode = still_af_mode;
+        fps_range = flat_fps_range;
+        break;
+      case CAMERA3_TEMPLATE_STILL_CAPTURE:
+        intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+        af_mode = still_af_mode;
+        fps_range = variable_fps_range;
+        break;
+      case CAMERA3_TEMPLATE_VIDEO_RECORD:
+        intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+        af_mode = video_af_mode;
+        fps_range = flat_fps_range;
+        break;
+      case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+        intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+        af_mode = video_af_mode;
+        fps_range = flat_fps_range;
+        break;
+      case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:  // Fall through.
+      case CAMERA3_TEMPLATE_MANUAL:  // Fall though.
+      default:
+        // Unsupported/unrecognized. Don't add this template; skip it.
+        continue;
+    }
+
+    ADD_REQUEST_ENTRY(ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
+    ADD_REQUEST_ENTRY(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+                      fps_range.data(), fps_range.size());
+    ADD_REQUEST_ENTRY(ANDROID_CONTROL_AF_MODE, &af_mode, 1);
+
+    const camera_metadata_t* template_raw_metadata =
+        template_metadata.getAndLock();
+    res = setTemplate(template_id, template_raw_metadata);
+    if (res != android::OK) {
+      return res;
+    }
+    res = template_metadata.unlock(template_raw_metadata);
+    if (res != android::OK) {
+      return res;
+    }
+
+    // Reset the template metadata to the base.
+    template_metadata = base_metadata;
+  }
+
+  mTemplatesInitialized = true;
   return 0;
 }
 
 bool V4L2Camera::isValidCaptureSettings(const camera_metadata_t* settings) {
   HAL_LOG_ENTER();
 
-  // TODO(b): reject capture settings this camera isn't capable of.
+  // TODO(b/29335262): reject capture settings this camera isn't capable of.
   return true;
 }
 
+int V4L2Camera::initCharacteristics() {
+  HAL_LOG_ENTER();
+
+  /* Physical characteristics. */
+  // No way to get these in V4L2, so faked.
+  // Note: While many of these are primarily informative for post-processing
+  // calculations by the app and will potentially cause bad results there,
+  // focal length and physical size are actually used in framework
+  // calculations (field of view, pixel pitch, etc), so faking them may
+  // have unexpected results.
+  mAperture = 2.0;  // RPi camera v2 is f/2.0.
+  mFilterDensity = 0.0;
+  mFocalLength = 3.04;  // RPi camera v2 is 3.04mm.
+  mOrientation = 0;
+  mPhysicalSize = {{3.674, 2.760}};  // RPi camera v2 is 3.674 x 2.760 mm.
+
+  /* Fixed features. */
+
+  // TODO(b/29394024): query VIDIOC_CROPCAP to get pixel rectangle.
+  // Spoofing as 640 x 480 for now.
+  mPixelArraySize = {{/*xmin*/0, /*ymin*/0, /*width*/640, /*height*/480}};
+
+  // V4L2 VIDIOC_CROPCAP doesn't give a way to query this;
+  // it's driver dependent. For now, assume freeform, and
+  // some cameras may just behave badly.
+  // TODO(b/29579652): Figure out a way to determine this.
+  mCropType = ANDROID_SCALER_CROPPING_TYPE_FREEFORM;
+
+  // TODO(b/29394024): query VIDIOC_CROPCAP to get cropping ranges,
+  // and VIDIOC_G_CROP to determine if cropping is supported.
+  // If the ioctl isn't available (or cropping has non-square pixelaspect),
+  // assume no cropping/scaling.
+  // May need to try setting some crops to determine what the driver actually
+  // supports (including testing center vs freeform).
+  mMaxZoom = 1;
+
+  // TODO(b/29394024): query V4L2_CID_EXPOSURE_BIAS.
+  mAeCompensationRange = {{0, 0}};
+  mAeCompensationStep = {1, 1};
+
+  // TODO(b/29394024): query V4L2_CID_3A_LOCK.
+  mAeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
+  mAwbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+
+  // TODO(b/29394024): query V4L2_CID_FLASH_LED_MODE.
+  mFlashAvailable = 0;
+
+  // TODO(b/29394024): query V4L2_CID_FOCUS_ABSOLUTE for focus range.
+  mFocusDistance = 0;  // Fixed focus.
+
+  /* Features with (potentially) multiple options. */
+
+  // TODO(b/29394024): query V4L2_CID_EXPOSURE_AUTO for ae modes.
+  mAeModes.push_back(ANDROID_CONTROL_AE_MODE_ON);
+
+  // TODO(b/29394024): query V4L2_CID_POWER_LINE_FREQUENCY.
+  // Auto as the default, since it could mean anything, while OFF would
+  // require guaranteeing no antibanding happens.
+  mAeAntibandingModes.push_back(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO);
+
+  // TODO(b/29394024): query V4L2_CID_FOCUS_AUTO for
+  // CONTINUOUS_VIDEO/CONTINUOUS_PICTURE. V4L2_CID_AUTO_FOCUS_START
+  // supports what Android thinks of as auto focus (single auto focus).
+  // V4L2_CID_AUTO_FOCUS_RANGE allows MACRO.
+  mAfModes.push_back(ANDROID_CONTROL_AF_MODE_OFF);
+
+  // TODO(b/29394024): query V4L2_CID_AUTO_WHITE_BALANCE, or
+  // V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE if available.
+  mAwbModes.push_back(ANDROID_CONTROL_AWB_MODE_AUTO);
+
+  // TODO(b/29394024): query V4L2_CID_SCENE_MODE.
+  mSceneModes.push_back(ANDROID_CONTROL_SCENE_MODE_DISABLED);
+
+  mControlModes.push_back(ANDROID_CONTROL_MODE_AUTO);
+  if (mSceneModes.size() > 1) {
+    // We have some mode other than just DISABLED available.
+    mControlModes.push_back(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+  }
+
+  // TODO(b/29394024): query V4L2_CID_COLORFX.
+  mEffects.push_back(ANDROID_CONTROL_EFFECT_MODE_OFF);
+
+  // TODO(b/29394024): query V4L2_CID_FLASH_INDICATOR_INTENSITY.
+  // For now, no indicator LED available; nothing to push back.
+  // When there is, push back ANDROID_LED_AVAILABLE_LEDS_TRANSMIT.
+
+  // TODO(b/29394024): query V4L2_CID_IMAGE_STABILIZATION.
+  mOpticalStabilizationModes.push_back(
+      ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF);
+  mVideoStabilizationModes.push_back(
+      ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+
+  // Need to support YUV_420_888 and JPEG.
+  // TODO(b/29394024): query VIDIOC_ENUM_FMT.
+  std::vector<uint32_t> formats = {{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420}};
+  int32_t hal_format;
+  // We want to find the smallest maximum frame duration amongst formats.
+  mMaxFrameDuration = std::numeric_limits<int64_t>::max();
+  int64_t min_yuv_frame_duration = std::numeric_limits<int64_t>::max();
+  for (auto format : formats) {
+    // Translate V4L2 format to HAL format.
+    switch (format) {
+      case V4L2_PIX_FMT_JPEG:
+        hal_format = HAL_PIXEL_FORMAT_BLOB;
+        break;
+      case V4L2_PIX_FMT_YUV420:
+        hal_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+      default:
+        // Unrecognized/unused format. Skip it.
+        continue;
+    }
+
+    // TODO(b/29394024): query VIDIOC_ENUM_FRAMESIZES.
+    // For now, just 640x480.
+    ArrayVector<int32_t, 2> frame_sizes;
+    frame_sizes.push_back({{640, 480}});
+    size_t num_frame_sizes = frame_sizes.num_arrays();
+    for (size_t i = 0; i < num_frame_sizes; ++i) {
+      const int32_t* frame_size = frame_sizes[i];
+      mStreamConfigs.push_back({{hal_format, frame_size[0], frame_size[1],
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}});
+
+      // TODO(b/29394024): query VIDIOC_ENUM_FRAMEINTERVALS.
+      // For now, using the emulator max value of .3 sec.
+      int64_t max_frame_duration = 300000000;
+      // For now, min value of 30 fps = 1/30 spf ~= 33333333 ns.
+      // For whatever reason the goldfish/qcom cameras report this as
+      // 33331760, so copying that.
+      int64_t min_frame_duration = 33331760;
+
+      mMinFrameDurations.push_back(
+          {{hal_format, frame_size[0], frame_size[1], min_frame_duration}});
+
+      // In theory max frame duration (min frame rate) should be consistent
+      // between all formats, but we check and only advertise the smallest
+      // available max duration just in case.
+      if (max_frame_duration < mMaxFrameDuration) {
+        mMaxFrameDuration = max_frame_duration;
+      }
+
+      // We only care about min frame duration (max frame rate) for YUV.
+      if (hal_format == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+          min_frame_duration < min_yuv_frame_duration) {
+        min_yuv_frame_duration = min_frame_duration;
+      }
+
+      // Usually 0 for non-jpeg, non-zero for JPEG.
+      // Randomly choosing absurd 1 sec for JPEG. Unsure what this breaks.
+      int64_t stall_duration = 0;
+      if (hal_format == HAL_PIXEL_FORMAT_BLOB) {
+        stall_duration =  1000000000;
+      }
+      mStallDurations.push_back(
+          {{hal_format, frame_size[0], frame_size[1], stall_duration}});
+    }
+  }
+
+  // This should be at minimum {mi, ma}, {ma, ma} where mi and ma
+  // are min and max frame rates for YUV_420_888. Min should be at most 15.
+  // Convert from frame durations measured in ns.
+  int32_t min_yuv_fps = 1000000000 / mMaxFrameDuration;
+  if (min_yuv_fps > 15) {
+    return -ENODEV;
+  }
+  int32_t max_yuv_fps = 1000000000 / min_yuv_frame_duration;
+  mFpsRanges.push_back({{min_yuv_fps, max_yuv_fps}});
+  mFpsRanges.push_back({{max_yuv_fps, max_yuv_fps}});
+  // Always advertise {30, 30} if max is even higher,
+  // since this is what the default video requests use.
+  if (max_yuv_fps > 30) {
+    mFpsRanges.push_back({{30, 30}});
+  }
+
+  mCharacteristicsInitialized = true;
+  return 0;
+}
+
 } // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/V4L2Camera.h b/modules/camera/3_4/V4L2Camera.h
index ff7275a..7aece03 100644
--- a/modules/camera/3_4/V4L2Camera.h
+++ b/modules/camera/3_4/V4L2Camera.h
@@ -19,11 +19,14 @@
 #ifndef V4L2_CAMERA_H
 #define V4L2_CAMERA_H
 
+#include <array>
 #include <string>
+#include <vector>
 
 #include <nativehelper/ScopedFd.h>
 #include <system/camera_metadata.h>
 
+#include "ArrayVector.h"
 #include "Camera.h"
 #include "Common.h"
 
@@ -58,6 +61,50 @@
   // The opened device fd.
   ScopedFd mDeviceFd;
 
+  bool mTemplatesInitialized;
+  int initTemplates();
+
+  // Camera characteristics.
+  bool mCharacteristicsInitialized;  // If false, characteristics are invalid.
+  // Fixed characteristics.
+  float mAperture;
+  float mFilterDensity;
+  float mFocalLength;
+  int32_t mOrientation;
+  std::array<float, 2> mPhysicalSize;  // {width, height}, in mm.
+  std::array<int32_t, 4> mPixelArraySize;  // {xmin, ymin, width, height}.
+  uint8_t mCropType;
+  float mMaxZoom;
+  std::array<int32_t, 2> mAeCompensationRange;  // {min, max}.
+  camera_metadata_rational mAeCompensationStep;
+  uint8_t mAeLockAvailable;
+  uint8_t mAwbLockAvailable;
+  uint8_t mFlashAvailable;
+  float mFocusDistance;
+  // Variable characteristics available options.
+  std::vector<uint8_t> mAeModes;
+  std::vector<uint8_t> mAeAntibandingModes;
+  std::vector<uint8_t> mAfModes;
+  std::vector<uint8_t> mAwbModes;
+  std::vector<uint8_t> mSceneModes;
+  std::vector<uint8_t> mControlModes;
+  std::vector<uint8_t> mEffects;
+  std::vector<uint8_t> mLeds;
+  std::vector<uint8_t> mOpticalStabilizationModes;
+  std::vector<uint8_t> mVideoStabilizationModes;
+  // {format, width, height, direction} (input or output).
+  ArrayVector<int32_t, 4> mStreamConfigs;
+  // {format, width, height, duration} (duration in ns).
+  ArrayVector<int64_t, 4> mMinFrameDurations;
+  int64_t mMaxFrameDuration;
+  // {format, width, height, duration} (duration in ns).
+  ArrayVector<int64_t, 4> mStallDurations;
+  // {min, max} (in fps).
+  ArrayVector<int32_t, 2> mFpsRanges;
+
+  // Initialize characteristics and set mCharacteristicsInitialized to True.
+  int initCharacteristics();
+
   DISALLOW_COPY_AND_ASSIGN(V4L2Camera);
 };