Add DaydreamVR native libraries and services

Upstreaming the main VR system components from master-dreamos-dev
into goog/master.

Bug: None
Test: `m -j32` succeeds. Sailfish boots and basic_vr sample app works
Change-Id: I853015872afc443aecee10411ef2d6b79184d051
diff --git a/libs/vr/libgvr/.clang-format b/libs/vr/libgvr/.clang-format
new file mode 100644
index 0000000..3287160
--- /dev/null
+++ b/libs/vr/libgvr/.clang-format
@@ -0,0 +1,2 @@
+Language: Cpp
+DisableFormat: true
diff --git a/libs/vr/libgvr/Android.mk b/libs/vr/libgvr/Android.mk
new file mode 100644
index 0000000..bcb3961
--- /dev/null
+++ b/libs/vr/libgvr/Android.mk
@@ -0,0 +1,126 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_dirs := \
+  $(LOCAL_PATH)/include \
+  $(LOCAL_PATH)/prebuilt/include
+
+# Java platform library for the system implementation of the GVR API.
+include $(CLEAR_VARS)
+LOCAL_MODULE := gvr_platform
+LOCAL_MODULE_STEM := com.google.vr.gvr.platform
+LOCAL_REQUIRED_MODULES := libgvr_system_loader libgvr_system
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+include $(BUILD_JAVA_LIBRARY)
+
+# Library to perform dlopen on the actual platform library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_system_loader
+LOCAL_SRC_FILES := library_loader.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library implementing the GVR API.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_system
+
+LOCAL_SRC_FILES := \
+    shim_gvr.cpp \
+    shim_gvr_controller.cpp \
+    shim_gvr_private.cpp \
+    deviceparams/CardboardDevice.nolite.proto
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+LOCAL_C_INCLUDES := $(include_dirs)
+LOCAL_C_INCLUDES += $(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(include_dirs)
+
+gvr_api_linker_script := $(LOCAL_PATH)/exported_apis.lds
+LOCAL_ADDITIONAL_DEPENDENCIES := $(gvr_api_linker_script)
+
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
+LOCAL_LDFLAGS += -Wl,-version-script,$(gvr_api_linker_script)
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid_runtime \
+    libbase \
+    libbinder \
+    libcutils \
+    libutils \
+    libgui \
+    libui \
+    libEGL \
+    libGLESv2 \
+    libvulkan \
+    libhardware \
+    liblog \
+    libsync \
+    libevent \
+    libprotobuf-cpp-full
+
+LOCAL_STATIC_LIBRARIES := \
+    libdisplay \
+    libbufferhub \
+    libbufferhubqueue \
+    libchrome \
+    libdvrcommon \
+    libeds \
+    libdvrgraphics \
+    libsensor \
+    libperformance \
+    libpdx_default_transport \
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Prebuilt shared library for libgvr_audio.so
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_audio
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MULTILIB := both
+LOCAL_SRC_FILES_arm := prebuilt/lib/android_arm/libgvr_audio.so
+LOCAL_SRC_FILES_arm64 := prebuilt/lib/android_arm64/libgvr_audio.so
+include $(BUILD_PREBUILT)
+
+# Prebuilt shared library for libgvr.so
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/prebuilt/include
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MULTILIB := both
+LOCAL_SRC_FILES_arm := prebuilt/lib/android_arm/libgvr.so
+LOCAL_SRC_FILES_arm64 := prebuilt/lib/android_arm64/libgvr.so
+include $(BUILD_PREBUILT)
+
+# Prebuilt Java static library for common_library.aar
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+    gvr_common_library_aar:prebuilt/lib/common_library.aar
+include $(BUILD_MULTI_PREBUILT)
+
+# Dummy libgvr_ext to be used along side libgvr.so prebuilt.
+# This shall be replaced with Google3 prebuilts in future.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgvr_ext
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SRC_FILES := dummy_gvr_ext.cpp
+LOCAL_STATIC_LIBRARIES := libchrome
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES += libgvr
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/vr/libgvr/CPPLINT.cfg b/libs/vr/libgvr/CPPLINT.cfg
new file mode 100644
index 0000000..2da1c50
--- /dev/null
+++ b/libs/vr/libgvr/CPPLINT.cfg
@@ -0,0 +1 @@
+filter=-build/header_guard,-build/include_alpha
diff --git a/libs/vr/libgvr/README.dreamos b/libs/vr/libgvr/README.dreamos
new file mode 100644
index 0000000..d847210
--- /dev/null
+++ b/libs/vr/libgvr/README.dreamos
@@ -0,0 +1 @@
+Files under public/vr/gvr were imported from the public Google VR SDK.
diff --git a/libs/vr/libgvr/com.google.vr.gvr.platform.xml b/libs/vr/libgvr/com.google.vr.gvr.platform.xml
new file mode 100644
index 0000000..9297c7f
--- /dev/null
+++ b/libs/vr/libgvr/com.google.vr.gvr.platform.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<permissions>
+    <library name="com.google.vr.gvr.platform"
+             file="/system/framework/com.google.vr.gvr.platform.jar" />
+</permissions>
diff --git a/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto b/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto
new file mode 100644
index 0000000..77b5d72
--- /dev/null
+++ b/libs/vr/libgvr/deviceparams/CardboardDevice.nolite.proto
@@ -0,0 +1,299 @@
+
+syntax = "proto2";
+
+option java_package = "com.google.vrtoolkit.cardboard.proto";
+option java_outer_classname = "CardboardDevice";
+option optimize_for = SPEED;
+
+package proto;
+
+
+/**
+ * Message describing properties of a VR head mount device (HMD) which uses an
+ * interchangeable smartphone as a display (e.g. Google Cardboard).
+ *
+ * While some properties are certain (e.g. inter_lens_distance), others
+ * represent nominal values which may be refined depending on context (e.g.
+ * viewport_angles).
+ *
+ * Lengths are in meters unless noted otherwise.  Fields are _required_
+ * unless noted otherwise.
+ *
+ * Some context on why this set of parameters are deemed necessary and
+ * sufficient:
+ *    * FOV scale can be reasonably approximated from lens-to-screen distance
+ *      and display size (i.e. knowing lens focal length isn't crucial).
+ *    * Lenses are assumed to be horizontally centered with respect to
+ *      display.
+ *    * The display is not necessarily vertically centered.  For interchangeable
+ *      phones where the device rests against a tray, we can derive
+ *      the vertical offset from tray-to-lens height along with phone-specific
+ *      bezel and screen sizes (supplied separately).
+ */
+message DeviceParams {
+  // String identifying the device's vendor (e.g. "Google, Inc.").
+  // A device's [vendor, model] pair is expected to be globally unique.
+  optional string vendor = 1;
+
+  // String identifying the device's model, including revision info if
+  // needed (e.g. "Cardboard v1").  A device's [vendor, model] pair is
+  // expected to be globally unique.
+  optional string model = 2;
+
+  // Distance from the display screen to the optical center of lenses.
+  // This is a required field for distortion rendering, and must be positive.
+  optional float screen_to_lens_distance = 3;
+
+  // Horizontal distance between optical center of the lenses.
+  // This is a required field for distortion rendering, and must be positive.
+  optional float inter_lens_distance = 4;
+
+  // Four-element tuple (left, right, bottom, top) of left eye's view extent
+  // angles relative to center, assuming the following:
+  //     * eye is aligned with optical center of lens
+  //     * display screen is equal or larger than extents viewable through lens
+  //     * nominal eye-to-lens distance
+  //     * mirrored field of view will be applied to the right eye
+  // These values are essentially used as an optimization to avoid rendering
+  // pixels which can't be seen.
+  // This is a required field for distortion rendering, and angles must be
+  // positive.
+  repeated float left_eye_field_of_view_angles = 5 [packed = true];
+
+  enum VerticalAlignmentType {
+    BOTTOM = 0;  // phone rests against a fixed bottom tray
+    CENTER = 1;  // phone screen assumed to be centered w.r.t. lenses
+    TOP = 2;     // phone rests against a fixed top tray
+  }
+
+  // Set according to vertical alignment strategy-- see enum comments above.
+  // NOTE: If you set this to CENTER, see special instructions for the
+  // tray_to_lens_distance field below.
+  optional VerticalAlignmentType vertical_alignment = 11 [default = BOTTOM];
+
+  // If the phone is aligned vertically within the device by resting against
+  // a fixed top or bottom tray, this is the distance from the tray to
+  // optical center of the lenses.
+  // This is a required field for distortion rendering, and must be positive.
+  // NOTE: Due to a bug in initial versions of the SDK's, this field
+  // must be set explicitly to .035 when vertical_alignment = CENTER.
+  optional float tray_to_lens_distance = 6;
+
+  // Coefficients Ki for pincushion distortion function which maps
+  // from position on real screen to virtual screen (i.e. texture) relative
+  // to optical center:
+  //
+  //    p' = p (1 + K1 r^2 + K2 r^4 + ... + Kn r^(2n))
+  //
+  // where r is the distance in tan-angle units from the optical center,
+  // p the input point, and p' the output point.  Tan-angle units can be
+  // computed as distance on the screen divided by distance from the
+  // virtual eye to the screen.
+  repeated float distortion_coefficients = 7 [packed = true];
+  // Slots 8, 9 reserved for per-color channel distortion.
+
+  // Optionally, whether the head mount uses a magnet in any part of its
+  // design.  Intended as hint as to whether phone's magnetometer is
+  // available for tasks such as orientation tracking.
+  optional bool has_magnet = 10;
+
+  enum ButtonType {
+    // No physical button, and touch screen is not easily accessible.
+    NONE = 0;
+    // HMD has integrated magnet switch similar to original Cardboard.
+    MAGNET = 1;
+    // At least a portion of touch screen is easily accessible to user for taps.
+    TOUCH = 2;
+    // Touch screen is triggered indirectly via integrated button on the HMD.
+    INDIRECT_TOUCH = 3;
+  }
+
+  // Specify primary input mechanism of the HMD.  Intended for advisory
+  // purposes only, to address simple questions such as "can HMD
+  // be used with apps requiring a physical button event?" or "what icon
+  // should be used to represent button action to the user?".
+  optional ButtonType primary_button = 12 [default = MAGNET];
+
+  // Some internal data for Cardboard.  This data is not intended to be
+  // set or used by developers, and any data in this proto is not guaranteed
+  // to be supported with new SDK updates.
+  optional CardboardInternalParams internal = 1729;
+
+  // Optionally, specifies the additional parameters that are necessary for
+  // a Daydream-ready headset. This field is non-null if the headset is
+  // Daydream-ready.
+  // TODO(b/30112366) The inclusion of this message inside a DeviceParams is a
+  // somewhat ugly result of some historical choices in the SDK. We should
+  // consider refactoring our code to allow us to remove this, and the
+  // CardboardInternalParams messages from this proto.
+  optional DaydreamInternalParams daydream_internal = 196883;
+}
+
+// TODO(b/27108179): CardboardInternalParams should be migrated into its own
+// file, and not live in this file.
+
+/**
+ * Message describing parameters that are used internally by Cardboard
+ * and VRToolkit. These parameters don't necessarily fit into the DeviceParams
+ * notion of a VR viewer combined with user's phone (e.g. case of viewer with
+ * dedicated display, etc.) and are not intended to be used by developers
+ * and may or may not be supported or changed without notice on new releases
+ * of the Cardboard SDK or VR Toolkit.
+ */
+message CardboardInternalParams {
+  // Used to specify a per-eye post-process transformation -- an optional
+  // rotation and x-axis reflection -- to be applied after distortion
+  // correction.
+  enum OrientationType {
+    CCW_0_DEGREES = 0;
+    CCW_90_DEGREES = 1;
+    CCW_180_DEGREES = 2;
+    CCW_270_DEGREES = 3;
+    CCW_0_DEGREES_MIRRORED = 4;
+    CCW_90_DEGREES_MIRRORED = 5;
+    CCW_180_DEGREES_MIRRORED = 6;
+    CCW_270_DEGREES_MIRRORED = 7;
+  }
+
+  // Specify a post-process transformation that is applied after the distortion
+  // function. This field is optional, if not specified, CCW_0_DEGREES is
+  // assumed. If repeated, the first orientation is for the left eye, the second
+  // is for the right eye.
+  //
+  // For example, if [CCW_90_DEGREES, CCW_270_DEGREES_MIRRORED] is specified,
+  //
+  // this input:
+  //
+  // ***************** *****************
+  // *1             2* *1             2*
+  // *      *        * *      ***      *
+  // *      *        * *      * *      *
+  // *      ****     * *      *  *     *
+  // *4             3* *4             3*
+  // ***************** *****************
+  //
+  // is rendered on the screen like this:
+  //
+  // ***************** *****************
+  // *2       *     3* *3     *       2*
+  // *        *      * *       **      *
+  // *        *      * *        *      *
+  // *      ***      * *      ***      *
+  // *1             4* *4             1*
+  // ***************** *****************
+  repeated OrientationType eye_orientations = 1 [packed = true];
+
+  // Specify a horizontal offset from the middle of the screen to the center of
+  // the lens, in meters. If one is not provided, half of the inter lens
+  // distance is used.
+  //
+  // This is only necessary if the HMD has some sort of periscope effect, where
+  // the position of the lenses, relative to the screen, is different than
+  // their position relative to the user.
+  //
+  // For example, in the HMD below, two mirrors reflect the image from the
+  // screen to the user, creating a larger inter lens distance than the screen
+  // can support.
+  //
+  // [In the diagram below, S = screen, L = lens]
+  //
+  // screen_center_to_lens_distance
+  //             |--|
+  //
+  // -------------------------
+  // |     SSSSSSSSSSSS      |
+  // |        |  |  |        |
+  // |   /----/  |  \----\   |
+  // |   |       |       |   |
+  // |  LLL             LLL  |
+  //
+  //     |---------------|
+  //    inter_lens_distance
+  //
+  optional float screen_center_to_lens_distance = 2;
+
+  // Optional x-dimension physical pixels per inch of the external display,
+  // assuming landscape orientation. If set, this will override OS-reported
+  // values.
+  optional float x_ppi_override = 3;
+
+  // Optional y-dimension physical pixels per inch of the external display,
+  // assuming landscape orientation.  If set, this will override OS-reported
+  // values.
+  optional float y_ppi_override = 4;
+
+  // Optional string identifying the device's accelerometer and gyroscope.
+  // If either field is filled out, the corresponding sensor (gyroscope or
+  // accelerometer) will be used for head tracking.
+  //
+  // Valid strings are usually found in:
+  // vendor/<vendorname>/<devicename>/xxx/sensors.cpp
+  //
+  // For dynamic sensors, this string will be provided in a separate way.
+  //
+  // NB: Vendors and manufacturers should make the name of the sensor as
+  // specific as possible, since if multiple sensors with the same name are
+  // connected, the first will be used.
+  optional string accelerometer = 5;
+  optional string gyroscope = 6;
+}
+
+/**
+ * Message describing the additional properties of a Daydream-ready headset that
+ * are not used for a normal cardboard viewer. These parameters are not intended
+ * to be used, or consumed, by developers and may or may not be supported or
+ * changed without notice on new releases of the Cardboard SDK or VR Toolkit.
+ */
+message DaydreamInternalParams {
+  // The version of the Daydream-ready specification to which this device
+  // conforms.
+  optional int32 version = 1;
+
+  // Optionally, specifies the collection of screen alignment markers in the
+  // headset.
+  repeated ScreenAlignmentMarker alignment_markers = 2;
+}
+
+/**
+ * Message describing a single screen alignment marker.
+ *
+ * A screen alignment marker is a capacitive touch point affixed to the headset
+ * which is capable of making contact with the screen. The location of the touch
+ * point is given in meters, measured along a horizontal axis which passes
+ * through the center of both lenses, and a vertical axis which is equidistant
+ * from the centers of the lenses. A positive vertical value indicates that the
+ * point lies above the horizontal axis, and a positive horizontal value
+ * indicates that the point lies to the right, as seen by a user of the headset,
+ * of the vertical axis. For example, if the following is a representation of a
+ * headset, viewed from the point of view of a user, with three points marked by
+ * the numbers 1, 2, and 3.
+ *
+ * *****************************************************************************
+ * *                                    ^                                      *
+ * *               _____                |                _____                 *
+ * *              /     \               1               /     \                *
+ * *             /       \              |              /       \               *
+ * *            /         \             |             /         \              *
+ * *           /           \            |            /           \             *
+ * *          /             \           |           /             \            *
+ * *---------|-------*-------|----------+------2---|-------*-------|---------->*
+ * *          \             /           |           \             /            *
+ * *           \           /            |            \           /             *
+ * *            \         /         3   |             \         /              *
+ * *             \       /              |              \       /               *
+ * *              \_____/               |               \_____/                *
+ * *                                    |                                      *
+ * *                                    |                                      *
+ * *****************************************************************************
+ *
+ * Then the coordinates of point 1 could be horizontal = 0.0, vertical = 0.035;
+ * point 2 could be horizontal = 0.02; and point 3 could be horizontal = -0.01
+ * vertical = -0.012
+ */
+message ScreenAlignmentMarker {
+  // The horizontal coordinate of the touch point.
+  optional float horizontal = 1;
+
+  // The vertical coordinate of the touch point.
+  optional float vertical = 2;
+}
diff --git a/libs/vr/libgvr/dummy_gvr_ext.cpp b/libs/vr/libgvr/dummy_gvr_ext.cpp
new file mode 100644
index 0000000..c507038
--- /dev/null
+++ b/libs/vr/libgvr/dummy_gvr_ext.cpp
@@ -0,0 +1,29 @@
+#include <base/logging.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_ext.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+gvr_frame_schedule* gvr_frame_schedule_create() { return NULL; }
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** /* schedule */) {}
+
+uint32_t gvr_frame_schedule_get_vsync_count(
+    gvr_frame_schedule* /* schedule */) {
+  return 0;
+}
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+                                                uint32_t /* vsync_count */) {
+  LOG(FATAL) << "gvr_get_6dof_head_pose_in_start_space is not implemented. "
+             << "Use gvr_get_head_space_from_start_space_pose instead.";
+  return gvr_mat4f({{{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}}});
+}
+
+void gvr_wait_next_frame(gvr_swap_chain* /* swap_chain */,
+                         int64_t /* sched_offset_nanos */,
+                         gvr_frame_schedule* /* out_next_frame_schedule */) {
+  LOG(FATAL) << "gvr_wait_next_frame is not implemented.";
+}
diff --git a/libs/vr/libgvr/exported_apis.lds b/libs/vr/libgvr/exported_apis.lds
new file mode 100644
index 0000000..2d19303
--- /dev/null
+++ b/libs/vr/libgvr/exported_apis.lds
@@ -0,0 +1,16 @@
+{
+  global:
+    # Export GVR APIs, both public and private.
+    gvr_*;
+
+    # Whitelist of DVR APIs required by VrCore for Ambrosia controller support.
+    dvrPoseCreate;
+    dvrPoseDestroy;
+    dvrPoseGet;
+    dvrPoseGetController;
+    dvrPoseGetVsyncCount;
+
+  local:
+    # Hide everything else.
+    *;
+};
diff --git a/libs/vr/libgvr/include/private/dvr/internal_types.h b/libs/vr/libgvr/include/private/dvr/internal_types.h
new file mode 100644
index 0000000..dafdb73
--- /dev/null
+++ b/libs/vr/libgvr/include/private/dvr/internal_types.h
@@ -0,0 +1,170 @@
+#ifndef ANDROID_DVR_INTERNAL_TYPES_H_
+#define ANDROID_DVR_INTERNAL_TYPES_H_
+
+#include <GLES2/gl2.h>
+#include <atomic>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+#include <dvr/graphics.h>
+#include <dvr/pose_client.h>
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_core.h>
+#include <private/dvr/display_client.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+#include <vr/gvr/capi/src/gvr_types_experimental.h>
+
+typedef struct gvr_user_prefs_ {
+} gvr_user_prefs;
+
+typedef struct gvr_context_ {
+  int32_t last_error_;
+  JNIEnv* jni_env_;
+  DvrPose* pose_client_;
+  std::unique_ptr<android::dvr::DisplayClient> display_client_;
+  android::dvr::SystemDisplayMetrics display_metrics_;
+  gvr_mat4f left_eye_viewport_transform_;
+  gvr_mat4f right_eye_viewport_transform_;
+  gvr_mat4f next_frame_6dof_pose_;
+  gvr_mat4f next_frame_controller_pose_[2];
+  gvr_user_prefs user_prefs_;
+  bool force_6dof_;
+  std::vector<gvr_swap_chain*> swap_chains_;
+
+  gvr_context_() :
+      last_error_(GVR_ERROR_NONE),
+      jni_env_(nullptr),
+      pose_client_(nullptr),
+      force_6dof_(false) {}
+
+  ~gvr_context_();
+} gvr_context;
+
+typedef struct gvr_buffer_spec_ {
+  gvr_sizei size;
+  int32_t msaa_samples;
+  int32_t color_format;
+  int32_t depth_stencil_format;
+  bool blur_behind;
+  bool initially_visible;
+  int z_order;
+
+  // The default values are configured to match SVR defaults
+  gvr_buffer_spec_()
+      : size{0, 0},
+        msaa_samples(0),
+        color_format(GVR_COLOR_FORMAT_RGBA_8888),
+        depth_stencil_format(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16),
+        blur_behind(true),
+        initially_visible(true),
+        z_order(0) {}
+} gvr_buffer_spec;
+
+// This isn't a public gvr type
+struct gvr_buffer {
+  gvr_buffer_spec spec;
+  GLuint frame_buffer;
+  GLuint color_render_buffer;
+  GLuint depth_stencil_render_buffer;
+
+  // requested_size is used for resizing. It will be {-1, -1} when no resize is
+  // requested. Any other value indicates the app changed the size.
+  gvr_sizei requested_size;
+
+  gvr_buffer();
+  // If creation fails frame_buffer will be 0
+  gvr_buffer(gvr_context* gvr, const gvr_buffer_spec& spec,
+             GLuint texture_id, GLenum texture_target);
+  ~gvr_buffer();
+
+  gvr_buffer(gvr_buffer&& other);
+  gvr_buffer& operator=(gvr_buffer&& other);
+  gvr_buffer(const gvr_buffer& other) = delete;
+  gvr_buffer& operator=(const gvr_buffer& other) = delete;
+
+  // Set default values. Doesn't free GL resources first.
+  void SetDefaults();
+
+  // Frees all GL resources associated with the buffer
+  void FreeGl();
+};
+
+typedef struct gvr_swap_chain_ {
+  gvr_context* context;
+  DvrGraphicsContext* graphics_context_;
+  std::vector<gvr_buffer> buffers_;
+  bool frame_acquired_;
+  bool wait_next_frame_called_by_app_;
+  std::atomic<int32_t> next_external_surface_id_;
+  std::unordered_map<int32_t, gvr_external_surface*> external_surfaces_;
+
+  explicit gvr_swap_chain_(gvr_context* context)
+      : context(context),
+        graphics_context_(nullptr),
+        frame_acquired_(false),
+        wait_next_frame_called_by_app_(false),
+        next_external_surface_id_(0) {}
+  ~gvr_swap_chain_();
+} gvr_swap_chain;
+
+typedef struct gvr_buffer_viewport_ {
+  int32_t buffer_index;
+  gvr_rectf uv;
+  gvr_mat4f transform;
+  int32_t eye;
+  int32_t external_surface_id;
+  gvr_reprojection reprojection;
+
+  gvr_buffer_viewport_()
+      : buffer_index(0),
+        uv{0, 0, 0, 0},
+        transform{{{1.f, 0.f, 0.f, 0.f},
+                   {0.f, 1.f, 0.f, 0.f},
+                   {0.f, 0.f, 1.f, 0.f},
+                   {0.f, 0.f, 0.f, 1.f}}},
+        eye(0),
+        external_surface_id(-1),
+        reprojection(GVR_REPROJECTION_FULL) {}
+
+  gvr_buffer_viewport_(int32_t /* buffer_index */, gvr_rectf uv,
+                       const gvr_mat4f& transform, int32_t eye,
+                       int32_t external_surface_id,
+                       gvr_reprojection reprojection)
+      : buffer_index(0),
+        uv(uv),
+        transform(transform),
+        eye(eye),
+        external_surface_id(external_surface_id),
+        reprojection(reprojection) {}
+
+  bool operator==(const gvr_buffer_viewport_& other) const;
+
+  bool operator!=(const gvr_buffer_viewport_& other) const {
+    return !operator==(other);
+  }
+} gvr_buffer_viewport;
+
+typedef struct gvr_buffer_viewport_list_ {
+  std::vector<gvr_buffer_viewport> viewports;
+} gvr_buffer_viewport_list;
+
+typedef struct gvr_frame_schedule_ {
+  uint32_t vsync_count;
+  gvr_clock_time_point scheduled_finish;
+
+  gvr_frame_schedule_() : vsync_count(0) {
+    scheduled_finish.monotonic_system_time_nanos = 0;
+  }
+} gvr_frame_schedule;
+
+typedef struct gvr_display_synchronizer_ {} gvr_display_synchronizer;
+
+typedef struct gvr_external_surface_ {
+  int32_t id;
+  gvr_swap_chain* swap_chain;
+  DvrVideoMeshSurface* video_surface;
+} gvr_external_surface;
+
+#endif  // ANDROID_DVR_INTERNAL_TYPES_H_
diff --git a/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h
new file mode 100644
index 0000000..8af434f
--- /dev/null
+++ b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_ext.h
@@ -0,0 +1,119 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// Constants that represent GVR error codes.
+typedef enum {
+  // TODO(steventhomas): All errors should be switched to something more
+  // meaningful and this should eventually go away.
+  GVR_ERROR_INTERNAL = 9000,
+} gvr_error_ext;
+
+typedef struct gvr_frame_schedule_ gvr_frame_schedule;
+
+gvr_frame_schedule* gvr_frame_schedule_create();
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** schedule);
+
+uint32_t gvr_frame_schedule_get_vsync_count(gvr_frame_schedule* schedule);
+
+gvr_clock_time_point gvr_frame_schedule_get_scheduled_finish(
+    gvr_frame_schedule* schedule);
+
+/// Sleep until it's time to render the next frame.
+// |start_delay_ns| adjusts how long this function blocks the app from starting
+// its next frame. If |start_delay_ns| is 0, the function waits until the
+// scheduled frame finish time for the current frame, which gives the app one
+// full vsync period to render the next frame. If the app needs less than a full
+// vysnc period to render the frame, pass in a non-zero |start_delay_ns| to
+// delay the start of frame rendering further. For example, if the vsync period
+// is 11.1ms and the app takes 6ms to render a frame, consider setting this to
+// 5ms (note that the value is in nanoseconds, so 5,000,000ns) so that the app
+// finishes the frame closer to the scheduled frame finish time. Delaying the
+// start of rendering allows the app to use a more up-to-date pose for
+// rendering.
+// |start_delay_ns| must be a positive value or 0. If you're unsure what to set
+// for |start_delay_ns|, use 0.
+/// |out_next_frame_schedule| is an output parameter that will contain the
+/// schedule for the next frame. It can be null.
+void gvr_wait_next_frame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+                         gvr_frame_schedule* out_next_frame_schedule);
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+                                                uint32_t vsync_count);
+
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+    gvr_context* gvr, const gvr_clock_time_point time);
+
+gvr_mat4f gvr_get_start_space_from_controller_space_pose(
+    gvr_context* gvr, int controller_id, const gvr_clock_time_point time);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+#include <utility>
+
+namespace gvr {
+
+/// Convenience C++ wrapper for gvr_frame_schedule. Frees the underlying
+/// gvr_frame_schedule on destruction.
+class FrameSchedule {
+ public:
+  FrameSchedule() { schedule_ = gvr_frame_schedule_create(); }
+
+  ~FrameSchedule() {
+    if (schedule_)
+      gvr_frame_schedule_destroy(&schedule_);
+  }
+
+  FrameSchedule(FrameSchedule&& other) {
+    std::swap(schedule_, other.schedule_);
+  }
+
+  FrameSchedule& operator=(FrameSchedule&& other) {
+    std::swap(schedule_, other.schedule_);
+    return *this;
+  }
+
+  gvr_frame_schedule* cobj() { return schedule_; }
+  const gvr_frame_schedule* cobj() const { return schedule_; }
+
+  uint32_t GetVsyncCount() const {
+    return gvr_frame_schedule_get_vsync_count(schedule_);
+  }
+
+  gvr_clock_time_point GetScheduledFinish() const {
+    return gvr_frame_schedule_get_scheduled_finish(schedule_);
+  }
+
+ private:
+  gvr_frame_schedule* schedule_;
+};
+
+}  // namespace gvr
+#endif  // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_EXT_H_
diff --git a/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h
new file mode 100644
index 0000000..1fae611
--- /dev/null
+++ b/libs/vr/libgvr/include/vr/gvr/capi/include/gvr_util.h
@@ -0,0 +1,123 @@
+#ifndef VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
+
+#include <private/dvr/eigen.h>
+#include <private/dvr/numeric.h>
+#include <private/dvr/types.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+namespace android {
+namespace dvr {
+
+inline gvr_rectf FovRadiansToDegrees(const gvr_rectf& fov) {
+  return gvr_rectf{ToDeg(fov.left), ToDeg(fov.right), ToDeg(fov.bottom),
+                   ToDeg(fov.top)};
+}
+
+inline gvr_rectf FovDegreesToRadians(const gvr_rectf& fov) {
+  return gvr_rectf{ToRad(fov.left), ToRad(fov.right), ToRad(fov.bottom),
+                   ToRad(fov.top)};
+}
+
+inline FieldOfView GvrToDvrFov(const gvr_rectf& fov) {
+  gvr_rectf fov_rad = FovDegreesToRadians(fov);
+  return FieldOfView(fov_rad.left, fov_rad.right, fov_rad.bottom, fov_rad.top);
+}
+
+inline gvr_rectf DvrToGvrFov(const FieldOfView& fov) {
+  return FovRadiansToDegrees(
+      gvr_rectf{fov.GetLeft(), fov.GetRight(), fov.GetBottom(), fov.GetTop()});
+}
+
+inline gvr_mat4f GvrIdentityMatrix() {
+  gvr_mat4f identity;
+  memset(&identity.m, 0, sizeof(identity.m));
+  for (int i = 0; i < 4; i++)
+    identity.m[i][i] = 1;
+  return identity;
+}
+
+inline gvr_mat4f GvrTranslationMatrix(float x, float y, float z) {
+  gvr_mat4f trans = GvrIdentityMatrix();
+  trans.m[0][3] = x;
+  trans.m[1][3] = y;
+  trans.m[2][3] = z;
+  return trans;
+}
+
+inline gvr_mat4f EigenToGvrMatrix(const mat4& m) {
+  gvr_mat4f ret;
+  for (int i = 0; i < 4; ++i)
+    for (int j = 0; j < 4; ++j)
+      ret.m[i][j] = m(i, j);
+  return ret;
+}
+
+inline mat4 GvrToEigenMatrix(const gvr::Mat4f& m) {
+  mat4 ret;
+  for (int i = 0; i < 4; ++i)
+    for (int j = 0; j < 4; ++j)
+      ret(i, j) = m.m[i][j];
+  return ret;
+}
+
+inline quat GvrToEigenRotation(const gvr_mat4f& m) {
+  mat3 ret;
+  for (int r = 0; r < 3; ++r)
+    for (int c = 0; c < 3; ++c)
+      ret(r, c) = m.m[r][c];
+  return quat(ret.matrix());
+}
+
+inline vec3 GvrToEigenTranslation(const gvr_mat4f& m) {
+  return vec3(m.m[0][3], m.m[1][3], m.m[2][3]);
+}
+
+// Converts a DVR pose to 6DOF head transform as a GVR matrix.
+inline gvr_mat4f PosefToGvrMatrix(const Posef& pose) {
+  return EigenToGvrMatrix(pose.GetObjectFromReferenceMatrix());
+}
+
+// Converts a DVR pose to 3DOF head transform as a GVR matrix by stripping out
+// position translation.
+inline gvr_mat4f PosefTo3DofGvrMatrix(const Posef& pose) {
+  gvr_mat4f ret = PosefToGvrMatrix(pose);
+  ret.m[0][3] = 0;
+  ret.m[1][3] = 0;
+  ret.m[2][3] = 0;
+  return ret;
+}
+
+// Converts a GVR matrix to a DVR pose.
+inline Posef GvrMatrixToPosef(const gvr_mat4f& m) {
+  return Posef(GvrToEigenRotation(m), GvrToEigenTranslation(m)).Inverse();
+}
+
+// Calculates an transform with only the yaw and position components of |pose|.
+// The inverse of this matrix cancels yaw and position without affecting roll or
+// pitch.
+inline mat4 CalculateRecenterTransform(const mat4& pose) {
+  const vec4 z_axis = pose * vec4::UnitZ();
+  const float yaw = std::atan2(z_axis[0], z_axis[2]);
+  const vec3 position = pose.translation();
+  return mat4(Eigen::AngleAxis<float>(yaw, vec3::UnitY())).translate(position);
+}
+
+// Calculates a transform that negates the position component of |pose| and
+// offsets the pose by |position|. The inverse of this matrix cancels the
+// position component of pose and translates by |position| without affecting
+// orientation.
+inline mat4 CalculateOffsetTransform(const mat4& pose, const vec3& position) {
+  // Transform the origin by the pose matrix to produce the offset that cancels
+  // only the position of the pose.
+  //          -1          T
+  // [ R | t ]  [ 0 ] = -R * t
+  // [ 0   1 ]  [ 1 ]
+  const vec3 position_offset = (pose.inverse() * vec4(0, 0, 0, 1)).head<3>();
+  return mat4(mat4::Identity()).translate(position - position_offset);
+}
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_UTIL_H_
diff --git a/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
new file mode 100644
index 0000000..5c5cc62
--- /dev/null
+++ b/libs/vr/libgvr/java/com/google/vr/gvr/platform/Loader.java
@@ -0,0 +1,32 @@
+package com.google.vr.gvr.platform;
+
+/**
+ * Auxiliary class to load the system implementation of the GVR API.
+ */
+public class Loader {
+
+  /**
+   * Opens a shared library containing the system implementation for the GVR
+   * API and returns the handle to it.
+   *
+   * @return A Long object describing the handle returned by dlopen.
+   */
+  public static Long loadLibrary() {
+    // Note: we cannot safely do caller verifications here, so instead we do
+    // them in the service side. This means that private API symbols will be
+    // visible to any app adding the appropriate <uses-library> in their
+    // manifest, but any requests to such APIs will fail if not done from a
+    // trusted package like VrCore.
+    //
+    // Trusted packages are defined by (package name, signature) pairs in within
+    // a system service, and both must match.
+
+    // Load a thin JNI library that runs dlopen on request.
+    System.loadLibrary("gvr_system_loader");
+
+    // Performs dlopen on the library and returns the handle.
+    return nativeLoadLibrary("libgvr_system.so");
+  }
+
+  private static native long nativeLoadLibrary(String library);
+}
diff --git a/libs/vr/libgvr/library_loader.cpp b/libs/vr/libgvr/library_loader.cpp
new file mode 100644
index 0000000..3cdc7d6
--- /dev/null
+++ b/libs/vr/libgvr/library_loader.cpp
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <jni.h>
+
+#include <string>
+
+extern "C" {
+
+JNIEXPORT jlong JNICALL
+Java_com_google_vr_gvr_platform_Loader_nativeLoadLibrary(
+    JNIEnv* env, jclass, jstring java_library) {
+  if (!java_library)
+    return 0;
+
+  // Convert the Java String object to a C++ null-terminated string.
+  const char* data = env->GetStringUTFChars(java_library, NULL);
+  size_t size = env->GetStringUTFLength(java_library);
+  std::string library(data, size);
+  env->ReleaseStringUTFChars(java_library, data);
+
+  // Return the handle to the requested library.
+  return reinterpret_cast<jlong>(
+      dlopen(library.c_str(), RTLD_NOW | RTLD_LOCAL));
+}
+
+}  // extern "C"
diff --git a/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh b/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh
new file mode 100644
index 0000000..5d5076b
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/build_gvr_prebuilts.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+# Build and copy libgvr from Google3. Make sure that your local Google3 client
+# is up-to-date by running `p4 sync` before executing this script.
+#
+# Usage:
+# build_gvr_prebuilts.sh --google3_dir=<path_google3_client_root>
+
+source gbash.sh || exit
+
+DEFINE_string --required "google3_dir" "" \
+  "Path to the root directory of Google3 client"
+
+BLAZE_COMMON_OPTS=(
+  --compilation_mode=opt
+  --copt=-fdata-sections
+  --copt=-ffunction-sections
+  --define='prod=1'
+  --define='enable_experimental_sdk=1'
+  --linkopt=-Wl,--gc-sections
+)
+
+function copy_file() {
+  cp -v "${1}" ${CURRENT_DIR}/"${2}"
+}
+
+function copy_gvr_headers() {
+  echo "Copy GVR headers ..."
+
+  GVR_HEADER_DIR="include/vr/gvr/capi/include"
+  GVR_SOURCE_DIR="include/vr/gvr/capi/src"
+
+  # GVR public headers
+  copy_file "vr/gvr/capi/include/gvr.h" ${GVR_HEADER_DIR}
+  copy_file "vr/gvr/capi/include/gvr_audio.h" ${GVR_HEADER_DIR}
+  copy_file "vr/gvr/capi/include/gvr_controller.h" ${GVR_HEADER_DIR}
+  copy_file "vr/gvr/capi/include/gvr_types.h" ${GVR_HEADER_DIR}
+
+  # GVR private and experimental headers
+  copy_file "vr/gvr/capi/src/gvr_experimental.h" ${GVR_SOURCE_DIR}
+  copy_file "vr/gvr/capi/src/gvr_private.h" ${GVR_SOURCE_DIR}
+  copy_file "vr/gvr/capi/src/gvr_types_experimental.h" ${GVR_SOURCE_DIR}
+}
+
+function build_gvr_libs() {
+  echo "Build GVR libraries ..."
+
+  blaze build \
+    //java/com/google/vr/sdk/release:common_library.aar \
+    //vr/gvr/platform:libgvr.so \
+    //vr/gvr/platform:libgvr_audio.so \
+    ${BLAZE_COMMON_OPTS[@]} --config=android_arm --symlink_prefix blaze-arm-
+
+  blaze build \
+    //vr/gvr/platform:libgvr.so \
+    //vr/gvr/platform:libgvr_audio.so \
+    ${BLAZE_COMMON_OPTS[@]} --config=android_arm64 --symlink_prefix blaze-arm64-
+
+  copy_file "blaze-arm-genfiles/java/com/google/vr/sdk/release/common_library.aar" \
+    "lib/common_library.aar"
+  copy_file "blaze-arm-genfiles/vr/gvr/platform/libgvr.so" "lib/android_arm"
+  copy_file "blaze-arm-genfiles/vr/gvr/platform/libgvr_audio.so" "lib/android_arm"
+  copy_file "blaze-arm64-genfiles/vr/gvr/platform/libgvr.so" "lib/android_arm64"
+  copy_file "blaze-arm64-genfiles/vr/gvr/platform/libgvr_audio.so" "lib/android_arm64"
+}
+
+function main() {
+  set -ex
+
+  CURRENT_DIR=$(pwd)
+  GOOGLE3_DIR=${FLAGS_google3_dir}
+
+  cd ${GOOGLE3_DIR}
+  copy_gvr_headers
+  build_gvr_libs
+}
+
+gbash::init_google "$@"
+main "$@"
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h
new file mode 100644
index 0000000..5054ebd
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr.h
@@ -0,0 +1,1737 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 VR_GVR_CAPI_INCLUDE_GVR_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_H_
+
+#ifdef __ANDROID__
+#include <jni.h>
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+#include <array>
+#include <memory>
+#include <vector>
+#endif
+
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup base Google VR Base C API
+/// @brief This is the Google VR C API. It supports clients writing VR
+/// experiences for head mounted displays that consist of a mobile phone and a
+/// VR viewer.
+///
+/// Example API usage:
+///
+///     #ifdef __ANDROID__
+///     // On Android, the gvr_context should almost always be obtained from
+///     // the Java GvrLayout object via
+///     // GvrLayout.getGvrApi().getNativeGvrContext().
+///     gvr_context* gvr = ...;
+///     #else
+///     gvr_context* gvr = gvr_create();
+///     #endif
+///
+///     gvr_initialize_gl(gvr);
+///
+///     gvr_buffer_viewport_list* viewport_list =
+///         gvr_buffer_viewport_list_create(gvr);
+///     gvr_get_recommended_buffer_viewports(gvr, viewport_list);
+///     gvr_buffer_viewport* left_eye_vp = gvr_buffer_viewport_create(gvr);
+///     gvr_buffer_viewport* right_eye_vp = gvr_buffer_viewport_create(gvr);
+///     gvr_buffer_viewport_list_get_item(viewport_list, 0, left_eye_vp);
+///     gvr_buffer_viewport_list_get_item(viewport_list, 1, right_eye_vp);
+///
+///     while (client_app_should_render) {
+///       // A client app should be ready for the render target size to change
+///       // whenever a new QR code is scanned, or a new viewer is paired.
+///       gvr_sizei render_target_size =
+///           gvr_get_maximum_effective_render_target_size(gvr);
+///       // The maximum effective render target size can be very large, most
+///       // applications need to scale down to compensate.
+///       render_target_size.width /= 2;
+///       render_target_size.height /= 2;
+///       gvr_swap_chain_resize_buffer(swap_chain, 0, render_target_size);
+///
+///       // This function will depend on your render loop's implementation.
+///       gvr_clock_time_point next_vsync = AppGetNextVsyncTime();
+///
+///       const gvr_mat4f head_view =
+///           gvr_get_head_space_from_start_space_rotation(gvr, next_vsync);
+///       const gvr_mat4f left_eye_view = MatrixMultiply(
+///           gvr_get_eye_from_head_matrix(gvr, GVR_LEFT_EYE), head_view);
+///       const gvr::Mat4f right_eye_view = MatrixMultiply(
+///           gvr_get_eye_from_head_matrix(gvr, GVR_RIGHT_EYE), head_view);
+///
+///       // Insert client rendering code here.
+///
+///       AppSetRenderTarget(offscreen_texture_id);
+///
+///       AppDoSomeRenderingForEye(
+///           gvr_buffer_viewport_get_source_uv(left_eye_view),
+///           left_eye_matrix);
+///       AppDoSomeRenderingForEye(
+///           gvr_buffer_viewport_get_source_uv(right_eye_view),
+///           right_eye_matrix);
+///       AppSetRenderTarget(primary_display);
+///
+///       gvr_frame_submit(&frame, viewport_list, head_matrix);
+///     }
+///
+///     // Cleanup memory.
+///     gvr_buffer_viewport_list_destroy(&viewport_list);
+///     gvr_buffer_viewport_destroy(&left_eye_vp);
+///     gvr_buffer_viewport_destroy(&right_eye_vp);
+///
+///     #ifdef __ANDROID__
+///     // On Android, The Java GvrLayout owns the gvr_context.
+///     #else
+///     gvr_destroy(gvr);
+///     #endif
+///
+/// Head tracking is enabled by default, and will begin as soon as the
+/// gvr_context is created. The client should call gvr_pause_tracking() and
+/// gvr_resume_tracking() when the app is paused and resumed, respectively.
+///
+/// Note: Unless otherwise noted, the functions in this API may not be
+/// thread-safe with respect to the gvr_context, and it is up the caller to use
+/// the API in a thread-safe manner.
+///
+/// @{
+
+/// Creates a new gvr instance.
+///
+/// The instance must remain valid as long as any GVR object is in use. When
+/// the application no longer needs to use the GVR SDK, call gvr_destroy().
+///
+///
+/// On Android, the gvr_context should *almost always* be obtained from the Java
+/// GvrLayout object, rather than explicitly created here. The GvrLayout should
+/// live in the app's View hierarchy, and its use is required to ensure
+/// consistent behavior across all varieties of GVR-compatible viewers. See
+/// the Java GvrLayout and GvrApi documentation for more details.
+///
+#ifdef __ANDROID__
+/// @param env The JNIEnv associated with the current thread.
+/// @param app_context The Android application context. This must be the
+///     application context, NOT an Activity context (Note: from any Android
+///     Activity in your app, you can call getApplicationContext() to
+///     retrieve the application context).
+/// @param class_loader The class loader to use when loading Java classes.
+///     This must be your app's main class loader (usually accessible through
+///     activity.getClassLoader() on any of your Activities).
+///
+/// @return Pointer to the created gvr instance, NULL on failure.
+gvr_context* gvr_create(JNIEnv* env, jobject app_context, jobject class_loader);
+#else
+/// @return Pointer to the created gvr instance, NULL on failure.
+gvr_context* gvr_create();
+#endif  // #ifdef __ANDROID__
+
+/// Gets the current GVR runtime version.
+///
+/// Note: This runtime version may differ from the version against which the
+/// client app is compiled, as defined by the semantic version components in
+/// gvr_version.h.
+///
+/// @return The version as a gvr_version.
+gvr_version gvr_get_version();
+
+/// Gets a string representation of the current GVR runtime version. This is of
+/// the form "MAJOR.MINOR.PATCH".
+///
+/// Note: This runtime version may differ from the version against which the
+/// client app is compiled, as defined in gvr_version.h by
+/// GVR_SDK_VERSION_STRING.
+///
+/// @return The version as a static char pointer.
+const char* gvr_get_version_string();
+
+/// Gets the current GVR error code, or GVR_ERROR_NONE if there is no error.
+/// This function doesn't clear the error code; see gvr_clear_error().
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return The current gvr_error code, or GVR_ERROR_NONE if no error has
+///    occurred.
+int32_t gvr_get_error(gvr_context* gvr);
+
+/// Clears the current GVR error code, and returns the error code that was
+/// cleared.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return The gvr_error code that was cleared by this function, or
+/// GVR_ERROR_NONE if no error has occurred.
+int32_t gvr_clear_error(gvr_context* gvr);
+
+/// Gets a human-readable string representing the given error code.
+///
+/// @param error_code The gvr_error code.
+/// @return A human-readable string representing the error code.
+const char* gvr_get_error_string(int32_t error_code);
+
+/// Returns an opaque struct containing information about user preferences.
+///
+/// The returned struct will remain valid as long as the context is valid.
+/// The returned struct may be updated when the user changes their preferences,
+/// so this function only needs to be called once, and calling it multiple
+/// times will return the same object each time.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return An opaque struct containing information about user preferences.
+const gvr_user_prefs* gvr_get_user_prefs(gvr_context* gvr);
+
+/// Returns the controller handedness of the given gvr_user_prefs struct.
+///
+/// @param user_prefs Pointer to the gvr_user_prefs object returned by
+///     gvr_get_user_prefs.
+/// @return Either GVR_CONTROLLER_RIGHT_HANDED or GVR_CONTROLLER_LEFT_HANDED
+///     depending on which hand the user holds the controller in.
+int32_t gvr_user_prefs_get_controller_handedness(
+    const gvr_user_prefs* user_prefs);
+
+/// Destroys a gvr_context instance.  The parameter will be nulled by this
+/// operation.  Once this function is called, the behavior of any subsequent
+/// call to a GVR SDK function that references objects created from this
+/// context is undefined.
+///
+/// @param gvr Pointer to a pointer to the gvr instance to be destroyed and
+///     nulled.
+void gvr_destroy(gvr_context** gvr);
+
+/// Initializes necessary GL-related objects and uses the current thread and
+/// GL context for rendering. Please make sure that a valid GL context is
+/// available when this function is called.  This should never be called more
+/// than once on the same GL context (doing so would cause resource leaks).
+///
+/// @param gvr Pointer to the gvr instance to be initialized.
+void gvr_initialize_gl(gvr_context* gvr);
+
+/// Gets whether asynchronous reprojection is currently enabled.
+///
+/// If enabled, frames will be collected by the rendering system and
+/// asynchronously re-projected in sync with the scanout of the display. This
+/// feature may not be available on every platform, and requires a
+/// high-priority render thread with special extensions to function properly.
+///
+/// Note: On Android, this feature can be enabled solely via the GvrLayout Java
+/// instance which (indirectly) owns this gvr_context. The corresponding
+/// method call is GvrLayout.setAsyncReprojectionEnabled().
+///
+/// Note: Because of the above requirements, asynchronous reprojection is only
+/// currently available on Daydream-ready Android devices.  This function will
+/// always return false on other devices.
+///
+/// @param gvr Pointer to the gvr instance.
+/// @return Whether async reprojection is enabled. Defaults to false.
+bool gvr_get_async_reprojection_enabled(const gvr_context* gvr);
+
+/// Gets the recommended buffer viewport configuration, populating a previously
+/// allocated gvr_buffer_viewport_list object. The updated values include the
+/// per-eye recommended viewport and field of view for the target.
+///
+/// When the recommended viewports are used for distortion rendering, this
+/// method should always be called after calling refresh_viewer_profile(). That
+/// will ensure that the populated viewports reflect the currently paired
+/// viewer.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewports.
+/// @param viewport_list Pointer to a previously allocated viewport list. This
+///     will be populated with the recommended buffer viewports and resized if
+///     necessary.
+void gvr_get_recommended_buffer_viewports(
+    const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list);
+
+/// Gets the screen (non-distorted) buffer viewport configuration, populating a
+/// previously allocated gvr_buffer_viewport_list object. The updated values
+/// include the per-eye recommended viewport and field of view for the target.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewports.
+/// @param viewport_list Pointer to a previously allocated viewport list. This
+///     will be populated with the screen buffer viewports and resized if
+///     necessary.
+void gvr_get_screen_buffer_viewports(const gvr_context* gvr,
+                                     gvr_buffer_viewport_list* viewport_list);
+
+/// Returns the maximum effective size for the client's render target, given the
+/// parameters of the head mounted device selected. At this resolution, we have
+/// a 1:1 ratio between source pixels and screen pixels in the most magnified
+/// region of the screen. Applications should rarely, if ever, need to render
+/// to a larger target, as it will simply result in sampling artifacts.
+///
+/// Note that this is probably too large for most applications to use as a
+/// render target size. Applications should scale this value to be appropriate
+/// to their graphical load.
+///
+/// @param gvr Pointer to the gvr instance from which to get the size.
+///
+/// @return Maximum effective size for the target render target.
+gvr_sizei gvr_get_maximum_effective_render_target_size(const gvr_context* gvr);
+
+/// Returns a non-distorted size for the screen, given the parameters
+/// of the phone and/or the head mounted device selected.
+///
+/// @param gvr Pointer to the gvr instance from which to get the size.
+///
+/// @return Screen (non-distorted) size for the render target.
+gvr_sizei gvr_get_screen_target_size(const gvr_context* gvr);
+
+// Sets the size of the underlying render surface.
+//
+// By default, it is assumed that the display size matches the surface
+// size. If that is the case for the client app, this method need never be
+// called. However, in certain cases (e.g., hardware scaling), this will not
+// always hold, in which case the distortion pass must be informed of the
+// custom surface size.
+//
+// Note that the caller is responsible for resizing any BufferSpec objects
+// created before this function is called. Otherwise there will be rendering
+// artifacts, such as edges appearing pixelated. This function will change the
+// result of get_maximum_effective_render_target_size(), so that function can be
+// used to compute the appropriate size for buffers.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param surface_size_pixels The size in pixels of the display surface. If
+//     non-empty, this will be used in conjunction with the current display to
+//     perform properly scaled distortion. If empty, it is assumed that the
+//     rendering surface dimensions match that of the active display.
+void gvr_set_surface_size(gvr_context* gvr, gvr_sizei surface_size_pixels);
+
+/// Performs postprocessing, including lens distortion, on the contents of the
+/// passed texture and shows the result on the screen. Lens distortion is
+/// determined by the parameters of the viewer encoded in its QR code. The
+/// passed texture is not modified.
+///
+/// If the application does not call gvr_initialize_gl() before calling this
+/// function, the results are undefined.
+///
+/// @deprecated This function exists only to support legacy rendering pathways
+///     for Cardboard devices. It is incompatible with the low-latency
+///     experiences supported by async reprojection. Use the swap chain API
+///     instead.
+///
+/// @param gvr Pointer to the gvr instance which will do the distortion.
+/// @param texture_id The OpenGL ID of the texture that contains the next frame
+///     to be displayed.
+/// @param viewport_list Rendering parameters.
+/// @param head_space_from_start_space This parameter is ignored.
+/// @param target_presentation_time This parameter is ignored.
+void gvr_distort_to_screen(gvr_context* gvr, int32_t texture_id,
+                           const gvr_buffer_viewport_list* viewport_list,
+                           gvr_mat4f head_space_from_start_space,
+                           gvr_clock_time_point target_presentation_time);
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Viewports and viewport lists
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup viewport Viewports and viewport lists
+/// @brief Objects to define the mapping between the application's rendering
+///     output and the user's field of view.
+/// @{
+
+/// Creates a gvr_buffer_viewport instance.
+gvr_buffer_viewport* gvr_buffer_viewport_create(gvr_context* gvr);
+
+/// Frees a gvr_buffer_viewport instance and clears the pointer.
+void gvr_buffer_viewport_destroy(gvr_buffer_viewport** viewport);
+
+/// Gets the UV coordinates specifying where the output buffer is sampled.
+///
+/// @param viewport The buffer viewport.
+/// @return UV coordinates as a rectangle.
+gvr_rectf gvr_buffer_viewport_get_source_uv(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the UV coordinates specifying where the output buffer should be
+/// sampled when compositing the final distorted image.
+///
+/// @param viewport The buffer viewport.
+/// @param uv The new UV coordinates for sampling. The coordinates must be
+///     valid, that is, left <= right and bottom <= top. Otherwise an empty
+///     source region is set, which will result in no output for this viewport.
+void gvr_buffer_viewport_set_source_uv(gvr_buffer_viewport* viewport,
+                                       gvr_rectf uv);
+
+/// Retrieves the field of view for the referenced buffer region.
+///
+/// This is a helper that converts the stored projection matrix to a field of
+/// view. Note that if the previously set projection matrix cannot be expressed
+/// as a view frustum aligned with the eye's optical axis, the result will be
+/// incorrect.
+///
+/// @param viewport The buffer viewport.
+/// @return The field of view of the rendered image, in degrees.
+gvr_rectf gvr_buffer_viewport_get_source_fov(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the field of view for the viewport contents.
+///
+/// This is a helper that sets the projection matrix in such a way that the
+/// viewport's contents fill the specified FOV around the eye's optical axis.
+///
+/// @param viewport The buffer viewport.
+/// @param fov The field of view to use when compositing the rendered image,
+///     in degrees.
+void gvr_buffer_viewport_set_source_fov(gvr_buffer_viewport* viewport,
+                                        gvr_rectf fov);
+
+/// Gets the matrix that positions the viewport in eye space.
+///
+/// @param viewport The buffer viewport.
+/// @return Matrix that transforms a quad with vertices (-1, -1, 0), (1, -1, 0),
+///     (-1, 1, 0), (1, 1, 0) representing the viewport contents to its desired
+///     eye space position for the target eye.
+gvr_mat4f gvr_buffer_viewport_get_transform(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the matrix that positions the viewport in eye space.
+///
+/// @param viewport The buffer viewport.
+/// @param transform Matrix that transforms a quad with vertices (-1, -1, 0),
+///     (1, -1, 0), (-1, 1, 0), (1, 1, 0) representing the viewport contents to
+///     its desired eye space position for the target eye.
+void gvr_buffer_viewport_set_transform(gvr_buffer_viewport* viewport,
+                                       gvr_mat4f transform);
+
+/// Gets the target logical eye for the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @return Index of the target logical eye for this viewport.
+int32_t gvr_buffer_viewport_get_target_eye(const gvr_buffer_viewport* viewport);
+
+/// Sets the target logical eye for the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @param index Index of the target logical eye.
+void gvr_buffer_viewport_set_target_eye(gvr_buffer_viewport* viewport,
+                                        int32_t index);
+
+/// Gets the index of the source buffer from which the viewport reads its
+/// undistorted pixels.
+///
+/// @param viewport The buffer viewport.
+/// @return Index of the source buffer. This corresponds to the index in the
+///     list of buffer specs that was passed to gvr_swap_chain_create().
+int32_t gvr_buffer_viewport_get_source_buffer_index(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the buffer from which the viewport reads its undistorted pixels.
+///
+/// To use the contents of the external surface as buffer contents, associate an
+/// external surface with the viewport by calling
+/// gvr_buffer_viewport_set_external_surface_id(), then call this function and
+/// pass GVR_BUFFER_INDEX_EXTERNAL_SURFACE.
+///
+/// @param viewport The buffer viewport.
+/// @param buffer_index The index of the source buffer. This is either an index
+///     in the list of buffer specs that was passed to
+///     gvr_swap_chain_create(), or GVR_BUFFER_INDEX_EXTERNAL_SURFACE.
+void gvr_buffer_viewport_set_source_buffer_index(
+    gvr_buffer_viewport* viewport, int32_t buffer_index);
+
+/// Gets the ID of the externally-managed Surface texture from which this
+/// viewport reads undistored pixels.
+///
+/// @param viewport The buffer viewport.
+/// @return ID of the externally-managed Surface of undistorted pixels.
+int32_t gvr_buffer_viewport_get_external_surface_id(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the ID of the externally-managed Surface texture from which this
+/// viewport reads. The ID is issued by GvrLayout.
+///
+/// @param viewport The buffer viewport.
+/// @param external_surface_id The ID of the surface to read from.
+void gvr_buffer_viewport_set_external_surface_id(
+    gvr_buffer_viewport* viewport, int32_t external_surface_id);
+
+/// Gets the type of reprojection to perform on the specified viewport.
+///
+/// @param viewport The buffer viewport.
+/// @return Type of reprojection that is applied to the viewport.
+int32_t gvr_buffer_viewport_get_reprojection(
+    const gvr_buffer_viewport* viewport);
+
+/// Sets the type of reprojection to perform on the specified viewport.
+/// Viewports that display world content should use full reprojection.
+/// Viewports that display head-locked UI should disable reprojection to avoid
+/// excessive judder. The default is to perform full reprojection.
+///
+/// @param viewport The buffer viewport.
+/// @param reprojection Type of reprojection that will be applied to the passed
+///     viewport.
+void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport,
+                                          int32_t reprojection);
+
+/// Compares two gvr_buffer_viewport instances and returns true if they specify
+/// the same view mapping.
+///
+/// @param a Instance of a buffer viewport.
+/// @param b Another instance of a buffer viewport.
+/// @return True if the passed viewports are the same.
+bool gvr_buffer_viewport_equal(const gvr_buffer_viewport* a,
+                               const gvr_buffer_viewport* b);
+
+/// Creates a new, empty list of viewports. The viewport list defines how the
+/// application's rendering output should be transformed into the stabilized,
+/// lens-distorted image that is sent to the screen.
+///
+/// The caller should populate the returned viewport using one of:
+///   - gvr_get_recommended_buffer_viewports()
+///   - gvr_get_screen_buffer_viewports()
+///   - gvr_buffer_viewport_list_set_item()
+///
+/// @param gvr Pointer the gvr instance from which to allocate the viewport
+/// list.
+/// @return Pointer to an allocated gvr_buffer_viewport_list object. The caller
+//      is responsible for calling gvr_buffer_viewport_list_destroy() on the
+///     returned object when it is no longer needed.
+gvr_buffer_viewport_list* gvr_buffer_viewport_list_create(
+    const gvr_context* gvr);
+
+/// Destroys a gvr_buffer_viewport_list instance. The parameter will be nulled
+/// by this operation.
+///
+/// @param viewport_list Pointer to a pointer to the viewport list instance to
+///     be destroyed and nulled.
+void gvr_buffer_viewport_list_destroy(gvr_buffer_viewport_list** viewport_list);
+
+/// Returns the size of the given viewport list.
+///
+/// @param viewport_list Pointer to a viewport list.
+/// @return The number of entries in the viewport list.
+size_t gvr_buffer_viewport_list_get_size(
+    const gvr_buffer_viewport_list* viewport_list);
+
+/// Retrieve a buffer viewport entry from a list.
+///
+/// @param viewport_list Pointer to the previously allocated viewport list.
+/// @param index Zero-based index of the viewport entry to query. Must be
+///    smaller than the list size.
+/// @param viewport The buffer viewport structure that will be populated with
+///    retrieved data.
+void gvr_buffer_viewport_list_get_item(
+    const gvr_buffer_viewport_list* viewport_list, size_t index,
+    gvr_buffer_viewport* viewport);
+
+/// Update an element of the viewport list or append a new one at the end.
+///
+/// @param viewport_list Pointer to a previously allocated viewport list.
+/// @param index Index of the buffer viewport entry to update. If the
+///     `viewport_list` size is equal to the index, a new viewport entry will be
+///     added. The `viewport_list` size must *not* be less than the index value.
+/// @param viewport A pointer to the buffer viewport object.
+void gvr_buffer_viewport_list_set_item(gvr_buffer_viewport_list* viewport_list,
+                                       size_t index,
+                                       const gvr_buffer_viewport* viewport);
+
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Swapchains and frames
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup swap_chain Swap chains and frames
+/// @brief Functions to create a swap chain, manipulate it and submit frames
+///     for lens distortion and presentation on the screen.
+/// @{
+
+/// Creates a default buffer specification.
+gvr_buffer_spec* gvr_buffer_spec_create(gvr_context* gvr);
+
+/// Destroy the buffer specification and null the pointer.
+void gvr_buffer_spec_destroy(gvr_buffer_spec** spec);
+
+/// Gets the size of the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @return Size of the pixel buffer. The default is equal to the recommended
+///     render target size at the time when the specification was created.
+gvr_sizei gvr_buffer_spec_get_size(const gvr_buffer_spec* spec);
+
+/// Sets the size of the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @param size The size. Width and height must both be greater than zero.
+///     Otherwise, the application is aborted.
+void gvr_buffer_spec_set_size(gvr_buffer_spec* spec, gvr_sizei size);
+
+/// Gets the number of samples per pixel in the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @return Value >= 1 giving the number of samples. 1 means multisampling is
+///     disabled. Negative values and 0 are never returned.
+int32_t gvr_buffer_spec_get_samples(const gvr_buffer_spec* spec);
+
+/// Sets the number of samples per pixel in the buffer to be created.
+///
+/// @param spec Buffer specification.
+/// @param num_samples The number of samples. Negative values are an error.
+///     The values 0 and 1 are treated identically and indicate that
+//      multisampling should be disabled.
+void gvr_buffer_spec_set_samples(gvr_buffer_spec* spec, int32_t num_samples);
+
+/// Sets the color format for the buffer to be created. Default format is
+/// GVR_COLOR_FORMAT_RGBA_8888.
+///
+/// @param spec Buffer specification.
+/// @param color_format The color format for the buffer. Valid formats are in
+///     the gvr_color_format_type enum.
+void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec,
+                                      int32_t color_format);
+
+/// Sets the depth and stencil format for the buffer to be created. Currently,
+/// only packed stencil formats are supported. Default format is
+/// GVR_DEPTH_STENCIL_FORMAT_DEPTH_16.
+///
+/// @param spec Buffer specification.
+/// @param depth_stencil_format The depth and stencil format for the buffer.
+///     Valid formats are in the gvr_depth_stencil_format_type enum.
+void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec,
+                                              int32_t depth_stencil_format);
+
+/// Creates a swap chain from the given buffer specifications.
+/// This is a potentially time-consuming operation. All frames within the
+/// swapchain will be allocated. Once rendering is stopped, call
+/// gvr_swap_chain_destroy() to free GPU resources. The passed gvr_context must
+/// not be destroyed until then.
+///
+/// Swap chains can have no buffers. This is useful when only displaying
+/// external surfaces. When `count` is zero, `buffers` must be null.
+///
+/// @param gvr GVR instance for which a swap chain will be created.
+/// @param buffers Array of pixel buffer specifications. Each frame in the
+///     swap chain will be composed of these buffers.
+/// @param count Number of buffer specifications in the array.
+/// @return Opaque handle to the newly created swap chain.
+gvr_swap_chain* gvr_swap_chain_create(gvr_context* gvr,
+                                      const gvr_buffer_spec** buffers,
+                                      int32_t count);
+
+/// Destroys the swap chain and nulls the pointer.
+void gvr_swap_chain_destroy(gvr_swap_chain** swap_chain);
+
+/// Gets the number of buffers in each frame of the swap chain.
+int32_t gvr_swap_chain_get_buffer_count(const gvr_swap_chain* swap_chain);
+
+/// Retrieves the size of the specified pixel buffer. Note that if the buffer
+/// was resized while the current frame was acquired, the return value will be
+/// different than the value obtained from the equivalent function for the
+/// current frame.
+///
+/// @param swap_chain The swap chain.
+/// @param index Index of the pixel buffer.
+/// @return Size of the specified pixel buffer in frames that will be returned
+///     from gvr_swap_chain_acquire_frame().
+gvr_sizei gvr_swap_chain_get_buffer_size(gvr_swap_chain* swap_chain,
+                                         int32_t index);
+
+/// Resizes the specified pixel buffer to the given size. The frames are resized
+/// when they are unused, so the currently acquired frame will not be resized
+/// immediately.
+///
+/// @param swap_chain The swap chain.
+/// @param index Index of the pixel buffer to resize.
+/// @param size New size for the specified pixel buffer.
+void gvr_swap_chain_resize_buffer(gvr_swap_chain* swap_chain, int32_t index,
+                                  gvr_sizei size);
+
+/// Acquires a frame from the swap chain for rendering. Buffers that are part of
+/// the frame can then be bound with gvr_frame_bind_buffer(). Once the frame
+/// is finished and all its constituent buffers are ready, call
+/// gvr_frame_submit() to display it while applying lens distortion.
+///
+/// @param swap_chain The swap chain.
+/// @return Handle to the acquired frame. NULL if the swap chain is invalid,
+///     or if acquire has already been called on this swap chain.
+gvr_frame* gvr_swap_chain_acquire_frame(gvr_swap_chain* swap_chain);
+
+/// Binds a pixel buffer that is part of the frame to the OpenGL framebuffer.
+///
+/// @param frame Frame handle acquired from the swap chain.
+/// @param index Index of the pixel buffer to bind. This corresponds to the
+///     index in the buffer spec list that was passed to
+///     gvr_swap_chain_create().
+void gvr_frame_bind_buffer(gvr_frame* frame, int32_t index);
+
+/// Unbinds any buffers bound from this frame and binds the default OpenGL
+/// framebuffer.
+void gvr_frame_unbind(gvr_frame* frame);
+
+/// Returns the dimensions of the pixel buffer with the specified index. Note
+/// that a frame that was acquired before resizing a swap chain buffer will not
+/// be resized until it is submitted to the swap chain.
+///
+/// @param frame Frame handle.
+/// @param index Index of the pixel buffer to inspect.
+/// @return Dimensions of the specified pixel buffer.
+gvr_sizei gvr_frame_get_buffer_size(const gvr_frame* frame, int32_t index);
+
+/// Gets the name (ID) of the framebuffer object associated with the specified
+/// buffer. The OpenGL state is not modified.
+///
+/// @param frame Frame handle.
+/// @param index Index of a pixel buffer.
+/// @return OpenGL object name (ID) of a framebuffer object which can be used
+///     to render into the buffer. The ID is valid only until the frame is
+///     submitted.
+int32_t gvr_frame_get_framebuffer_object(const gvr_frame* frame, int32_t index);
+
+/// Submits the frame for distortion and display on the screen. The passed
+/// pointer is nulled to prevent reuse.
+///
+/// @param frame The frame to submit.
+/// @param list Buffer view configuration to be used for this frame.
+/// @param head_space_from_start_space Transform from start space (space with
+///     head at the origin at last tracking reset) to head space (space with
+///     head at the origin and axes aligned to the view vector).
+void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list,
+                      gvr_mat4f head_space_from_start_space);
+
+/// Resets the OpenGL framebuffer binding to what it was at the time the
+/// passed gvr_context was created.
+void gvr_bind_default_framebuffer(gvr_context* gvr);
+
+/// @}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head tracking
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup Headtracking Head tracking
+/// @brief Functions for managing head tracking.
+/// @{
+
+/// Gets the current monotonic system time.
+///
+/// @return The current monotonic system time.
+gvr_clock_time_point gvr_get_time_point_now();
+
+/// Gets the rotation from start space to head space.  The head space is a
+/// space where the head is at the origin and faces the -Z direction.
+///
+/// @param gvr Pointer to the gvr instance from which to get the pose.
+/// @param time The time at which to get the head pose. The time should be in
+///     the future. If the time is not in the future, it will be clamped to now.
+/// @return A matrix representation of the rotation from start space (the space
+///     where the head was last reset) to head space (the space with the head
+///     at the origin, and the axes aligned to the view vector).
+gvr_mat4f gvr_get_head_space_from_start_space_rotation(
+    const gvr_context* gvr, const gvr_clock_time_point time);
+
+/// Applies a simple neck model translation based on the rotation of the
+/// provided head pose.
+///
+/// Note: Neck model application may not be appropriate for all tracking
+/// scenarios, e.g., when tracking is non-biological.
+///
+/// @param gvr Pointer to the context instance from which the pose was obtained.
+/// @param head_rotation_in_start_space The head rotation as returned by
+///     gvr_get_head_space_from_start_space_rotation().
+/// @param factor A scaling factor for the neck model offset, clamped from 0 to
+///     1. This should be 1 for most scenarios, while 0 will effectively disable
+///     neck model application. This value can be animated to smoothly
+///     interpolate between alternative (client-defined) neck models.
+/// @return The new head pose with the neck model applied.
+gvr_mat4f gvr_apply_neck_model(const gvr_context* gvr,
+                               gvr_mat4f head_space_from_start_space_rotation,
+                               float factor);
+
+/// Pauses head tracking, disables all sensors (to save power).
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be paused and
+///     sensors disabled.
+void gvr_pause_tracking(gvr_context* gvr);
+
+/// Resumes head tracking, re-enables all sensors.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be resumed.
+void gvr_resume_tracking(gvr_context* gvr);
+
+/// Resets head tracking.
+///
+/// This API call is deprecated. Use gvr_recenter_tracking instead, which
+/// accomplishes the same effects but avoids the undesirable side-effects of
+/// a full reset (temporary loss of tracking quality).
+///
+/// Only to be used by Cardboard apps. Daydream apps must not call this. On the
+/// Daydream platform, recentering is handled automatically and should never
+/// be triggered programatically by applications. Hybrid apps that support both
+/// Cardboard and Daydream must only call this function when in Cardboard mode
+/// (that is, when the phone is paired with a Cardboard viewer), never in
+/// Daydream mode.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be reseted.
+/// @deprecated Calls to this method can be safely replaced by calls to
+//    gvr_recenter_tracking.
+void gvr_reset_tracking(gvr_context* gvr);
+
+/// Recenters the head orientation (resets the yaw to zero, leaving pitch and
+/// roll unmodified).
+///
+/// Only to be used by Cardboard apps. Daydream apps must not call this. On the
+/// Daydream platform, recentering is handled automatically and should never
+/// be triggered programatically by applications. Hybrid apps that support both
+/// Cardboard and Daydream must only call this function when in Cardboard mode
+/// (that is, when the phone is paired with a Cardboard viewer), never in
+/// Daydream mode.
+///
+/// @param gvr Pointer to the gvr instance for which tracking will be
+///     recentered.
+void gvr_recenter_tracking(gvr_context* gvr);
+
+/// @}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Head mounted display.
+/////////////////////////////////////////////////////////////////////////////
+/// @defgroup HMD Head Mounted Display
+/// @brief Functions for managing viewer information.
+/// @{
+
+/// Sets the default viewer profile specified by viewer_profile_uri.
+/// The viewer_profile_uri that is passed in will be ignored if a valid
+/// viewer profile has already been stored on the device that the app
+/// is running on.
+///
+/// Note: This function has the potential of blocking for up to 30 seconds for
+/// each redirect if a shortened URI is passed in as argument. It will try to
+/// unroll the shortened URI for a maximum number of 5 times if the redirect
+/// continues. In that case, it is recommended to create a separate thread to
+/// call this function so that other tasks like rendering will not be blocked
+/// on this. The blocking can be avoided if a standard URI is passed in.
+///
+/// @param gvr Pointer to the gvr instance which to set the profile on.
+/// @param viewer_profile_uri A string that contains either the shortened URI or
+///     the standard URI representing the viewer profile that the app should be
+///     using. If the valid viewer profile can be found on the device, the URI
+///     that is passed in will be ignored and nothing will happen. Otherwise,
+///     gvr will look for the viewer profile specified by viewer_profile_uri,
+///     and it will be stored if found. Also, the values will be applied to gvr.
+///     A valid standard URI can be generated from this page:
+///     https://www.google.com/get/cardboard/viewerprofilegenerator/
+/// @return True if the viewer profile specified by viewer_profile_uri was
+///     successfully stored and applied, false otherwise.
+bool gvr_set_default_viewer_profile(gvr_context* gvr,
+                                    const char* viewer_profile_uri);
+
+/// Refreshes gvr_context with the viewer profile that is stored on the device.
+/// If it can not find the viewer profile, nothing will happen.
+///
+/// @param gvr Pointer to the gvr instance to refresh the profile on.
+void gvr_refresh_viewer_profile(gvr_context* gvr);
+
+/// Gets the name of the viewer vendor.
+///
+/// @param gvr Pointer to the gvr instance from which to get the vendor.
+/// @return A pointer to the vendor name. May be NULL if no viewer is paired.
+///     WARNING: This method guarantees the validity of the returned pointer
+///     only until the next use of the `gvr` context. The string should be
+///     copied immediately if persistence is required.
+const char* gvr_get_viewer_vendor(const gvr_context* gvr);
+
+/// Gets the name of the viewer model.
+///
+/// @param gvr Pointer to the gvr instance from which to get the name.
+/// @return A pointer to the model name. May be NULL if no viewer is paired.
+///     WARNING: This method guarantees the validity of the returned pointer
+///     only until the next use of the `gvr` context. The string should be
+///     copied immediately if persistence is required.
+const char* gvr_get_viewer_model(const gvr_context* gvr);
+
+/// Gets the type of the viewer, as defined by gvr_viewer_type.
+///
+/// @param gvr Pointer to the gvr instance from which to get the viewer type.
+/// @return The gvr_viewer_type of the currently paired viewer.
+int32_t gvr_get_viewer_type(const gvr_context* gvr);
+
+/// Gets the transformation matrix to convert from Head Space to Eye Space for
+/// the given eye.
+///
+/// @param gvr Pointer to the gvr instance from which to get the matrix.
+/// @param eye Selected gvr_eye type.
+/// @return Transformation matrix from Head Space to selected Eye Space.
+gvr_mat4f gvr_get_eye_from_head_matrix(const gvr_context* gvr,
+                                       const int32_t eye);
+
+/// Gets the window bounds.
+///
+/// @param gvr Pointer to the gvr instance from which to get the bounds.
+///
+/// @return Window bounds in physical pixels.
+gvr_recti gvr_get_window_bounds(const gvr_context* gvr);
+
+/// Computes the distorted point for a given point in a given eye.  The
+/// distortion inverts the optical distortion caused by the lens for the eye.
+/// Due to chromatic aberration, the distortion is different for each
+/// color channel.
+///
+/// @param gvr Pointer to the gvr instance which will do the computing.
+/// @param eye The gvr_eye type (left or right).
+/// @param uv_in A point in screen eye Viewport Space in [0,1]^2 with (0, 0)
+///     in the lower left corner of the eye's viewport and (1, 1) in the
+///     upper right corner of the eye's viewport.
+/// @param uv_out A pointer to an array of (at least) 3 elements, with each
+///     element being a Point2f representing a point in render texture eye
+///     Viewport Space in [0,1]^2 with (0, 0) in the lower left corner of the
+///     eye's viewport and (1, 1) in the upper right corner of the eye's
+///     viewport.
+///     `uv_out[0]` is the corrected position of `uv_in` for the red channel
+///     `uv_out[1]` is the corrected position of `uv_in` for the green channel
+///     `uv_out[2]` is the corrected position of `uv_in` for the blue channel
+void gvr_compute_distorted_point(const gvr_context* gvr, const int32_t eye,
+                                 const gvr_vec2f uv_in, gvr_vec2f uv_out[3]);
+
+/// @}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+namespace gvr {
+
+/// Convenience C++ wrapper for gvr_user_prefs.
+class UserPrefs {
+ public:
+  /// Creates a C++ wrapper for a gvr_user_prefs object. Note that unlike most
+  /// of the C++ wrappers in the API, this does not take ownership, as the
+  /// gvr_user_prefs will remain valid for the lifetime of the GVR context.
+  explicit UserPrefs(const gvr_user_prefs* user_prefs)
+      : user_prefs_(user_prefs) {}
+
+  UserPrefs(UserPrefs&& other) : user_prefs_(nullptr) {
+    std::swap(user_prefs_, other.user_prefs_);
+  }
+
+  UserPrefs& operator=(UserPrefs&& other) {
+    std::swap(user_prefs_, other.user_prefs_);
+    return *this;
+  }
+
+  /// For more information, see gvr_user_prefs_get_controller_handedness().
+  ControllerHandedness GetControllerHandedness() const {
+    return static_cast<ControllerHandedness>(
+        gvr_user_prefs_get_controller_handedness(user_prefs_));
+  }
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  const gvr_user_prefs* cobj() const { return user_prefs_; }
+
+ private:
+  const gvr_user_prefs* user_prefs_;
+
+  // Disallow copy and assign.
+  UserPrefs(const UserPrefs&);
+  void operator=(const UserPrefs&);
+};
+
+/// Convenience C++ wrapper for the opaque gvr_buffer_viewport type.
+/// The constructor allocates memory, so when used in tight loops, instances
+/// should be reused.
+class BufferViewport {
+ public:
+  BufferViewport(BufferViewport&& other)
+      : viewport_(nullptr) {
+    std::swap(viewport_, other.viewport_);
+  }
+
+  BufferViewport& operator=(BufferViewport&& other) {
+    std::swap(viewport_, other.viewport_);
+    return *this;
+  }
+
+  ~BufferViewport() {
+    if (viewport_) gvr_buffer_viewport_destroy(&viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_source_fov().
+  Rectf GetSourceFov() const {
+    return gvr_buffer_viewport_get_source_fov(viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_source_fov().
+  void SetSourceFov(const Rectf& fov) {
+    gvr_buffer_viewport_set_source_fov(viewport_, fov);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_transform().
+  Mat4f GetTransform() const {
+    return gvr_buffer_viewport_get_transform(viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_transform().
+  void SetTransform(const Mat4f& transform) {
+    gvr_buffer_viewport_set_transform(viewport_, transform);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_source_uv().
+  Rectf GetSourceUv() const {
+    return gvr_buffer_viewport_get_source_uv(viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_source_uv().
+  void SetSourceUv(const Rectf& uv) {
+    gvr_buffer_viewport_set_source_uv(viewport_, uv);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_target_eye().
+  Eye GetTargetEye() const {
+    return static_cast<Eye>(gvr_buffer_viewport_get_target_eye(viewport_));
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_target_eye().
+  void SetTargetEye(Eye eye) {
+    gvr_buffer_viewport_set_target_eye(viewport_, eye);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_source_buffer_index().
+  int32_t GetSourceBufferIndex() const {
+    return gvr_buffer_viewport_get_source_buffer_index(viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_source_buffer_index().
+  void SetSourceBufferIndex(int32_t buffer_index) {
+    gvr_buffer_viewport_set_source_buffer_index(viewport_, buffer_index);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_external_surface_id().
+  int32_t GetExternalSurfaceId() const {
+    return gvr_buffer_viewport_get_external_surface_id(viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_set_external_surface_id().
+  void SetExternalSurfaceId(const int32_t external_surface_id) {
+    gvr_buffer_viewport_set_external_surface_id(viewport_, external_surface_id);
+  }
+
+  /// For more information, see gvr_buffer_viewport_get_reprojection().
+  gvr_reprojection GetReprojection() const {
+    return static_cast<gvr_reprojection>(
+        gvr_buffer_viewport_get_reprojection(viewport_));
+  }
+  /// For more information, see gvr_buffer_viewport_set_reprojection().
+  void SetReprojection(gvr_reprojection reprojection) {
+    gvr_buffer_viewport_set_reprojection(viewport_, reprojection);
+  }
+
+  /// For more information, see gvr_buffer_viewport_equal().
+  bool operator==(const BufferViewport& other) const {
+    return gvr_buffer_viewport_equal(viewport_, other.viewport_) ? true : false;
+  }
+  bool operator!=(const BufferViewport& other) const {
+    return !(*this == other);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit BufferViewport(gvr_buffer_viewport* viewport)
+      : viewport_(viewport) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_buffer_viewport* cobj() { return viewport_; }
+  const gvr_buffer_viewport* cobj() const { return viewport_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_buffer_viewport* release() {
+    auto result = viewport_;
+    viewport_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  friend class GvrApi;
+  friend class BufferViewportList;
+
+  explicit BufferViewport(gvr_context* gvr)
+      : viewport_(gvr_buffer_viewport_create(gvr)) {}
+
+  gvr_buffer_viewport* viewport_;
+};
+
+/// Convenience C++ wrapper for the opaque gvr_buffer_viewport_list type. This
+/// class will automatically release the wrapped gvr_buffer_viewport_list upon
+/// destruction. It can only be created via a `GvrApi` instance, and its
+/// validity is tied to the lifetime of that instance.
+class BufferViewportList {
+ public:
+  BufferViewportList(BufferViewportList&& other)
+      : context_(nullptr), viewport_list_(nullptr) {
+    std::swap(context_, other.context_);
+    std::swap(viewport_list_, other.viewport_list_);
+  }
+
+  BufferViewportList& operator=(BufferViewportList&& other) {
+    std::swap(context_, other.context_);
+    std::swap(viewport_list_, other.viewport_list_);
+    return *this;
+  }
+
+  ~BufferViewportList() {
+    if (viewport_list_) {
+      gvr_buffer_viewport_list_destroy(&viewport_list_);
+    }
+  }
+
+  /// For more information, see gvr_get_recommended_buffer_viewports().
+  void SetToRecommendedBufferViewports() {
+    gvr_get_recommended_buffer_viewports(context_, viewport_list_);
+  }
+
+  /// For more information, see gvr_get_screen_buffer_viewports().
+  void SetToScreenBufferViewports() {
+    gvr_get_screen_buffer_viewports(context_, viewport_list_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_list_set_item().
+  void SetBufferViewport(size_t index, const BufferViewport& viewport) {
+    gvr_buffer_viewport_list_set_item(viewport_list_, index,
+                                      viewport.viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_list_get_item().
+  void GetBufferViewport(size_t index, BufferViewport* viewport) const {
+    gvr_buffer_viewport_list_get_item(viewport_list_, index,
+                                      viewport->viewport_);
+  }
+
+  /// For more information, see gvr_buffer_viewport_list_get_size().
+  size_t GetSize() const {
+    return gvr_buffer_viewport_list_get_size(viewport_list_);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  BufferViewportList(gvr_buffer_viewport_list* viewport_list,
+                     gvr_context* context)
+      : context_(context),
+        viewport_list_(viewport_list) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_buffer_viewport_list* cobj() { return viewport_list_; }
+  const gvr_buffer_viewport_list* cobj() const { return viewport_list_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_buffer_viewport_list* release() {
+    auto result = viewport_list_;
+    viewport_list_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  friend class Frame;
+  friend class GvrApi;
+  friend class SwapChain;
+
+  explicit BufferViewportList(gvr_context* context)
+      : context_(context),
+        viewport_list_(gvr_buffer_viewport_list_create(context)) {}
+
+  const gvr_context* context_;
+  gvr_buffer_viewport_list* viewport_list_;
+
+  // Disallow copy and assign.
+  BufferViewportList(const BufferViewportList&) = delete;
+  void operator=(const BufferViewportList&) = delete;
+};
+
+/// Convenience C++ wrapper for gvr_buffer_spec, an opaque pixel buffer
+/// specification. Frees the underlying gvr_buffer_spec on destruction.
+class BufferSpec {
+ public:
+  BufferSpec(BufferSpec&& other)
+      : spec_(nullptr) {
+    std::swap(spec_, other.spec_);
+  }
+
+  BufferSpec& operator=(BufferSpec&& other) {
+    std::swap(spec_, other.spec_);
+    return *this;
+  }
+
+  ~BufferSpec() {
+    if (spec_) gvr_buffer_spec_destroy(&spec_);
+  }
+
+  /// Gets the buffer's size. The default value is the recommended render
+  /// target size. For more information, see gvr_buffer_spec_get_size().
+  Sizei GetSize() const {
+    return gvr_buffer_spec_get_size(spec_);
+  }
+
+  /// Sets the buffer's size. For more information, see
+  /// gvr_buffer_spec_set_size().
+  void SetSize(const Sizei& size) {
+    gvr_buffer_spec_set_size(spec_, size);
+  }
+
+  /// Sets the buffer's size to the passed width and height. For more
+  /// information, see gvr_buffer_spec_set_size().
+  ///
+  /// @param width The width in pixels. Must be greater than 0.
+  /// @param height The height in pixels. Must be greater than 0.
+  void SetSize(int32_t width, int32_t height) {
+    gvr_sizei size{width, height};
+    gvr_buffer_spec_set_size(spec_, size);
+  }
+
+  /// Gets the number of samples per pixel in the buffer. For more
+  /// information, see gvr_buffer_spec_get_samples().
+  int32_t GetSamples() const { return gvr_buffer_spec_get_samples(spec_); }
+
+  /// Sets the number of samples per pixel. For more information, see
+  /// gvr_buffer_spec_set_samples().
+  void SetSamples(int32_t num_samples) {
+    gvr_buffer_spec_set_samples(spec_, num_samples);
+  }
+
+  /// Sets the color format for this buffer. For more information, see
+  /// gvr_buffer_spec_set_color_format().
+  void SetColorFormat(ColorFormat color_format) {
+    gvr_buffer_spec_set_color_format(spec_, color_format);
+  }
+
+  /// Sets the depth and stencil format for this buffer. For more
+  /// information, see gvr_buffer_spec_set_depth_stencil_format().
+  void SetDepthStencilFormat(DepthStencilFormat depth_stencil_format) {
+    gvr_buffer_spec_set_depth_stencil_format(spec_, depth_stencil_format);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit BufferSpec(gvr_buffer_spec* spec) : spec_(spec) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_buffer_spec* cobj() { return spec_; }
+  const gvr_buffer_spec* cobj() const { return spec_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_buffer_spec* release() {
+    auto result = spec_;
+    spec_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  friend class GvrApi;
+  friend class SwapChain;
+
+  explicit BufferSpec(gvr_context* gvr) {
+    spec_ = gvr_buffer_spec_create(gvr);
+  }
+
+  gvr_buffer_spec* spec_;
+};
+
+/// Convenience C++ wrapper for gvr_frame, which represents a single frame
+/// acquired for rendering from the swap chain.
+class Frame {
+ public:
+  Frame(Frame&& other) : frame_(nullptr) {
+    std::swap(frame_, other.frame_);
+  }
+
+  Frame& operator=(Frame&& other) {
+    std::swap(frame_, other.frame_);
+    return *this;
+  }
+
+  ~Frame() {
+    // The swap chain owns the frame, so no clean-up is required.
+  }
+
+  /// For more information, see gvr_frame_get_buffer_size().
+  Sizei GetBufferSize(int32_t index) const {
+    return gvr_frame_get_buffer_size(frame_, index);
+  }
+
+  /// For more information, see gvr_frame_bind_buffer().
+  void BindBuffer(int32_t index) {
+    gvr_frame_bind_buffer(frame_, index);
+  }
+
+  /// For more information, see gvr_frame_unbind().
+  void Unbind() {
+    gvr_frame_unbind(frame_);
+  }
+
+  /// For more information, see gvr_frame_get_framebuffer_object().
+  int32_t GetFramebufferObject(int32_t index) {
+    return gvr_frame_get_framebuffer_object(frame_, index);
+  }
+
+  /// For more information, see gvr_frame_submit().
+  void Submit(const BufferViewportList& viewport_list,
+              const Mat4f& head_space_from_start_space) {
+    gvr_frame_submit(&frame_, viewport_list.viewport_list_,
+                     head_space_from_start_space);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit Frame(gvr_frame* frame) : frame_(frame) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_frame* cobj() { return frame_; }
+  const gvr_frame* cobj() const { return frame_; }
+
+  /// Returns whether the wrapped gvr_frame reference is valid.
+  bool is_valid() const { return frame_ != nullptr; }
+  explicit operator bool const() { return is_valid(); }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_frame* release() {
+    auto result = frame_;
+    frame_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  friend class SwapChain;
+
+  gvr_frame* frame_;
+};
+
+/// Convenience C++ wrapper for gvr_swap_chain, which represents a queue of
+/// frames. The GvrApi object must outlive any SwapChain objects created from
+/// it.
+class SwapChain {
+ public:
+  SwapChain(SwapChain&& other)
+      : swap_chain_(nullptr) {
+    std::swap(swap_chain_, other.swap_chain_);
+  }
+
+  SwapChain& operator=(SwapChain&& other) {
+    std::swap(swap_chain_, other.swap_chain_);
+    return *this;
+  }
+
+  ~SwapChain() {
+    if (swap_chain_) gvr_swap_chain_destroy(&swap_chain_);
+  }
+
+  /// For more information, see gvr_swap_chain_get_buffer_count().
+  int32_t GetBufferCount() const {
+    return gvr_swap_chain_get_buffer_count(swap_chain_);
+  }
+
+  /// For more information, see gvr_swap_chain_get_buffer_size().
+  Sizei GetBufferSize(int32_t index) const {
+    return gvr_swap_chain_get_buffer_size(swap_chain_, index);
+  }
+
+  /// For more information, see gvr_swap_chain_resize_buffer().
+  void ResizeBuffer(int32_t index, Sizei size) {
+    gvr_swap_chain_resize_buffer(swap_chain_, index, size);
+  }
+
+  /// For more information, see gvr_swap_chain_acquire_frame().
+  /// Note that if Frame acquisition fails, the returned Frame may not be valid.
+  /// The caller should inspect the returned Frame's validity before using,
+  /// and reschedule frame acquisition upon failure.
+  Frame AcquireFrame() {
+    Frame result(gvr_swap_chain_acquire_frame(swap_chain_));
+    return result;
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit SwapChain(gvr_swap_chain* swap_chain) : swap_chain_(swap_chain) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_swap_chain* cobj() { return swap_chain_; }
+  const gvr_swap_chain* cobj() const { return swap_chain_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_swap_chain* release() {
+    auto result = swap_chain_;
+    swap_chain_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  friend class GvrApi;
+
+  SwapChain(gvr_context* gvr, const std::vector<BufferSpec>& specs) {
+    std::vector<const gvr_buffer_spec*> c_specs;
+    for (const auto& spec : specs)
+      c_specs.push_back(spec.spec_);
+    swap_chain_ = gvr_swap_chain_create(gvr, c_specs.data(),
+                                        static_cast<int32_t>(c_specs.size()));
+  }
+
+  gvr_swap_chain* swap_chain_;
+
+  // Disallow copy and assign.
+  SwapChain(const SwapChain&);
+  void operator=(const SwapChain&);
+};
+
+/// This is a convenience C++ wrapper for the Google VR C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+/// Example API usage:
+///
+///     // Functionality supplied by the application in the example below has
+///     // the "app-" prefix.
+///     #ifdef __ANDROID__
+///     // On Android, the gvr_context should almost always be obtained from the
+///     // Java GvrLayout object via
+///     // GvrLayout.getGvrApi().getNativeGvrContext().
+///     std::unique_ptr<GvrApi> gvr = GvrApi::WrapNonOwned(gvr_context);
+///     #else
+///     std::unique_ptr<GvrApi> gvr = GvrApi::Create();
+///     #endif
+///
+///     gvr->InitializeGl();
+///
+///     gvr::BufferViewportList viewport_list =
+///         gvr->CreateEmptyBufferViewportList();
+///     gvr->GetRecommendedBufferViewports(&viewport_list);
+///     gvr::BufferViewport left_eye_viewport = gvr->CreateBufferViewport();
+///     gvr::BufferViewport right_eye_viewport = gvr->CreateBufferViewport();
+///     viewport_list.Get(0, &left_eye_view);
+///     viewport_list.Get(1, &right_eye_view);
+///
+///     std::vector<gvr::BufferSpec> specs;
+///     specs.push_back(gvr->CreateBufferSpec());
+///     specs[0].SetSamples(app_samples);
+///     gvr::SwapChain swap_chain = gvr->CreateSwapChain(specs);
+///
+///     while (client_app_should_render) {
+///       // A client app should be ready for the render target size to change
+///       // whenever a new QR code is scanned, or a new viewer is paired.
+///       gvr::Sizei render_target_size =
+///           gvr->GetRecommendedRenderTargetSize();
+///       swap_chain.ResizeBuffer(0, render_target_size);
+///       gvr::Frame frame = swap_chain.AcquireFrame();
+///       while (!frame) {
+///         std::this_thread::sleep_for(2ms);
+///         frame = swap_chain.AcquireFrame();
+///       }
+///
+///       // This function will depend on your render loop's implementation.
+///       gvr::ClockTimePoint next_vsync = AppGetNextVsyncTime();
+///
+///       const gvr::Mat4f head_view =
+///           gvr->GetHeadSpaceFromStartSpaceRotation(next_vsync);
+///       const gvr::Mat4f left_eye_view = MatrixMultiply(
+///           gvr->GetEyeFromHeadMatrix(kLeftEye), head_view);
+///       const gvr::Mat4f right_eye_view = MatrixMultiply(
+///           gvr->GetEyeFromHeadMatrix(kRightEye), head_view);
+///
+///       frame.BindBuffer(0);
+///       // App does its rendering to the current framebuffer here.
+///       AppDoSomeRenderingForEye(
+///           left_eye_viewport.GetSourceUv(), left_eye_view);
+///       AppDoSomeRenderingForEye(
+///           right_eye_viewport.GetSourceUv(), right_eye_view);
+///       frame.Unbind();
+///       frame.Submit(viewport_list, head_matrix);
+///     }
+///
+class GvrApi {
+ public:
+#ifdef __ANDROID__
+  /// Instantiates and returns a GvrApi instance that owns a gvr_context.
+  ///
+  /// @param env The JNIEnv associated with the current thread.
+  /// @param app_context The Android application context. This must be the
+  ///     application context, NOT an Activity context (Note: from any Android
+  ///     Activity in your app, you can call getApplicationContext() to
+  ///     retrieve the application context).
+  /// @param class_loader The class loader to use when loading Java classes.
+  ///     This must be your app's main class loader (usually accessible through
+  ///     activity.getClassLoader() on any of your Activities).
+  /// @return unique_ptr to the created GvrApi instance, nullptr on failure.
+  static std::unique_ptr<GvrApi> Create(JNIEnv* env, jobject app_context,
+                                        jobject class_loader) {
+    gvr_context* context = gvr_create(env, app_context, class_loader);
+    if (!context) {
+      return nullptr;
+    }
+    return std::unique_ptr<GvrApi>(new GvrApi(context, true /* owned */));
+  }
+#else
+  /// Instantiates and returns a GvrApi instance that owns a gvr_context.
+  ///
+  /// @return unique_ptr to the created GvrApi instance, nullptr on failure.
+  static std::unique_ptr<GvrApi> Create() {
+    gvr_context* context = gvr_create();
+    if (!context) {
+      return nullptr;
+    }
+    return std::unique_ptr<GvrApi>(new GvrApi(context, true /* owned */));
+  }
+#endif  // #ifdef __ANDROID__
+
+  ~GvrApi() {
+    if (context_ && owned_) {
+      gvr_destroy(&context_);
+    }
+  }
+
+  /// @name Error handling
+  /// @{
+
+  /// For more information, see gvr_get_error().
+  Error GetError() { return static_cast<Error>(gvr_get_error(context_)); }
+
+  /// For more information, see gvr_clear_error().
+  Error ClearError() { return static_cast<Error>(gvr_clear_error(context_)); }
+
+  /// For more information, see gvr_get_error_string().
+  static const char* GetErrorString(Error error_code) {
+    return gvr_get_error_string(error_code);
+  }
+
+  /// For more information, see gvr_get_user_prefs().
+  UserPrefs GetUserPrefs() { return UserPrefs(gvr_get_user_prefs(context_)); }
+
+  /// @}
+
+  /// @name Rendering
+  /// @{
+
+  /// For more information, see gvr_initialize_gl().
+  void InitializeGl() { gvr_initialize_gl(context_); }
+
+  /// For more information, see gvr_get_async_reprojection_enabled().
+  bool GetAsyncReprojectionEnabled() const {
+    return gvr_get_async_reprojection_enabled(context_);
+  }
+
+  /// Constructs a C++ wrapper for a gvr_buffer_viewport object.  For more
+  /// information, see gvr_buffer_viewport_create().
+  ///
+  /// @return A new BufferViewport instance with memory allocated for an
+  ///     underlying gvr_buffer_viewport.
+  BufferViewport CreateBufferViewport() const {
+    return BufferViewport(context_);
+  }
+
+  /// Constructs a C++ wrapper for a gvr_buffer_viewport_list object.
+  /// For more information, see gvr_buffer_viewport_list_create().
+  ///
+  /// @return A new, empty BufferViewportList instance.
+  ///     Note: The validity of the returned object is closely tied to the
+  ///     lifetime of the member gvr_context. The caller is responsible for
+  ///     ensuring correct usage accordingly.
+  BufferViewportList CreateEmptyBufferViewportList() const {
+    return BufferViewportList(context_);
+  }
+
+  /// For more information, see gvr_get_maximum_effective_render_target_size().
+  Sizei GetMaximumEffectiveRenderTargetSize() const {
+    return gvr_get_maximum_effective_render_target_size(context_);
+  }
+
+  /// For more information, see gvr_get_screen_target_size().
+  Sizei GetScreenTargetSize() const {
+    return gvr_get_screen_target_size(context_);
+  }
+
+  /// For more information, see gvr_set_surface_size().
+  void SetSurfaceSize(Sizei surface_size_pixels) {
+    gvr_set_surface_size(context_, surface_size_pixels);
+  }
+
+  /// For more information, see gvr_distort_to_screen().
+  void DistortToScreen(int32_t texture_id,
+                       const BufferViewportList& viewport_list,
+                       const Mat4f& rendered_head_pose_in_start_space_matrix,
+                       const ClockTimePoint& texture_presentation_time) {
+    gvr_distort_to_screen(context_, texture_id, viewport_list.viewport_list_,
+                          rendered_head_pose_in_start_space_matrix,
+                          texture_presentation_time);
+  }
+
+  /// For more information, see gvr_buffer_spec_create().
+  BufferSpec CreateBufferSpec() {
+    return BufferSpec(context_);
+  }
+
+  /// For more information, see gvr_swap_chain_create().
+  SwapChain CreateSwapChain(const std::vector<BufferSpec>& specs) {
+    return SwapChain(context_, specs);
+  }
+
+  /// For more information, see gvr_bind_default_framebuffer().
+  void BindDefaultFramebuffer() {
+    gvr_bind_default_framebuffer(context_);
+  }
+  /// @}
+
+  /// @name Head tracking
+  /// @{
+
+  /// For more information see gvr_get_head_space_from_start_space_rotation.
+  ///
+  /// @param time_point The time at which to calculate the head pose in start
+  ///     space.
+  /// @return The matrix representation of the rotation from start space
+  ///     (the space with the head pose at the last tracking reset at origin) to
+  ///     head space (the space with the head at origin and axes aligned to the
+  ///     view vector).
+  Mat4f GetHeadSpaceFromStartSpaceRotation(const ClockTimePoint& time_point) {
+    return gvr_get_head_space_from_start_space_rotation(context_, time_point);
+  }
+
+  /// For more information, see gvr_apply_neck_model().
+  Mat4f ApplyNeckModel(const Mat4f& head_pose_in_start_space, float factor) {
+    return gvr_apply_neck_model(context_, head_pose_in_start_space, factor);
+  }
+
+  /// For more information, see gvr_pause_tracking().
+  void PauseTracking() { gvr_pause_tracking(context_); }
+
+  /// For more information, see gvr_resume_tracking().
+  void ResumeTracking() { gvr_resume_tracking(context_); }
+
+  /// For more information, see gvr_reset_tracking().
+  void ResetTracking() { gvr_reset_tracking(context_); }
+
+  // For more information, see gvr_recenter_tracking().
+  void RecenterTracking() { gvr_recenter_tracking(context_); }
+
+  /// For more information, see gvr_get_time_point_now().
+  static ClockTimePoint GetTimePointNow() { return gvr_get_time_point_now(); }
+  /// @}
+
+  /// @name Viewer parameters
+  /// @{
+
+  /// For more information, see gvr_set_default_viewer_profile().
+  bool SetDefaultViewerProfile(const char* viewer_profile_uri) {
+    return gvr_set_default_viewer_profile(context_, viewer_profile_uri);
+  }
+
+  /// For more information, see gvr_refresh_viewer_profile().
+  void RefreshViewerProfile() { gvr_refresh_viewer_profile(context_); }
+
+  /// For more information, see gvr_get_viewer_vendor().
+  const char* GetViewerVendor() const {
+    return gvr_get_viewer_vendor(context_);
+  }
+
+  /// For more information, see gvr_get_viewer_model().
+  const char* GetViewerModel() const { return gvr_get_viewer_model(context_); }
+
+  /// For more information, see gvr_get_viewer_type().
+  ViewerType GetViewerType() const {
+    return static_cast<ViewerType>(gvr_get_viewer_type(context_));
+  }
+
+  /// For more information, see gvr_get_eye_from_head_matrix().
+  Mat4f GetEyeFromHeadMatrix(Eye eye) const {
+    return gvr_get_eye_from_head_matrix(context_, eye);
+  }
+
+  /// For more information, see gvr_get_window_bounds().
+  Recti GetWindowBounds() const { return gvr_get_window_bounds(context_); }
+
+  /// For more information, see gvr_compute_distorted_point().
+  std::array<Vec2f, 3> ComputeDistortedPoint(Eye eye, const Vec2f& uv_in) {
+    std::array<Vec2f, 3> uv_out = {{{}}};
+    gvr_compute_distorted_point(context_, eye, uv_in, uv_out.data());
+    return uv_out;
+  }
+  /// @}
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and optionally takes ownership.
+  ///
+  /// @param context C object to wrap.
+  /// @param owned Whether the wrapper will own the underlying C object.
+  explicit GvrApi(gvr_context* context, bool owned = true)
+      : context_(context), owned_(owned) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_context* cobj() { return context_; }
+  const gvr_context* cobj() const { return context_; }
+
+  /// @deprecated Use cobj() instead.
+  gvr_context* GetContext() { return context_; }
+  /// @deprecated Use cobj() instead.
+  const gvr_context* GetContext() const { return context_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_context* release() {
+    auto result = context_;
+    context_ = nullptr;
+    return result;
+  }
+
+  /// Instantiates a GvrApi instance that wraps a *non-owned* gvr_context.
+  ///
+  /// Ownership of the provided `context` remains with the caller, and they
+  /// are responsible for ensuring proper disposal of the context.
+  ///
+  /// @param context Pointer to a non-null, non-owned gvr_context instance.
+  /// @return unique_ptr to the created GvrApi instance. Never null.
+  static std::unique_ptr<GvrApi> WrapNonOwned(gvr_context* context) {
+    return std::unique_ptr<GvrApi>(new GvrApi(context, false /* owned */));
+  }
+  /// @}
+
+ private:
+  gvr_context* context_;
+
+  // Whether context_ is owned by the GvrApi instance. If owned, the context
+  // will be released upon destruction.
+  const bool owned_;
+
+  // Disallow copy and assign.
+  GvrApi(const GvrApi&);
+  void operator=(const GvrApi&);
+};
+
+}  // namespace gvr
+#endif  // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h
new file mode 100644
index 0000000..eee3d0c
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_audio.h
@@ -0,0 +1,854 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
+
+#if __ANDROID__
+#include <jni.h>
+#endif  // __ANDROID__
+
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr.h"
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+/// @defgroup Audio Spatial Audio API
+/// @brief This is the GVR Audio C API, a spatial audio rendering engine,
+/// optimized for mobile VR.
+///
+/// It allows the user to spatialize sound sources in 3D space, including
+/// distance and elevation cues. Specifically, the API is capable of playing
+/// back spatial sound in three ways:
+///
+/// - **Sound object rendering**: This allows the user to create a virtual sound
+///   source in 3D space. These sources, while spatialized, are fed with mono
+///   audio data.
+///
+/// - **Ambisonic soundfields**: Ambisonic recordings are multi-channel audio
+///   files which are spatialized all around the listener in 360 degrees. These
+///   can be thought of as recorded or pre-baked soundfields. They can be of
+///   great use for background effects which sound perfectly spatial.  Examples
+///   include rain noise, crowd noise or even the sound of the ocean off to one
+///   side.
+///
+/// - **Stereo Sounds**: This allows the user to directly play back
+///   non-spatialized mono or stereo audio files. This is useful for music and
+///   other such audio.
+///
+/// **Initialization**
+///
+///     gvr_audio_context* gvr_audio_create(int32_t rendering_mode);
+///
+/// The rendering_mode argument corresponds to a `gvr_audio_rendering_mode` enum
+/// value, which specifies a rendering configuration setting:
+///
+/// - `GVR_AUDIO_RENDERING_STEREO_PANNING`:
+///   Stereo panning of all sound objects. This disables HRTF-based rendering.
+/// - `GVR_AUDIO_RENDERING_BINAURAL_LOW_QUALITY`:
+///   This renders sound objects over a virtual array of 8 loudspeakers arranged
+///   in a cube configuration around the listener’s head. HRTF-based rendering
+///   is enabled.
+/// - `GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY`:
+///   This renders sound objects over a virtual array of 16 loudspeakers
+///   arranged in an approximate equidistribution about the listener’s
+///   head. HRTF-based rendering is enabled.
+///
+/// For most modern phones, the high quality mode offers a good balance between
+/// performance and audio quality. To optimize the rendering performance for
+/// headphones *and* speaker playback, the stereo speaker mode can be enabled
+/// which automatically switches to stereo panning when no headphone is plugin.
+/// Note that this can lead to varying CPU usage based on headphone and speaker
+/// playback.
+///
+/// **Sound engine control**
+///
+/// Audio playback on the default audio device can be started and stopped by
+/// calling the following two methods:
+///
+///     void gvr_audio_pause(gvr_audio_context* api);
+///     void gvr_audio_resume(gvr_audio_context* api);
+///
+/// Note that:
+///
+///     void gvr_audio_update(gvr_audio_context* api);
+///
+/// must be called from the main thread at a regular rate. It is used to execute
+/// background operations outside of the audio thread.
+///
+/// **Listener position and rotation**
+///
+/// To ensure that the audio in your application reacts to listener head
+/// movement, it is important to update the listener's head orientation in the
+/// graphics callback using the head orientation matrix.
+///
+/// The following methods can be used to control the listener’s head position
+/// and orientation with the audio engine:
+///
+///     void gvr_audio_set_head_position(gvr_audio_context* api, float x,
+///                                      float y, float z);
+/// or
+///
+///     void gvr_audio_set_head_position_gvr(gvr_audio_context* api,
+///                                          const gvr_vec3f& position);
+///
+/// and
+///
+///     void gvr_audio_set_head_rotation(gvr_audio_context* api,
+///                                      float x, float y, float z, float w);
+/// or
+///
+///     void gvr_audio_set_head_rotation_gvr(gvr_audio_context* api,
+///                                          const gvr_quatf& rotation);
+///
+/// **Preloading Sounds**
+///
+/// Both mono sound files for use with Sound Objects and multi-channel Ambisonic
+/// soundfield files can be preloaded into memory before playback or
+/// alternatively streamed during playback. Preloading can be useful to reduce
+/// CPU usage especially if the same audio clip is likely to be played back many
+/// times. In this case playback latency is also reduced.
+///
+/// Sound files can be preloaded into memory by calling:
+///
+///     bool gvr_audio_preload_soundfile(gvr_audio_context* api,
+///                                      const char* filename);
+///
+/// Unused sound files can be unloaded with a call to:
+///
+///     void gvr_audio_unload_soundfile(gvr_audio_context* api,
+///                                     const char* filename);
+///
+/// NOTE: If a sound object, soundfield or stereo sound is created with a file
+/// that has not been preloaded, that audio will be streamed.
+///
+/// **Spatializtion of sound objects**
+///
+/// The GVR Audio System allows the user to create virtual sound objects which
+/// can be placed anywhere in space around the listener.
+///
+/// To create a new sound object, call:
+///
+///     gvr_audio_source_id
+///     gvr_audio_create_sound_object(gvr_audio_context* api,
+///                                   const char* filename);
+///
+/// This returns a handle that can be used to set properties such as the
+/// position and the volume of the sound object via calls to the following two
+/// functions:
+///
+///     void
+///     gvr_audio_set_sound_object_position(gvr_audio_context* api,
+///                                         gvr_audio_source_id sound_object_id,
+///                                         float x, float y, float z);
+///
+///     void
+///     gvr_audio_set_sound_volume(gvr_audio_context* api,
+///                                gvr_audio_source_id source_id, float volume);
+///
+/// The behavior of Sound Objects with respect to their distance from the
+/// listener can be controlled via calls to the following method:
+///
+///     void gvr_audio_set_sound_object_distance_rolloff_model(
+///         gvr_audio_context* api, gvr_audio_source_id sound_object_id,
+///         int32_t rolloff_model, float min_distance, float max_distance);
+///
+/// This enables a user to choose between logarithmic and linear distance
+/// rolloff methods, or to completely disable distance rolloff effects.
+///
+///
+/// The spatialized playback of a sound object can be triggered with a call to:
+///
+///     void gvr_audio_play_sound(gvr_audio_context* api,
+///                               gvr_audio_source_id source_id,
+///                               bool looping_enabled);
+///
+/// and stopped with a call to:
+///
+///     void gvr_audio_stop_sound(gvr_audio_context* api,
+///                               gvr_audio_source_id source_id);
+///
+/// Note that the sound object handle destroys itself at the moment the sound
+/// playback has stopped. This way, no clean up of sound object handles is
+/// needed. On subsequent calls to this function the corresponding
+/// gvr_audio_source_id no longer refers to a valid sound object.
+///
+/// The following function can be used to check if a sound object is currently
+/// active:
+///
+///     bool gvr_audio_is_sound_playing(const gvr_audio_context* api,
+///                                     gvr_audio_source_id source_id);
+///
+/// **Rendering of ambisonic soundfields**
+///
+/// The GVR Audio System also provides the user with the ability to play back
+/// ambisonic soundfields. Ambisonic soundfields are captured or pre-rendered
+/// 360 degree recordings. It is best to think of them as equivalent to 360
+/// degree video. While they envelop and surround the listener, they only react
+/// to the listener's rotational movement. That is, one cannot walk towards
+/// features in the soundfield. Soundfields are ideal for accompanying 360
+/// degree video playback, for introducing background and environmental effects
+/// such as rain or crowd noise, or even for pre baking 3D audio to reduce
+/// rendering costs.  The GVR Audio System supports full 3D First Order
+/// Ambisonic recordings using ACN channel ordering and SN3D normalization. For
+/// more information please see our Spatial Audio specification at:
+/// https://github.com/google/spatial-media/blob/master/docs/spatial-audio-rfc.md#semantics
+///
+/// Note that Soundfield playback is directly streamed from the sound file and
+/// no sound file preloading is needed.
+///
+/// To obtain a soundfield handler, call:
+///
+///     gvr_audio_source_id gvr_audio_create_soundfield(gvr_audio_context* api,
+///                                                    const char* filename);
+///
+/// This returns a gvr_audio_source_id handle that allows the user to begin
+/// playback of the soundfield, to alter the soundfield’s volume or to stop
+/// soundfield playback and as such destroy the object. These actions can be
+/// achieved with calls to the following functions:
+///
+///     void gvr_audio_play_sound(gvr_audio_context* api,
+///                               gvr_audio_source_id source_id,
+///                               bool looping_enabled);
+///
+///     void gvr_audio_set_sound_volume(gvr_audio_context* api,
+///                                     gvr_audio_source_id source_id,
+///                                     float volume);
+///
+///     void gvr_audio_stop_sound(gvr_audio_context* api,
+///                               gvr_audio_source_id source_id);
+///
+/// Ambisonic soundfields can also be rotated about the listener's head in order
+/// to align the components of the soundfield with the visuals of the game/app.
+///
+/// void gvr_audio_set_soundfield_rotation(gvr_audio_context* api,
+///                                        gvr_audio_source_id soundfield_id,
+///                                        const gvr_quatf&
+///                                        soundfield_rotation);
+///
+/// **Direct Playback of Stereo or Mono Sounds**
+///
+/// The GVR Audio System allows the direct non-spatialized playback of both
+/// stereo and mono audio. Such audio is often used for music or sound effects
+/// that should not be spatialized.
+///
+/// A stereo sound can be created with a call to:
+///
+/// gvr_audio_source_id gvr_audio_create_stereo_sound(gvr_audio_context* api,
+///                                                  const char* filename);
+///
+/// **Paused Sounds and Stopped Sounds**
+///
+/// When using sound sources of any of the above types, the user can ensure that
+/// the given source is currently playing before calling.
+///
+/// bool gvr_audio_is_sound_playing(gvr_audio_source_id source_id);
+///
+/// This method will return false if the source has been either paused or
+/// stopped, and true if the source is currently playing.
+///
+/// Once one is finished with a Sound Object and wish to remove it, a call can
+/// be placed to:
+///
+/// void gvr_audio_stop_sound(gvr_audio_source_id source_id);
+///
+/// Once a source has been stopped it is destroyed and the corresponding
+/// gvr_audio_source_id will be invalid. Sources which have been played with the
+/// |looping_enabled| parameter disabled will also be destroyed once playback
+/// of the full audio clip has completed.
+///
+/// To check whether a given gvr_audio_source_id corresponds to a valid source
+/// which exists and is in a playable state, a call can be made to:
+///
+/// bool gvr_audio_is_source_id_valid(gvr_audio_source_id source_id);
+///
+/// By using this pair of methods a user can differentiate between sources which
+/// have been paused and those which have ceased.
+///
+/// **Room effects**
+///
+/// The GVR Audio System provides a powerful reverb engine which can be used to
+/// create customized room effects by specifying the size of a room and a
+/// material for each surface of the room from the gvr_audio_material_name enum.
+/// Each of these surface materials has unique absorption properties which
+/// differ with frequency. The room created will be centered around the
+/// listener. Note that the Google VR Audio System uses meters as the unit of
+/// distance throughout.
+///
+/// The following methods are used to control room effects:
+///
+///     void gvr_audio_enable_room(gvr_audio_context* api, bool enable);
+///
+/// enables or disables room effects with smooth transitions.
+///
+/// and
+///
+///     void
+///     gvr_audio_set_room_properties(gvr_audio_context* api, float size_x,
+///                                   float size_y, float size_z,
+///                                   gvr_audio_material_name wall_material,
+///                                   gvr_audio_material_name ceiling_material,
+///                                   gvr_audio_material_name floor_material);
+///
+/// allows the user to describe the room based on its dimensions and its surface
+/// properties. For example, one can expect very large rooms to be more
+/// reverberant than smaller rooms, and a room with with hard surface materials
+/// such as brick to be more reverberant than one with soft absorbent materials
+/// such as heavy curtains on every surface.
+///
+/// Note that when a sound source is located outside of the listener's room,
+/// it will sound different from sources located within the room due to
+/// attenuation of both the direct sound and the reverb on that source. Sources
+/// located far outside of the listener's room will not be audible to the
+/// listener.
+///
+/// The following method can be used to subtly adjust the reverb in a room by
+/// changing the gain/attenuation on the reverb, setting a multiplier on the
+/// reverberation time to control the reverb's length, or adjusting the balance
+/// between the low and high frequency components of the reverb.
+///
+/// void gvr_audio_set_room_reverb_adjustments(gvr_audio_context* api,
+///                                            float gain,
+///                                            float time_adjust,
+///                                            float brightness_adjust);
+///
+/// If you are writing C++ code, you might prefer to use the C++ wrapper
+/// rather than implement this C API directly.
+///
+/// **Example usage (C++ API)**
+///
+/// Construction:
+///
+///     std::unique_ptr<gvr::AudioApi> gvr_audio_api(new gvr::AudioApi);
+///     gvr_audio_api->Init(GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY);
+///
+/// Update head rotation in DrawFrame():
+///
+///     head_pose_ = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time);
+///     gvr_audio_api_->SetHeadPose(head_pose_);
+///     gvr_audio_api_->Update();
+///
+/// Preload sound file, create sound handle and start playback:
+///
+///     gvr_audio_api->PreloadSoundfile(kSoundFile);
+///     AudioSourceId source_id =
+///                   gvr_audio_api_->CreateSoundObject("sound.wav");
+///     gvr_audio_api->SetSoundObjectPosition(source_id,
+///                                           position_x,
+///                                           position_y,
+///                                           position_z);
+///     gvr_audio_api->PlaySound(source_id, true /* looped playback */);
+///
+
+/// @{
+
+typedef struct gvr_audio_context_ gvr_audio_context;
+
+/// Creates and initializes a gvr_audio_context. This call also initializes
+/// the audio interface and starts the audio engine. Note that the returned
+/// instance must be deleted with gvr_audio_destroy.
+///
+#ifdef __ANDROID__
+/// @param env The JNI Env associated with the current thread.
+/// @param android_context The Android application context. This must be the
+///     application context, NOT an Activity context (Note: from any Android
+///     Activity in your app, you can call getApplicationContext() to
+///     retrieve the application context).
+/// @param class_loader The class loader to use when loading Java
+///     classes. This must be your app's main class loader (usually
+///     accessible through activity.getClassLoader() on any of your Activities).
+/// @param rendering_mode The gvr_audio_rendering_mode value which determines
+///     the rendering configuration preset. This is passed as an int32_t to
+///     ensure API compatibility.
+/// @return gvr_audio_context instance.
+gvr_audio_context* gvr_audio_create(JNIEnv* env, jobject android_context,
+                                    jobject class_loader,
+                                    int32_t rendering_mode);
+#else
+/// @param rendering_mode The gvr_audio_rendering_mode value which determines
+///     the rendering configuration preset. This is passed as an int32_t to
+///     ensure API compatibility.
+/// @return gvr_audio_context instance.
+gvr_audio_context* gvr_audio_create(int32_t rendering_mode);
+#endif  // #ifdef __ANDROID__
+
+/// Destroys a gvr_audio_context that was previously created with
+/// gvr_audio_create or gvr_audio_create_android.
+///
+/// @param api Pointer to a pointer to a gvr_audio_context. The pointer
+///     will be set to NULL after destruction.
+void gvr_audio_destroy(gvr_audio_context** api);
+
+/// Resumes the VR Audio system.
+/// Call this when your app/game loses focus.
+/// Calling this when not paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_resume(gvr_audio_context* api);
+
+/// Pauses the VR Audio system.
+/// Calling this when already paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_pause(gvr_audio_context* api);
+
+/// This method must be called from the main thread at a regular rate. It is
+/// used to execute background operations outside of the audio thread.
+///
+/// @param api Pointer to a gvr_audio_context.
+void gvr_audio_update(gvr_audio_context* api);
+
+/// Preloads a local sound file. Note that the local file access method
+/// depends on the target platform.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename Name of the file, used as identifier.
+/// @return True on success or if file has already been preloaded.
+bool gvr_audio_preload_soundfile(gvr_audio_context* api, const char* filename);
+
+/// Unloads a previously preloaded sample from memory. Note that if the sample
+/// is currently used, the memory is freed at the moment playback stops.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename Name of the file, used as identifier.
+void gvr_audio_unload_soundfile(gvr_audio_context* api, const char* filename);
+
+/// Returns a new sound object. Note that the sample should only contain a
+/// single audio channel (stereo sources are automatically downmixed to mono).
+/// The handle automatically destroys itself at the moment the sound playback
+/// has stopped.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played.
+/// @return Id of new sound object. Returns kInvalidId if the sound file has not
+///     been preloaded or if the number of input channels is > 1.
+gvr_audio_source_id gvr_audio_create_sound_object(gvr_audio_context* api,
+                                                 const char* filename);
+
+/// Returns a new ambisonic sound field. Note that the sample needs to be
+/// preloaded and must have 4 separate audio channels. The handle automatically
+/// destroys itself at the moment the sound playback has stopped.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played.
+/// @return Id of new soundfield. Returns kInvalidId if the sound file has not
+///     been preloaded or if the number of input channels does not match that
+///     required.
+gvr_audio_source_id gvr_audio_create_soundfield(gvr_audio_context* api,
+                                               const char* filename);
+
+/// Returns a new stereo non-spatialized source, which directly plays back mono
+/// or stereo audio. Note the sample needs to be preloaded and may contain only
+/// one (mono) or two (stereo) audio channels.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param filename The path/name of the file to be played..
+/// @return Id of new stereo non-spatialized source. Returns kInvalidId if the
+///     sound file has not been preloaded or if the number of input channels is
+///     > 2;
+gvr_audio_source_id gvr_audio_create_stereo_sound(gvr_audio_context* api,
+                                                 const char* filename);
+
+/// Starts the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be stopped.
+/// @param looping_enabled Enables looped audio playback.
+void gvr_audio_play_sound(gvr_audio_context* api, gvr_audio_source_id source_id,
+                          bool looping_enabled);
+
+/// Pauses the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be paused.
+void gvr_audio_pause_sound(gvr_audio_context* api,
+                           gvr_audio_source_id source_id);
+
+/// Resumes the playback of a sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be resumed.
+void gvr_audio_resume_sound(gvr_audio_context* api,
+                            gvr_audio_source_id source_id);
+
+/// Stops the playback of a sound and destroys the corresponding sound object
+/// or Soundfield.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be stopped.
+void gvr_audio_stop_sound(gvr_audio_context* api,
+                          gvr_audio_source_id source_id);
+
+/// Checks if a sound is playing.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be checked.
+/// @return True if the sound is being played.
+bool gvr_audio_is_sound_playing(const gvr_audio_context* api,
+                                gvr_audio_source_id source_id);
+
+/// Checks if a |source_id| is valid, and that the corresponding source is in a
+/// playable state. Sources that have been stopped will be reported as invalid.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be checked.
+/// @return True if the source exists and is in a playable state.
+bool gvr_audio_is_source_id_valid(const gvr_audio_context* api,
+                                  gvr_audio_source_id source_id);
+
+/// Repositions an existing sound object.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param sound_object_id Id of the sound object to be moved.
+/// @param x X coordinate the sound will be placed at.
+/// @param y Y coordinate the sound will be placed at.
+/// @param z Z coordinate the sound will be placed at.
+void gvr_audio_set_sound_object_position(gvr_audio_context* api,
+                                         gvr_audio_source_id sound_object_id,
+                                         float x, float y, float z);
+
+/// Sets the given ambisonic soundfields's rotation.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param soundfield_id Id of the soundfield source to be rotated.
+/// @param soundfield_rotation Quaternion representing the soundfield rotation.
+void gvr_audio_set_soundfield_rotation(gvr_audio_context* api,
+                                       gvr_audio_source_id soundfield_id,
+                                       const gvr_quatf& soundfield_rotation);
+
+/// Sets the given sound object source's distance attenuation method with
+/// minimum and maximum distances. Maximum distance must be greater than the
+/// minimum distance for the method to be set.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param sound_object_id Id of sound object source.
+/// @param rolloff_model Linear or logarithmic distance rolloff models. Note
+///     setting the rolloff model to |GVR_AUDIO_ROLLOFF_NONE| will allow
+///     distance attenuation values to be set manually.
+/// @param min_distance Minimum distance to apply distance attenuation method.
+/// @param max_distance Maximum distance to apply distance attenuation method.
+void gvr_audio_set_sound_object_distance_rolloff_model(
+    gvr_audio_context* api, gvr_audio_source_id sound_object_id,
+    int32_t rolloff_model, float min_distance, float max_distance);
+
+
+/// Changes the master volume.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param volume Volume value. Should range from 0 (mute) to 1 (max).
+void gvr_audio_set_master_volume(gvr_audio_context* api, float volume);
+
+/// Changes the volume of an existing sound.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param source_id Id of the audio source to be modified.
+/// @param volume Volume value. Should range from 0 (mute) to 1 (max).
+void gvr_audio_set_sound_volume(gvr_audio_context* api,
+                                gvr_audio_source_id source_id, float volume);
+
+/// Sets the head pose from a matrix representation of the same.
+///
+/// @param api Pointer to a gvr_audio_context on which to set the pose.
+/// @param head_pose_matrix Matrix representing the head transform to be set.
+void gvr_audio_set_head_pose(gvr_audio_context* api,
+                             const gvr_mat4f& head_pose_matrix);
+
+/// Turns on/off the room reverberation effect.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param enable True to enable room effect.
+void gvr_audio_enable_room(gvr_audio_context* api, bool enable);
+
+/// Sets the room properties describing the dimensions and surface materials of
+/// a given room.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param size_x Dimension along X axis.
+/// @param size_y Dimension along Y axis.
+/// @param size_z Dimension along Z axis.
+/// @param wall_material Surface gvr_audio_material_type for the four walls.
+/// @param ceiling_material Surface gvr_audio_material_type for the ceiling.
+/// @param floor_material Surface gvr_audio_material_type for the floor.
+void gvr_audio_set_room_properties(gvr_audio_context* api, float size_x,
+                                   float size_y, float size_z,
+                                   int32_t wall_material,
+                                   int32_t ceiling_material,
+                                   int32_t floor_material);
+
+/// Adjusts the properties of the current reverb, allowing changes to the
+/// reverb's gain, duration and low/high frequency balance.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param gain Reverb volume (linear) adjustment in range [0, 1] for
+///     attenuation, range [1, inf) for gain boost.
+/// @param time_adjust Reverb time adjustment multiplier to scale the
+///     reverberation tail length. This value should be >= 0.
+/// @param brightness_adjust Reverb brightness adjustment that controls the
+///     reverberation ratio across low and high frequency bands.
+void gvr_audio_set_room_reverb_adjustments(gvr_audio_context* api, float gain,
+                                           float time_adjust,
+                                           float brightness_adjust);
+
+/// Enables the stereo speaker mode. It enforces stereo-panning when headphones
+/// are *not* plugged into the phone. This helps to avoid HRTF-based coloring
+/// effects and reduces computational complexity when speaker playback is
+/// active. By default the stereo speaker mode optimization is disabled.
+///
+/// @param api Pointer to a gvr_audio_context.
+/// @param enable True to enable the stereo speaker mode.
+void gvr_audio_enable_stereo_speaker_mode(gvr_audio_context* api, bool enable);
+
+/// @}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+// Convenience C++ wrapper.
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#include <memory>
+#include <string>
+
+namespace gvr {
+/// This is a convenience C++ wrapper for the Audio C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+///
+/// THREADING: this class is thread-safe and reentrant after initialized
+/// with Init().
+class AudioApi {
+ public:
+  /// Creates an (uninitialized) ControllerApi object. You must initialize
+  /// it by calling Init() before interacting with it.
+  AudioApi() : context_(nullptr) {}
+
+  ~AudioApi() {
+    if (context_) {
+      gvr_audio_destroy(&context_);
+    }
+  }
+
+/// Creates and initializes a gvr_audio_context.
+/// For more information, see gvr_audio_create().
+#ifdef __ANDROID__
+  bool Init(JNIEnv* env, jobject android_context, jobject class_loader,
+            AudioRenderingMode rendering_mode) {
+    context_ =
+        gvr_audio_create(env, android_context, class_loader, rendering_mode);
+    return context_ != nullptr;
+  }
+#else
+  bool Init(AudioRenderingMode rendering_mode) {
+    context_ = gvr_audio_create(rendering_mode);
+    return context_ != nullptr;
+  }
+#endif  // #ifdef __ANDROID__
+
+  /// Pauses the audio engine.
+  /// For more information, see gvr_audio_pause().
+  void Pause() { gvr_audio_pause(context_); }
+
+  /// Resumes the audio engine.
+  /// For more information, see gvr_audio_resume().
+  void Resume() { gvr_audio_resume(context_); }
+
+  /// For more information, see gvr_audio_update().
+  void Update() { gvr_audio_update(context_); }
+
+  /// Preloads a local sound file.
+  /// For more information, see gvr_audio_preload_soundfile().
+  bool PreloadSoundfile(const std::string& filename) {
+    return gvr_audio_preload_soundfile(context_, filename.c_str());
+  }
+
+  /// Unloads a previously preloaded sample from memory.
+  /// For more information, see gvr_audio_preload_soundfile().
+  void UnloadSoundfile(const std::string& filename) {
+    gvr_audio_unload_soundfile(context_, filename.c_str());
+  }
+
+  /// Returns a new sound object.
+  /// For more information, see gvr_audio_create_sound_object().
+  AudioSourceId CreateSoundObject(const std::string& filename) {
+    return gvr_audio_create_sound_object(context_, filename.c_str());
+  }
+
+  /// Returns a new sound field.
+  /// For more information, see gvr_audio_create_soundfield().
+  AudioSourceId CreateSoundfield(const std::string& filename) {
+    return gvr_audio_create_soundfield(context_, filename.c_str());
+  }
+
+  /// Returns a new stereo soound.
+  /// For more information, see gvr_audio_create_stereo_sound().
+  AudioSourceId CreateStereoSound(const std::string& filename) {
+    return gvr_audio_create_stereo_sound(context_, filename.c_str());
+  }
+
+  /// Starts the playback of a sound.
+  /// For more information, see gvr_audio_play_sound().
+  void PlaySound(AudioSourceId source_id, bool looping_enabled) {
+    gvr_audio_play_sound(context_, source_id, looping_enabled);
+  }
+
+  /// Pauses the playback of a sound.
+  /// For more information, see gvr_audio_pause_sound().
+  void PauseSound(AudioSourceId source_id) {
+    gvr_audio_pause_sound(context_, source_id);
+  }
+
+  /// Resumes the playback of a sound.
+  /// For more information, see gvr_audio_resume_sound().
+  void ResumeSound(AudioSourceId source_id) {
+    gvr_audio_resume_sound(context_, source_id);
+  }
+
+  /// Stops the playback of a sound.
+  /// For more information, see gvr_audio_stop_sound().
+  void StopSound(AudioSourceId source_id) {
+    gvr_audio_stop_sound(context_, source_id);
+  }
+
+  /// Checks if a sound is playing.
+  /// For more information, see gvr_audio_is_sound_playing().
+  bool IsSoundPlaying(AudioSourceId source_id) const {
+    return gvr_audio_is_sound_playing(context_, source_id);
+  }
+
+  /// Checks if a source is in a valid playable state.
+  /// For more information, see gvr_audio_is_source_id_valid().
+  bool IsSourceIdValid(AudioSourceId source_id) {
+    return gvr_audio_is_source_id_valid(context_, source_id);
+  }
+
+  /// Repositions an existing sound object.
+  /// For more information, see gvr_audio_set_sound_object_position().
+  void SetSoundObjectPosition(AudioSourceId sound_object_id, float x, float y,
+                              float z) {
+    gvr_audio_set_sound_object_position(context_, sound_object_id, x, y, z);
+  }
+
+  void SetSoundObjectDistanceRolloffModel(
+      AudioSourceId sound_object_id,
+      gvr_audio_distance_rolloff_type rolloff_model, float min_distance,
+      float max_distance) {
+    gvr_audio_set_sound_object_distance_rolloff_model(
+        context_, sound_object_id, rolloff_model, min_distance, max_distance);
+  }
+
+  /// Rotates an existing soundfield.
+  /// For more information, see gvr_audio_set_soundfield_rotation().
+  void SetSoundfieldRotation(AudioSourceId soundfield_id,
+                             const Quatf& soundfield_rotation) {
+    gvr_audio_set_soundfield_rotation(context_, soundfield_id,
+                                      soundfield_rotation);
+  }
+
+  /// Changes the master volume.
+  /// For more information, see gvr_audio_set_master_volume().
+  void SetMasterVolume(float volume) {
+    gvr_audio_set_master_volume(context_, volume);
+  }
+
+  /// Changes the volume of an existing sound.
+  /// For more information, see gvr_audio_set_sound_volume().
+  void SetSoundVolume(AudioSourceId source_id, float volume) {
+    gvr_audio_set_sound_volume(context_, source_id, volume);
+  }
+
+  /// Sets the head position from a matrix representation.
+  /// For more information, see gvr_audio_set_head_pose().
+  void SetHeadPose(const Mat4f& head_pose_matrix) {
+    gvr_audio_set_head_pose(context_, head_pose_matrix);
+  }
+
+  /// Turns on/off the room reverberation effect.
+  /// For more information, see gvr_audio_enable_room().
+  void EnableRoom(bool enable) { gvr_audio_enable_room(context_, enable); }
+
+  /// Sets the room properties describing the dimensions and surface materials
+  /// of a given room. For more information, see
+  /// gvr_audio_set_room_properties().
+  void SetRoomProperties(float size_x, float size_y, float size_z,
+                         gvr_audio_material_type wall_material,
+                         gvr_audio_material_type ceiling_material,
+                         gvr_audio_material_type floor_material) {
+    gvr_audio_set_room_properties(context_, size_x, size_y, size_z,
+                                  wall_material, ceiling_material,
+                                  floor_material);
+  }
+
+  /// Adjusts the properties of the current reverb, allowing changes to the
+  /// reverb's gain, duration and low/high frequency balance. For more
+  /// information see gvr_audio_set_room_reverb_adjustments().
+  void SetRoomReverbAdjustments(float gain, float time_adjust,
+                                float brightness_adjust) {
+    gvr_audio_set_room_reverb_adjustments(context_, gain, time_adjust,
+                                          brightness_adjust);
+  }
+
+  /// Enables the stereo speaker mode. For more information see
+  /// gvr_audio_enable_stereo_speaker_mode().
+  void EnableStereoSpeakerMode(bool enable) {
+    gvr_audio_enable_stereo_speaker_mode(context_, enable);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit AudioApi(gvr_audio_context* context)
+      : context_(context) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_audio_context* cobj() { return context_; }
+  const gvr_audio_context* cobj() const { return context_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_audio_context* Release() {
+    auto result = context_;
+    context_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  gvr_audio_context* context_;
+
+  // Disallow copy and assign:
+  AudioApi(const AudioApi&);
+  void operator=(const AudioApi&);
+};
+
+}  // namespace gvr
+#endif  // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_AUDIO_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h
new file mode 100644
index 0000000..a67502f
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_controller.h
@@ -0,0 +1,752 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
+
+#ifdef __ANDROID__
+#include <jni.h>
+#endif
+
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr.h"
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup Controller Controller API
+/// @brief This is the Controller C API, which allows access to a VR controller.
+///
+/// If you are writing C++ code, you might prefer to use the C++ wrapper rather
+/// than implement this C API directly.
+///
+/// Typical initialization example:
+///
+///     // Get your gvr_context* pointer from GvrLayout:
+///     gvr_context* gvr = ......;  // (get from GvrLayout in Java)
+///
+///     // Set up the API features:
+///     int32_t options = gvr_controller_get_default_options();
+///
+///     // Enable non-default options, if needed:
+///     options |= GVR_CONTROLLER_ENABLE_GYRO | GVR_CONTROLLER_ENABLE_ACCEL;
+///
+///     // Create and init:
+///     gvr_controller_context* context =
+///         gvr_controller_create_and_init(options, gvr);
+///
+///     // Check if init was successful.
+///     if (!context) {
+///       // Handle error.
+///       return;
+///     }
+///
+///     gvr_controller_state* state = gvr_controller_state_create();
+///
+///     // Resume:
+///     gvr_controller_resume(api);
+///
+/// Usage:
+///
+///     void DrawFrame() {
+///       gvr_controller_state_update(context, 0, state);
+///       // ... process controller state ...
+///     }
+///
+///     // When your application gets paused:
+///     void OnPause() {
+///       gvr_controller_pause(context);
+///     }
+///
+///     // When your application gets resumed:
+///     void OnResume() {
+///       gvr_controller_resume(context);
+///     }
+///
+/// To conserve battery, be sure to call gvr_controller_pause and
+/// gvr_controller_resume when your app gets paused and resumed, respectively.
+///
+/// THREADING: unless otherwise noted, all functions are thread-safe, so
+/// you can operate on the same gvr_controller_context object from multiple
+/// threads.
+/// @{
+
+/// Represents a Daydream Controller API object, used to invoke the
+/// Daydream Controller API.
+typedef struct gvr_controller_context_ gvr_controller_context;
+
+/// Returns the default features for the controller API.
+///
+/// @return The set of default features, as bit flags (an OR'ed combination of
+///     the GVR_CONTROLLER_ENABLE_* feature flags).
+int32_t gvr_controller_get_default_options();
+
+/// Creates and initializes a gvr_controller_context instance which can be used
+/// to invoke the Daydream Controller API functions. Important: after creation
+/// the API will be in the paused state (the controller will be inactive).
+/// You must call gvr_controller_resume() explicitly (typically, in your Android
+/// app's onResume() callback).
+///
+/// @param options The API options. To get the defaults, use
+///     gvr_controller_get_default_options().
+/// @param context The GVR Context object to sync with (optional).
+///     This can be nullptr. If provided, the context's state will
+///     be synchronized with the controller's state where possible. For
+///     example, when the user recenters the controller, this will
+///     automatically recenter head tracking as well.
+///     WARNING: the caller is responsible for making sure the pointer
+///     remains valid for the lifetime of this object.
+/// @return A pointer to the initialized API, or NULL if an error occurs.
+gvr_controller_context* gvr_controller_create_and_init(
+    int32_t options, gvr_context* context);
+
+#ifdef __ANDROID__
+/// Creates and initializes a gvr_controller_context instance with an explicit
+/// Android context and class loader.
+///
+/// @param env The JNI Env associated with the current thread.
+/// @param android_context The Android application context. This must be the
+///     application context, NOT an Activity context (Note: from any Android
+///     Activity in your app, you can call getApplicationContext() to
+///     retrieve the application context).
+/// @param class_loader The class loader to use when loading Java
+///     classes. This must be your app's main class loader (usually
+///     accessible through activity.getClassLoader() on any of your Activities).
+/// @param options The API options. To get the defaults, use
+///     gvr_controller_get_default_options().
+/// @param context The GVR Context object to sync with (optional).
+///     This can be nullptr. If provided, the context's state will
+///     be synchronized with the controller's state where possible. For
+///     example, when the user recenters the controller, this will
+///     automatically recenter head tracking as well.
+///     WARNING: the caller is responsible for making sure the pointer
+///     remains valid for the lifetime of this object.
+/// @return A pointer to the initialized API, or NULL if an error occurs.
+gvr_controller_context* gvr_controller_create_and_init_android(
+    JNIEnv *env, jobject android_context, jobject class_loader,
+    int32_t options, gvr_context* context);
+#endif  // #ifdef __ANDROID__
+
+/// Destroys a gvr_controller_context that was previously created with
+/// gvr_controller_init.
+///
+/// @param api Pointer to a pointer to a gvr_controller_context. The pointer
+///     will be set to NULL after destruction.
+void gvr_controller_destroy(gvr_controller_context** api);
+
+/// Pauses the controller, possibly releasing resources.
+/// Call this when your app/game loses focus.
+/// Calling this when already paused is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+void gvr_controller_pause(gvr_controller_context* api);
+
+/// Resumes the controller. Call this when your app/game regains focus.
+/// Calling this when already resumed is a no-op.
+/// Thread-safe (call from any thread).
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+void gvr_controller_resume(gvr_controller_context* api);
+
+/// Convenience to convert an API status code to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param status The gvr_controller_api_status to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_api_status_to_string(int32_t status);
+
+/// Convenience to convert an connection state to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param state The state to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_connection_state_to_string(int32_t state);
+
+/// Convenience to convert an connection state to string. The returned pointer
+/// is static and valid throughout the lifetime of the application.
+///
+/// @param button The gvr_controller_button to convert to string.
+/// @return A pointer to a string that describes the value.
+const char* gvr_controller_button_to_string(int32_t button);
+
+/// Creates a gvr_controller_state.
+gvr_controller_state* gvr_controller_state_create();
+
+/// Destroys a a gvr_controller_state that was previously created with
+/// gvr_controller_state_create.
+void gvr_controller_state_destroy(gvr_controller_state** state);
+
+/// Updates the controller state. Reading the controller state is not a
+/// const getter: it has side-effects. In particular, some of the
+/// gvr_controller_state fields (the ones documented as "transient") represent
+/// one-time events and will be true for only one read operation, and false
+/// in subsequente reads.
+///
+/// @param api Pointer to a pointer to a gvr_controller_context.
+/// @param flags Optional flags reserved for future use. A value of 0 should be
+///     used until corresponding flag attributes are defined and documented.
+/// @param out_state A pointer where the controller's state
+///     is to be written. This must have been allocated with
+///     gvr_controller_state_create().
+void gvr_controller_state_update(gvr_controller_context* api, int32_t flags,
+                                 gvr_controller_state* out_state);
+
+/// Gets the API status of the controller state. Returns one of the
+/// gvr_controller_api_status variants, but returned as an int32_t for ABI
+/// compatibility.
+int32_t gvr_controller_state_get_api_status(const gvr_controller_state* state);
+
+/// Gets the connection state of the controller. Returns one of the
+/// gvr_controller_connection_state variants, but returned as an int32_t for ABI
+/// compatibility.
+int32_t gvr_controller_state_get_connection_state(
+    const gvr_controller_state* state);
+
+/// Returns the current controller orientation, in Start Space. The Start Space
+/// is the same space as the headset space and has these three axes
+/// (right-handed):
+///
+/// * The positive X axis points to the right.
+/// * The positive Y axis points upwards.
+/// * The positive Z axis points backwards.
+///
+/// The definition of "backwards" and "to the right" are based on the position
+/// of the controller when tracking started. For Daydream, this is when the
+/// controller was first connected in the "Connect your Controller" screen
+/// which is shown when the user enters VR.
+///
+/// The definition of "upwards" is given by gravity (away from the pull of
+/// gravity). This API may not work in environments without gravity, such
+/// as space stations or near the center of the Earth.
+///
+/// Since the coordinate system is right-handed, rotations are given by the
+/// right-hand rule. For example, rotating the controller counter-clockwise
+/// on a table top as seen from above means a positive rotation about the
+/// Y axis, while clockwise would mean negative.
+///
+/// Note that this is the Start Space for the *controller*, which initially
+/// coincides with the Start Space for the headset, but they may diverge over
+/// time due to controller/headset drift. A recentering operation will bring
+/// the two spaces back into sync.
+///
+/// Remember that a quaternion expresses a rotation. Given a rotation of theta
+/// radians about the (x, y, z) axis, the corresponding quaternion (in
+/// xyzw order) is:
+///
+///     (x * sin(theta/2), y * sin(theta/2), z * sin(theta/2), cos(theta/2))
+///
+/// Here are some examples of orientations of the controller and their
+/// corresponding quaternions, all given in xyzw order:
+///
+///   * Initial pose, pointing forward and lying flat on a surface: identity
+///     quaternion (0, 0, 0, 1). Corresponds to "no rotation".
+///
+///   * Flat on table, rotated 90 degrees counter-clockwise: (0, 0.7071, 0,
+///     0.7071). Corresponds to a +90 degree rotation about the Y axis.
+///
+///   * Flat on table, rotated 90 degrees clockwise: (0, -0.7071, 0, 0.7071).
+///     Corresponds to a -90 degree rotation about the Y axis.
+///
+///   * Flat on table, rotated 180 degrees (pointing backwards): (0, 1, 0, 0).
+///     Corresponds to a 180 degree rotation about the Y axis.
+///
+///   * Pointing straight up towards the sky: (0.7071, 0, 0, 0.7071).
+///     Corresponds to a +90 degree rotation about the X axis.
+///
+///   * Pointing straight down towards the ground: (-0.7071, 0, 0, 0.7071).
+///     Corresponds to a -90 degree rotation about the X axis.
+///
+///   * Banked 90 degrees to the left: (0, 0, 0.7071, 0.7071). Corresponds
+///     to a +90 degree rotation about the Z axis.
+///
+///   * Banked 90 degrees to the right: (0, 0, -0.7071, 0.7071). Corresponds
+///     to a -90 degree rotation about the Z axis.
+gvr_quatf gvr_controller_state_get_orientation(
+    const gvr_controller_state* state);
+
+/// Returns the current controller gyro reading, in Start Space.
+///
+/// The gyro measures the controller's angular speed in radians per second.
+/// Note that this is an angular *speed*, so it reflects how fast the
+/// controller's orientation is changing with time.
+/// In particular, if the controller is not being rotated, the angular speed
+/// will be zero on all axes, regardless of the current pose.
+///
+/// The axes are in the controller's device space. Specifically:
+///
+///    * The X axis points to the right of the controller.
+///    * The Y axis points upwards perpendicular to the top surface of the
+///      controller.
+///    * The Z axis points backwards along the body of the controller,
+///      towards its rear, where the charging port is.
+///
+/// As usual in a right-handed coordinate system, the sign of the angular
+/// velocity is given by the right-hand rule. So, for example:
+///
+///    * If the controller is flat on a table top spinning counter-clockwise
+///      as seen from above, you will read a positive angular velocity
+///      about the Y axis. Clockwise would be negative.
+///    * If the controller is initially pointing forward and lying flat and
+///      is then gradually angled up so that its tip points towards the sky,
+///      it will report a positive angular velocity about the X axis during
+///      that motion. Likewise, angling it down will report a negative angular
+///      velocity about the X axis.
+///    * If the controller is banked (rolled) to the right, this will
+///      report a negative angular velocity about the Z axis during the
+///      motion (remember the Z axis points backwards along the controller).
+///      Banking to the left will report a positive angular velocity about
+///      the Z axis.
+gvr_vec3f gvr_controller_state_get_gyro(const gvr_controller_state* state);
+
+/// Current (latest) controller accelerometer reading, in Start Space.
+///
+/// The accelerometer indicates the direction in which the controller feels
+/// an acceleration, including gravity. The reading is given in meters
+/// per second squared (m/s^2). The axes are the same as for the gyro.
+/// To have an intuition for the signs used in the accelerometer, it is useful
+/// to imagine that, when at rest, the controller is being "pushed" by a
+/// force opposite to gravity. It is as if, by the equivalency princle, it were
+/// on a frame of reference that is accelerating in the opposite direction to
+/// gravity. For example:
+///
+///   * If the controller is lying flat on a table top, it will read a positive
+///     acceleration of about 9.8 m/s^2 along the Y axis, corresponding to
+///     the acceleration of gravity (as if the table were pushing the controller
+///     upwards at 9.8 m/s^2 to counteract gravity).
+///   * If, in that situation, the controller is now accelerated upwards at
+///     3.0 m/s^2, then the reading will be 12.8 m/s^2 along the Y axis,
+///     since the controller will now feel a stronger acceleration corresponding
+///     to the 9.8 m/s^2 plus the upwards push of 3.0 m/s^2.
+///   * If, the controller is accelerated downwards at 5.0 m/s^2, then the
+///     reading will now be 4.8 m/s^2 along the Y axis, since the controller
+///     will now feel a weaker acceleration (as the acceleration is giving in
+///     to gravity).
+///   * If you were to give in to gravity completely, letting the controller
+///     free fall towards the ground, it will read 0 on all axes, as there
+///     will be no force acting on the controller. (Please do not put your
+///     controller in a free-fall situation. This is just a theoretical
+///     example.)
+gvr_vec3f gvr_controller_state_get_accel(const gvr_controller_state* state);
+
+/// Returns whether the user is touching the touchpad.
+bool gvr_controller_state_is_touching(const gvr_controller_state* state);
+
+/// If the user is touching the touchpad, this returns the touch position in
+/// normalized coordinates, where (0,0) is the top-left of the touchpad
+/// and (1,1) is the bottom right. If the user is not touching the touchpad,
+/// then this is the position of the last touch.
+gvr_vec2f gvr_controller_state_get_touch_pos(const gvr_controller_state* state);
+
+/// Returns true if user just started touching touchpad (this is a transient
+/// event:
+/// it is true for only one frame after the event).
+bool gvr_controller_state_get_touch_down(const gvr_controller_state* state);
+
+/// Returns true if user just stopped touching touchpad (this is a transient
+/// event:
+/// it is true for only one frame after the event).
+bool gvr_controller_state_get_touch_up(const gvr_controller_state* state);
+
+/// Returns true if a recenter operation just ended (this is a transient event:
+/// it is true only for one frame after the recenter ended). If this is
+/// true then the `orientation` field is already relative to the new center.
+bool gvr_controller_state_get_recentered(const gvr_controller_state* state);
+
+/// Returns whether the recenter flow is currently in progress.
+///
+/// @deprecated Use gvr_controller_state_get_recentered instead.
+bool gvr_controller_state_get_recentering(const gvr_controller_state* state);
+
+/// Returns whether the given button is currently pressed.
+bool gvr_controller_state_get_button_state(const gvr_controller_state* state,
+
+                                           int32_t button);
+
+/// Returns whether the given button was just pressed (transient).
+bool gvr_controller_state_get_button_down(const gvr_controller_state* state,
+                                          int32_t button);
+
+/// Returns whether the given button was just released (transient).
+bool gvr_controller_state_get_button_up(const gvr_controller_state* state,
+                                        int32_t button);
+
+/// Returns the timestamp (nanos) when the last orientation event was received.
+int64_t gvr_controller_state_get_last_orientation_timestamp(
+    const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last gyro event was received.
+int64_t gvr_controller_state_get_last_gyro_timestamp(
+    const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last accelerometer event was
+/// received.
+int64_t gvr_controller_state_get_last_accel_timestamp(
+    const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last touch event was received.
+int64_t gvr_controller_state_get_last_touch_timestamp(
+    const gvr_controller_state* state);
+
+/// Returns the timestamp (nanos) when the last button event was received.
+int64_t gvr_controller_state_get_last_button_timestamp(
+    const gvr_controller_state* state);
+
+// Current (latest) controller simulated position for use with an elbow model.
+gvr_vec3f gvr_controller_state_get_position(const gvr_controller_state* state);
+
+// Returns the timestamp (nanos) when the last position event was received.
+int64_t gvr_controller_state_get_last_position_timestamp(
+    const gvr_controller_state* state);
+
+/// @}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+
+// Convenience C++ wrapper.
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#include <memory>
+
+namespace gvr {
+/// This is a convenience C++ wrapper for the Controller C API.
+///
+/// This wrapper strategy prevents ABI compatibility issues between compilers
+/// by ensuring that the interface between client code and the implementation
+/// code in libgvr.so is a pure C interface. The translation from C++ calls
+/// to C calls provided by this wrapper runs entirely in the client's binary
+/// and is compiled by the client's compiler.
+///
+/// Methods in this class are only documented insofar as the C++ wrapping logic
+/// is concerned; for information about the method itself, please refer to the
+/// corresponding function in the C API.
+///
+/// Typical C++ initialization example:
+///
+///     std::unique_ptr<ControllerApi> controller_api(new ControllerApi);
+///
+///     // Your GVR context pointer (which can be obtained from GvrLayout)
+///     gvr_context* context = .....;  // (get it from GvrLayout)
+///
+///     // Set up the options:
+///     int32_t options = ControllerApi::DefaultOptions();
+///
+///     // Enable non-default options, if you need them:
+///     options |= GVR_CONTROLLER_ENABLE_GYRO;
+///
+///     // Init the ControllerApi object:
+///     bool success = controller_api->Init(options, context);
+///     if (!success) {
+///       // Handle failure.
+///       // Do NOT call other methods (like Resume, etc) if init failed.
+///       return;
+///     }
+///
+///     // Resume the ControllerApi (if your app is on the foreground).
+///     controller_api->Resume();
+///
+///     ControllerState state;
+///
+/// Usage example:
+///
+///     void DrawFrame() {
+///       state.Update(*controller_api);
+///       // ... process controller state ...
+///     }
+///
+///     // When your application gets paused:
+///     void OnPause() {
+///       controller_api->Pause();
+///     }
+///
+///     // When your application gets resumed:
+///     void OnResume() {
+///       controller_api->Resume();
+///     }
+///
+/// To conserve battery, be sure to call Pause() and Resume() when your app
+/// gets paused and resumed, respectively. This will allow the underlying
+/// logic to unbind from the VR service and let the controller sleep when
+/// no apps are using it.
+///
+/// THREADING: this class is thread-safe and reentrant after initialized
+/// with Init().
+class ControllerApi {
+ public:
+  /// Creates an (uninitialized) ControllerApi object. You must initialize
+  /// it by calling Init() before interacting with it.
+  ControllerApi() : context_(nullptr) {}
+
+  /// Returns the default controller options.
+  static int32_t DefaultOptions() {
+    return gvr_controller_get_default_options();
+  }
+
+  // Deprecated factory-style create method.
+  // TODO(btco): remove this once no one is using it.
+  static std::unique_ptr<ControllerApi> Create() {
+    return std::unique_ptr<ControllerApi>(new ControllerApi);
+  }
+
+  /// Initializes the controller API.
+  ///
+  /// This method must be called exactly once in the lifetime of this object.
+  /// Other methods in this class may only be called after Init() returns true.
+  /// Note: this does not cause the ControllerApi to be resumed. You must call
+  /// Resume() explicitly in order to start using the controller.
+  ///
+  /// For more information see gvr_controller_create_and_init().
+  ///
+  /// @return True if initialization was successful, false if it failed.
+  ///     Initialization may fail, for example, because invalid options were
+  ///     supplied.
+  bool Init(int32_t options, gvr_context* context) {
+    context_ = gvr_controller_create_and_init(options, context);
+    return context_ != nullptr;
+  }
+
+#ifdef __ANDROID__
+  /// Overload of Init() with explicit Android context and class loader
+  /// (for Android only). For more information, see:
+  /// gvr_controller_create_and_init_android().
+  bool Init(JNIEnv *env, jobject android_context, jobject class_loader,
+            int32_t options, gvr_context* context) {
+    context_ = gvr_controller_create_and_init_android(
+        env, android_context, class_loader, options, context);
+    return context_ != nullptr;
+  }
+#endif  // #ifdef __ANDROID__
+
+  /// Convenience overload that calls Init without a gvr_context.
+  // TODO(btco): remove once it is no longer being used.
+  bool Init(int32_t options) {
+    return Init(options, nullptr);
+  }
+
+  /// Pauses the controller.
+  /// For more information, see gvr_controller_pause().
+  void Pause() {
+    gvr_controller_pause(context_);
+  }
+
+  /// Resumes the controller.
+  /// For more information, see gvr_controller_resume().
+  void Resume() {
+    gvr_controller_resume(context_);
+  }
+
+  /// Destroys this ControllerApi instance.
+  ~ControllerApi() {
+    if (context_) gvr_controller_destroy(&context_);
+  }
+
+  /// Convenience functions to convert enums to strings.
+  /// For more information, see the corresponding functions in the C API.
+  static const char* ToString(ControllerApiStatus status) {
+    return gvr_controller_api_status_to_string(status);
+  }
+
+  static const char* ToString(ControllerConnectionState state) {
+    return gvr_controller_connection_state_to_string(state);
+  }
+
+  static const char* ToString(ControllerButton button) {
+    return gvr_controller_button_to_string(button);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit ControllerApi(gvr_controller_context* context)
+      : context_(context) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_controller_context* cobj() { return context_; }
+  const gvr_controller_context* cobj() const { return context_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_controller_context* release() {
+    auto result = context_;
+    context_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ protected:
+  gvr_controller_context* context_;
+
+ private:
+  friend class ControllerState;
+
+  // Disallow copy and assign:
+  ControllerApi(const ControllerApi&);
+  void operator=(const ControllerApi&);
+};
+
+/// Convenience C++ wrapper for the opaque gvr_controller_state type. See the
+/// gvr_controller_state functions for more information.
+class ControllerState {
+ public:
+  ControllerState() : state_(gvr_controller_state_create()) {}
+
+  ~ControllerState() {
+    if (state_) gvr_controller_state_destroy(&state_);
+  }
+
+  /// For more information, see gvr_controller_state_update().
+  void Update(const ControllerApi& api) {
+    gvr_controller_state_update(api.context_, 0, state_);
+  }
+
+  /// For more information, see gvr_controller_state_update().
+  void Update(const ControllerApi& api, int32_t flags) {
+    gvr_controller_state_update(api.context_, flags, state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_api_status().
+  ControllerApiStatus GetApiStatus() const {
+    return static_cast<ControllerApiStatus>(
+        gvr_controller_state_get_api_status(state_));
+  }
+
+  /// For more information, see gvr_controller_state_get_connection_state().
+  ControllerConnectionState GetConnectionState() const {
+    return static_cast<ControllerConnectionState>(
+        gvr_controller_state_get_connection_state(state_));
+  }
+
+  /// For more information, see gvr_controller_state_get_orientation().
+  gvr_quatf GetOrientation() const {
+    return gvr_controller_state_get_orientation(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_gyro().
+  gvr_vec3f GetGyro() const { return gvr_controller_state_get_gyro(state_); }
+
+  /// For more information, see gvr_controller_state_get_accel().
+  gvr_vec3f GetAccel() const { return gvr_controller_state_get_accel(state_); }
+
+  /// For more information, see gvr_controller_state_is_touching().
+  bool IsTouching() const { return gvr_controller_state_is_touching(state_); }
+
+  /// For more information, see gvr_controller_state_get_touch_pos().
+  gvr_vec2f GetTouchPos() const {
+    return gvr_controller_state_get_touch_pos(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_touch_down().
+  bool GetTouchDown() const {
+    return gvr_controller_state_get_touch_down(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_touch_up().
+  bool GetTouchUp() const { return gvr_controller_state_get_touch_up(state_); }
+
+  /// For more information, see gvr_controller_state_get_recentered().
+  bool GetRecentered() const {
+    return gvr_controller_state_get_recentered(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_recentering().
+  bool GetRecentering() const {
+    return gvr_controller_state_get_recentering(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_button_state().
+  bool GetButtonState(ControllerButton button) const {
+    return gvr_controller_state_get_button_state(state_, button);
+  }
+
+  /// For more information, see gvr_controller_state_get_button_down().
+  bool GetButtonDown(ControllerButton button) const {
+    return gvr_controller_state_get_button_down(state_, button);
+  }
+
+  /// For more information, see gvr_controller_state_get_button_up().
+  bool GetButtonUp(ControllerButton button) const {
+    return gvr_controller_state_get_button_up(state_, button);
+  }
+
+  /// For more information, see
+  /// gvr_controller_state_get_last_orientation_timestamp().
+  int64_t GetLastOrientationTimestamp() const {
+    return gvr_controller_state_get_last_orientation_timestamp(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_last_gyro_timestamp().
+  int64_t GetLastGyroTimestamp() const {
+    return gvr_controller_state_get_last_gyro_timestamp(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_last_accel_timestamp().
+  int64_t GetLastAccelTimestamp() const {
+    return gvr_controller_state_get_last_accel_timestamp(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_last_touch_timestamp().
+  int64_t GetLastTouchTimestamp() const {
+    return gvr_controller_state_get_last_touch_timestamp(state_);
+  }
+
+  /// For more information, see
+  /// gvr_controller_state_get_last_button_timestamp().
+  int64_t GetLastButtonTimestamp() const {
+    return gvr_controller_state_get_last_button_timestamp(state_);
+  }
+
+  /// For more information, see gvr_controller_state_get_position().
+  gvr_vec3f GetPosition() const {
+    return gvr_controller_state_get_position(state_);
+  }
+
+  /// For more information, see
+  /// gvr_controller_state_get_last_position_timestamp().
+  int64_t GetLastPositionTimestamp() const {
+    return gvr_controller_state_get_last_position_timestamp(state_);
+  }
+
+  /// @name Wrapper manipulation
+  /// @{
+  /// Creates a C++ wrapper for a C object and takes ownership.
+  explicit ControllerState(gvr_controller_state* state) : state_(state) {}
+
+  /// Returns the wrapped C object. Does not affect ownership.
+  gvr_controller_state* cobj() { return state_; }
+  const gvr_controller_state* cobj() const { return state_; }
+
+  /// Returns the wrapped C object and transfers its ownership to the caller.
+  /// The wrapper becomes invalid and should not be used.
+  gvr_controller_state* release() {
+    auto result = state_;
+    state_ = nullptr;
+    return result;
+  }
+  /// @}
+
+ private:
+  gvr_controller_state* state_;
+};
+
+}  // namespace gvr
+#endif  // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_CONTROLLER_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h
new file mode 100644
index 0000000..ff00863
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/include/gvr_types.h
@@ -0,0 +1,575 @@
+/* Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
+#define VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @defgroup types Google VR Types
+/// @brief Various types used in the Google VR NDK.
+/// @{
+
+/// Primary context for invoking Google VR APIs.
+typedef struct gvr_context_ gvr_context;
+
+/// An enum for the left and right eye.
+typedef enum {
+  GVR_LEFT_EYE = 0,
+  GVR_RIGHT_EYE,
+  GVR_NUM_EYES
+} gvr_eye;
+
+/// The type of VR viewer.
+typedef enum {
+  /// A Cardboard-compatible viewer. A typical Cardboard viewer supports a
+  /// simple touchscreen-based trigger input mechanism. On most platforms, this
+  // is the default viewer type if no viewer has been explicitly paired.
+  GVR_VIEWER_TYPE_CARDBOARD = 0,
+  /// A Daydream-compatible viewer. A typical Daydream viewer supports 3DOF
+  /// controller input (as defined in gvr_controller.h), and is intended only
+  /// for Daydream-ready platforms. It does *not* support touchscreen-based
+  /// input unless Cardboard emulation is explicitly enabled.
+  GVR_VIEWER_TYPE_DAYDREAM = 1,
+} gvr_viewer_type;
+
+/// @}
+
+/// Version information for the Google VR API.
+typedef struct gvr_version_ {
+  int32_t major;
+  int32_t minor;
+  int32_t patch;
+} gvr_version;
+
+/// An integral 2D size. Used for render target sizes.
+typedef struct gvr_sizei {
+  int32_t width;
+  int32_t height;
+} gvr_sizei;
+
+/// An integral 2D rect. Used for window bounds in pixels.
+typedef struct gvr_recti {
+  int32_t left;
+  int32_t right;
+  int32_t bottom;
+  int32_t top;
+} gvr_recti;
+
+/// A floating point 2D rect. Used for field of view, and also for ranges
+/// in texture space. When used for a field of view, all angles are in positive
+/// degrees from the optical axis.
+typedef struct gvr_rectf {
+  float left;
+  float right;
+  float bottom;
+  float top;
+} gvr_rectf;
+
+/// A floating point 2D vector.
+typedef struct gvr_vec2f {
+  float x;
+  float y;
+} gvr_vec2f;
+
+/// A floating point 3D vector.
+typedef struct gvr_vec3f {
+  float x;
+  float y;
+  float z;
+} gvr_vec3f;
+
+/// A floating point 4x4 matrix.
+typedef struct gvr_mat4f { float m[4][4]; } gvr_mat4f;
+
+/// A floating point quaternion, in JPL format.
+/// We use this simple struct in order not to impose a dependency on a
+/// particular math library. The user of this API is free to encapsulate this
+/// into any math library they want.
+typedef struct gvr_quatf {
+  /// qx, qy, qz are the vector component.
+  float qx;
+  float qy;
+  float qz;
+  /// qw is the linelar component.
+  float qw;
+} gvr_quatf;
+
+/// A *monotonic system time* representation. On Android, this is equivalent to
+/// System.nanoTime(), or clock_gettime(CLOCK_MONOTONIC). If there is any doubt
+/// about how to get the current time for the current platform, simply use
+/// gvr_get_time_point_now().
+typedef struct gvr_clock_time_point {
+  int64_t monotonic_system_time_nanos;
+} gvr_clock_time_point;
+
+/// A structure that ties together a region of a buffer, the field of view
+/// rendered into that region and a target eye index to define part of the
+/// user's field of view. The SDK implementation uses this information to
+/// transform the images generated by the app output into the final display that
+/// is sent to the screen.
+///
+/// A set of these structures will most often be generated by the API, via
+/// gvr_get_recommended_buffer_viewports() or
+/// gvr_get_screen_buffer_viewports(). However, the client may also customize
+/// these values via gvr_buffer_viewport_list_set(), constructing a custom
+/// gvr_buffer_viewport_list for use in the distortion pass.
+typedef struct gvr_buffer_viewport_ gvr_buffer_viewport;
+
+/// List of buffer viewports that completely specifies how to transform the
+/// frame's buffers into the image displayed on the screen.
+typedef struct gvr_buffer_viewport_list_ gvr_buffer_viewport_list;
+
+/// Specification of a pixel buffer. A pixel buffer can have color, depth and
+/// stencil attachments and mostly corresponds to the OpenGL concept of a
+/// framebuffer object. However, since there can be multiple such objects for
+/// each frame, we avoid calling them "framebuffers". Pixel buffers which are
+/// part of the currently acquired frame are immutable, i.e., they cannot be
+/// resized or otherwise reconfigured.
+typedef struct gvr_buffer_spec_ gvr_buffer_spec;
+
+/// Swap chain that contains some number of frames. Frames in the swap chain
+/// can be unused, in the process of being distorted and presented on the
+/// screen, or acquired and being rendered to by the application. The swap chain
+/// ensures that the most recent available frame is always shown and that the
+/// application never has to wait to render the next frame.
+typedef struct gvr_swap_chain_ gvr_swap_chain;
+
+/// A single frame acquired from the swap chain. Each frame is composed of one
+/// or more buffers, which are then lens distorted and composited into the final
+/// output. Buffers are identified by indices that correspond to the position
+/// of their gvr_buffer_spec in the list passed when constructing the swap
+/// chain.
+typedef struct gvr_frame_ gvr_frame;
+
+/// @addtogroup types
+/// @{
+
+/// Constants that represent GVR error codes.
+typedef enum {
+  GVR_ERROR_NONE = 0,
+  GVR_ERROR_CONTROLLER_CREATE_FAILED = 2,
+  GVR_ERROR_NO_FRAME_AVAILABLE = 3,
+} gvr_error;
+
+/// Controller API options (bit flags).
+enum {
+  /// Indicates that controller orientation data should be reported.
+  GVR_CONTROLLER_ENABLE_ORIENTATION = 1 << 0,
+  /// Indicates that controller touchpad data should be reported.
+  GVR_CONTROLLER_ENABLE_TOUCH = 1 << 1,
+  /// Indicates that controller gyroscope data should be reported.
+  GVR_CONTROLLER_ENABLE_GYRO = 1 << 2,
+  /// Indicates that controller accelerometer data should be reported.
+  GVR_CONTROLLER_ENABLE_ACCEL = 1 << 3,
+  /// Indicates that controller gestures should be reported.
+  GVR_CONTROLLER_ENABLE_GESTURES = 1 << 4,
+  /// Indicates that controller pose prediction should be enabled.
+  GVR_CONTROLLER_ENABLE_POSE_PREDICTION = 1 << 5,
+  /// Indicates that controller position data should be reported.
+  GVR_CONTROLLER_ENABLE_POSITION = 1 << 6,
+};
+
+/// Constants that represent the status of the controller API.
+typedef enum {
+  /// API is happy and healthy. This doesn't mean the controller itself
+  /// is connected, it just means that the underlying service is working
+  /// properly.
+  GVR_CONTROLLER_API_OK = 0,
+
+  /// Any other status represents a permanent failure that requires
+  /// external action to fix:
+
+  /// API failed because this device does not support controllers (API is too
+  /// low, or other required feature not present).
+  GVR_CONTROLLER_API_UNSUPPORTED = 1,
+  /// This app was not authorized to use the service (e.g., missing permissions,
+  /// the app is blacklisted by the underlying service, etc).
+  GVR_CONTROLLER_API_NOT_AUTHORIZED = 2,
+  /// The underlying VR service is not present.
+  GVR_CONTROLLER_API_UNAVAILABLE = 3,
+  /// The underlying VR service is too old, needs upgrade.
+  GVR_CONTROLLER_API_SERVICE_OBSOLETE = 4,
+  /// The underlying VR service is too new, is incompatible with current client.
+  GVR_CONTROLLER_API_CLIENT_OBSOLETE = 5,
+  /// The underlying VR service is malfunctioning. Try again later.
+  GVR_CONTROLLER_API_MALFUNCTION = 6,
+} gvr_controller_api_status;
+
+/// Constants that represent the state of the controller.
+typedef enum {
+  /// Controller is disconnected.
+  GVR_CONTROLLER_DISCONNECTED = 0,
+  /// Controller is scanning.
+  GVR_CONTROLLER_SCANNING = 1,
+  /// Controller is connecting.
+  GVR_CONTROLLER_CONNECTING = 2,
+  /// Controller is connected.
+  GVR_CONTROLLER_CONNECTED = 3,
+} gvr_controller_connection_state;
+
+/// Controller buttons.
+typedef enum {
+  GVR_CONTROLLER_BUTTON_NONE = 0,
+  GVR_CONTROLLER_BUTTON_CLICK = 1,  ///< Touchpad Click.
+  GVR_CONTROLLER_BUTTON_HOME = 2,
+  GVR_CONTROLLER_BUTTON_APP = 3,
+  GVR_CONTROLLER_BUTTON_VOLUME_UP = 4,
+  GVR_CONTROLLER_BUTTON_VOLUME_DOWN = 5,
+
+  /// Note: there are 5 buttons on the controller, but the state arrays have
+  /// this many elements due to the inclusion of a dummy "none" button.
+  GVR_CONTROLLER_BUTTON_COUNT = 6,
+} gvr_controller_button;
+
+/// @}
+
+/// Opaque handle to controller state.
+typedef struct gvr_controller_state_ gvr_controller_state;
+
+/// @addtogroup types
+/// @{
+
+/// Rendering modes define CPU load / rendering quality balances.
+typedef enum {
+  /// Stereo panning of all Sound Objects. This disables HRTF-based rendering.
+  GVR_AUDIO_RENDERING_STEREO_PANNING = 0,
+  /// HRTF-based rendering over a virtual array of 8 loudspeakers arranged in
+  /// a cube configuration around the listener’s head.
+  GVR_AUDIO_RENDERING_BINAURAL_LOW_QUALITY = 1,
+  /// HRTF-based rendering over a virtual array of 16 loudspeakers arranged in
+  /// an approximate equidistribution about the around the listener’s head.
+  GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY = 2,
+} gvr_audio_rendering_mode;
+
+/// Room surface material names, used to set room properties.
+typedef enum {
+  /// Acoustically transparent material, reflects no sound.
+  GVR_AUDIO_MATERIAL_TRANSPARENT = 0,
+  /// Acoustic ceiling tiles, absorbs most frequencies.
+  GVR_AUDIO_MATERIAL_ACOUSTIC_CEILING_TILES = 1,
+  /// Bare brick, relatively reflective.
+  GVR_AUDIO_MATERIAL_BRICK_BARE = 2,
+  /// Painted brick
+  GVR_AUDIO_MATERIAL_BRICK_PAINTED = 3,
+  /// Coarse surface concrete block.
+  GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_COARSE = 4,
+  /// Painted concrete block.
+  GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_PAINTED = 5,
+  /// Heavy curtains.
+  GVR_AUDIO_MATERIAL_CURTAIN_HEAVY = 6,
+  /// Fiber glass insulation.
+  GVR_AUDIO_MATERIAL_FIBER_GLASS_INSULATION = 7,
+  /// Thin glass.
+  GVR_AUDIO_MATERIAL_GLASS_THIN = 8,
+  /// Thick glass.
+  GVR_AUDIO_MATERIAL_GLASS_THICK = 9,
+  /// Grass.
+  GVR_AUDIO_MATERIAL_GRASS = 10,
+  /// Linoleum on concrete.
+  GVR_AUDIO_MATERIAL_LINOLEUM_ON_CONCRETE = 11,
+  /// Marble.
+  GVR_AUDIO_MATERIAL_MARBLE = 12,
+  /// Galvanized sheet metal.
+  GVR_AUDIO_MATERIAL_METAL = 13,
+  /// Wooden parquet on concrete.
+  GVR_AUDIO_MATERIAL_PARQUET_ON_CONCRETE = 14,
+  /// Rough plaster surface.
+  GVR_AUDIO_MATERIAL_PLASTER_ROUGH = 15,
+  /// Smooth plaster surface.
+  GVR_AUDIO_MATERIAL_PLASTER_SMOOTH = 16,
+  /// Plywood panel.
+  GVR_AUDIO_MATERIAL_PLYWOOD_PANEL = 17,
+  /// Polished concrete OR tile surface.
+  GVR_AUDIO_MATERIAL_POLISHED_CONCRETE_OR_TILE = 18,
+  /// Sheet rock.
+  GVR_AUDIO_MATERIAL_SHEET_ROCK = 19,
+  /// Surface of water or ice.
+  GVR_AUDIO_MATERIAL_WATER_OR_ICE_SURFACE = 20,
+  /// Wooden ceiling.
+  GVR_AUDIO_MATERIAL_WOOD_CEILING = 21,
+  /// Wood paneling.
+  GVR_AUDIO_MATERIAL_WOOD_PANEL = 22,
+} gvr_audio_material_type;
+
+/// Distance rolloff models used for distance attenuation.
+typedef enum {
+  /// Logarithmic distance rolloff model.
+  GVR_AUDIO_ROLLOFF_LOGARITHMIC = 0,
+  /// Linear distance rolloff model.
+  GVR_AUDIO_ROLLOFF_LINEAR = 1,
+  /// No distance attenuation will be applied.
+  GVR_AUDIO_ROLLOFF_NONE = 2,
+} gvr_audio_distance_rolloff_type;
+
+/// Sound object and sound field identifier.
+typedef int32_t gvr_audio_source_id;
+
+/// Valid color formats for swap chain buffers.
+typedef enum {
+  /// Equivalent to GL_RGBA8
+  GVR_COLOR_FORMAT_RGBA_8888 = 0,
+  /// Equivalent to GL_RGB565
+  GVR_COLOR_FORMAT_RGB_565 = 1,
+} gvr_color_format_type;
+
+typedef enum {
+  /// No depth or stencil buffer.
+  GVR_DEPTH_STENCIL_FORMAT_NONE = 255,
+  /// Equivalent to GL_DEPTH_COMPONENT16.
+  GVR_DEPTH_STENCIL_FORMAT_DEPTH_16 = 0,
+  /// Equivalent to GL_DEPTH_COMPONENT24.
+  GVR_DEPTH_STENCIL_FORMAT_DEPTH_24 = 1,
+  /// Equivlaent to GL_DEPTH24_STENCIL8.
+  GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8 = 2,
+  /// Equivalent to GL_DEPTH_COMPONENT32F.
+  GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F = 3,
+  /// Equivalent to GL_DEPTH_32F_STENCIL8.
+  GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8 = 4,
+  /// Equivalent to GL_STENCIL8.
+  GVR_DEPTH_STENCIL_FORMAT_STENCIL_8 = 5,
+} gvr_depth_stencil_format_type;
+
+/// Types of asynchronous reprojection.
+typedef enum {
+  /// Do not reproject.
+  GVR_REPROJECTION_NONE = 0,
+  /// Reproject in all dimensions.
+  GVR_REPROJECTION_FULL = 1,
+} gvr_reprojection;
+
+typedef enum {
+  GVR_CONTROLLER_RIGHT_HANDED = 0,
+  GVR_CONTROLLER_LEFT_HANDED = 1,
+} gvr_controller_handedness;
+
+typedef struct gvr_user_prefs_ gvr_user_prefs;
+
+// Anonymous enum for miscellaneous integer constants.
+enum {
+  /// Constant that represents a nonexistent external surface. Pass to
+  /// gvr_buffer_viewport_set_external_surface_id() to disable sampling from
+  /// an external surface.
+  GVR_EXTERNAL_SURFACE_ID_NONE = -1,
+  /// Special index for a source buffer that has the same contents as the
+  /// external surface attached to the given viewport. Pass this to
+  /// gvr_buffer_viewport_set_source_buffer_index() to use the external surface
+  /// as the buffer contents.
+  GVR_BUFFER_INDEX_EXTERNAL_SURFACE = -1,
+};
+
+/// @}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+// These typedefs convert the C-style names to C++-style names.
+
+namespace gvr {
+
+const int32_t kControllerEnableOrientation =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_ORIENTATION);
+const int32_t kControllerEnableTouch =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_TOUCH);
+const int32_t kControllerEnableGyro =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_GYRO);
+const int32_t kControllerEnableAccel =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_ACCEL);
+const int32_t kControllerEnableGestures =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_GESTURES);
+const int32_t kControllerEnablePosePrediction =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_POSE_PREDICTION);
+const int32_t kControllerEnablePosition =
+    static_cast<int32_t>(GVR_CONTROLLER_ENABLE_POSITION);
+
+typedef gvr_controller_api_status ControllerApiStatus;
+const ControllerApiStatus kControllerApiOk =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_OK);
+const ControllerApiStatus kControllerApiUnsupported =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_UNSUPPORTED);
+const ControllerApiStatus kControllerApiNotAuthorized =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_NOT_AUTHORIZED);
+const ControllerApiStatus kControllerApiUnavailable =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_UNAVAILABLE);
+const ControllerApiStatus kControllerApiServiceObsolete =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_SERVICE_OBSOLETE);
+const ControllerApiStatus kControllerApiClientObsolete =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_CLIENT_OBSOLETE);
+const ControllerApiStatus kControllerApiMalfunction =
+    static_cast<ControllerApiStatus>(GVR_CONTROLLER_API_MALFUNCTION);
+
+typedef gvr_controller_connection_state ControllerConnectionState;
+const ControllerConnectionState kControllerDisconnected =
+    static_cast<ControllerConnectionState>(GVR_CONTROLLER_DISCONNECTED);
+const ControllerConnectionState kControllerScanning =
+    static_cast<ControllerConnectionState>(GVR_CONTROLLER_SCANNING);
+const ControllerConnectionState kControllerConnecting =
+    static_cast<ControllerConnectionState>(GVR_CONTROLLER_CONNECTING);
+const ControllerConnectionState kControllerConnected =
+    static_cast<ControllerConnectionState>(GVR_CONTROLLER_CONNECTED);
+
+typedef gvr_controller_button ControllerButton;
+const ControllerButton kControllerButtonNone =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_NONE);
+const ControllerButton kControllerButtonClick =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_CLICK);
+const ControllerButton kControllerButtonHome =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_HOME);
+const ControllerButton kControllerButtonApp =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_APP);
+const ControllerButton kControllerButtonVolumeUp =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_VOLUME_UP);
+const ControllerButton kControllerButtonVolumeDown =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_VOLUME_DOWN);
+const ControllerButton kControllerButtonCount =
+    static_cast<ControllerButton>(GVR_CONTROLLER_BUTTON_COUNT);
+
+/// An uninitialized external surface ID.
+const int32_t kUninitializedExternalSurface = GVR_BUFFER_INDEX_EXTERNAL_SURFACE;
+/// The default source buffer index for viewports.
+const int32_t kDefaultBufferIndex = 0;
+
+typedef gvr_eye Eye;
+
+typedef gvr_viewer_type ViewerType;
+const ViewerType kViewerTypeCardboard =
+    static_cast<ViewerType>(GVR_VIEWER_TYPE_CARDBOARD);
+const ViewerType kViewerTypeDaydream =
+    static_cast<ViewerType>(GVR_VIEWER_TYPE_DAYDREAM);
+
+typedef gvr_version Version;
+typedef gvr_sizei Sizei;
+typedef gvr_recti Recti;
+typedef gvr_rectf Rectf;
+typedef gvr_vec2f Vec2f;
+typedef gvr_vec3f Vec3f;
+typedef gvr_mat4f Mat4f;
+typedef gvr_quatf Quatf;
+typedef gvr_clock_time_point ClockTimePoint;
+
+typedef gvr_vec2f ControllerVec2;
+typedef gvr_vec3f ControllerVec3;
+typedef gvr_quatf ControllerQuat;
+
+typedef gvr_audio_rendering_mode AudioRenderingMode;
+typedef gvr_audio_material_type AudioMaterialName;
+typedef gvr_audio_distance_rolloff_type AudioRolloffMethod;
+typedef gvr_audio_source_id AudioSourceId;
+
+typedef gvr_color_format_type ColorFormat;
+const ColorFormat kColorFormatRgba8888 =
+    static_cast<ColorFormat>(GVR_COLOR_FORMAT_RGBA_8888);
+const ColorFormat kColorFormatRgb565 =
+    static_cast<ColorFormat>(GVR_COLOR_FORMAT_RGB_565);
+
+typedef gvr_depth_stencil_format_type DepthStencilFormat;
+const DepthStencilFormat kDepthStencilFormatNone =
+    static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_NONE);
+const DepthStencilFormat kDepthStencilFormatDepth16 =
+    static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16);
+const DepthStencilFormat kDepthStencilFormatDepth24 =
+    static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_24);
+const DepthStencilFormat kDepthStencilFormatDepth24Stencil8 =
+    static_cast<DepthStencilFormat>(
+        GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8);
+const DepthStencilFormat kDepthStencilFormatDepth32f =
+    static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F);
+const DepthStencilFormat kDepthStencilFormatDepth32fStencil8 =
+    static_cast<DepthStencilFormat>(
+        GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8);
+const DepthStencilFormat kDepthStencilFormatStencil8 =
+    static_cast<DepthStencilFormat>(GVR_DEPTH_STENCIL_FORMAT_STENCIL_8);
+
+typedef gvr_controller_handedness ControllerHandedness;
+const ControllerHandedness kControllerRightHanded =
+    static_cast<ControllerHandedness>(GVR_CONTROLLER_RIGHT_HANDED);
+const ControllerHandedness kControllerLeftHanded =
+    static_cast<ControllerHandedness>(GVR_CONTROLLER_LEFT_HANDED);
+
+typedef gvr_error Error;
+const Error kErrorNone = static_cast<Error>(GVR_ERROR_NONE);
+const Error kErrorControllerCreateFailed =
+    static_cast<Error>(GVR_ERROR_CONTROLLER_CREATE_FAILED);
+const Error kErrorNoFrameAvailable =
+    static_cast<Error>(GVR_ERROR_NO_FRAME_AVAILABLE);
+
+class AudioApi;
+class BufferSpec;
+class ControllerApi;
+class ControllerState;
+class Frame;
+class GvrApi;
+class BufferViewport;
+class BufferViewportList;
+class SwapChain;
+class UserPrefs;
+
+}  // namespace gvr
+
+// Non-member equality operators for convenience. Since typedefs do not trigger
+// argument-dependent lookup, these operators have to be defined for the
+// underlying types.
+inline bool operator==(const gvr_vec2f& lhs, const gvr_vec2f& rhs) {
+  return lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+inline bool operator!=(const gvr_vec2f& lhs, const gvr_vec2f& rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_vec3f& lhs, const gvr_vec3f& rhs) {
+  return lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+inline bool operator!=(const gvr_vec3f& lhs, const gvr_vec3f& rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_recti& lhs, const gvr_recti& rhs) {
+  return lhs.left == rhs.left && lhs.right == rhs.right &&
+         lhs.bottom == rhs.bottom && lhs.top == rhs.top;
+}
+
+inline bool operator!=(const gvr_recti& lhs, const gvr_recti& rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_rectf& lhs, const gvr_rectf& rhs) {
+  return lhs.left == rhs.left && lhs.right == rhs.right &&
+         lhs.bottom == rhs.bottom && lhs.top == rhs.top;
+}
+
+inline bool operator!=(const gvr_rectf& lhs, const gvr_rectf& rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator==(const gvr_sizei& lhs, const gvr_sizei& rhs) {
+  return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const gvr_sizei& lhs, const gvr_sizei& rhs) {
+  return !(lhs == rhs);
+}
+
+#endif  // #if defined(__cplusplus) && !defined(GVR_NO_CPP_WRAPPER)
+
+#endif  // VR_GVR_CAPI_INCLUDE_GVR_TYPES_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h
new file mode 100644
index 0000000..6bc2b4e
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_experimental.h
@@ -0,0 +1,240 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
+#define VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "vr/gvr/capi/include/gvr_types.h"
+#include "vr/gvr/capi/src/gvr_types_experimental.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// NOTE: APIs added to this file are *not* part of the core GVR library, and
+// should only be used for prototyping or experimental projects. The idea is
+// that APIs added here can be used for testing and development, graduating to
+// the core API (gvr.h or gvr_private.h) after we're ready to commit to them
+// indefinitely.
+
+// ************************************************************************** //
+// *                     DaydreamOS experimental APIs                       * //
+// ************************************************************************** //
+
+/// Gets the position and rotation from start space to head space.  The head
+/// space is a space where the head is at the origin and faces the -Z direction.
+///
+/// @param gvr Pointer to the gvr instance from which to get the pose.
+/// @param time The time at which to get the head pose. The time should be in
+///     the future. If the time is not in the future, it will be clamped to now.
+/// @return A matrix representation of the position and rotation from start
+//      space (the space where the head was last reset) to head space (the space
+///     with the head at the origin, and the axes aligned to the view vector).
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+    gvr_context* gvr, const gvr_clock_time_point time);
+
+/// Sets the compositor z-order of the swap chain.
+///
+/// @param swap_chain the swap chain to change.
+/// @param z_order Z order, higher values are displayed on top of lower ones,
+///     the default value is 0.
+void gvr_swap_chain_set_z_order(const gvr_swap_chain* swap_chain, int z_order);
+
+/// Creates a gvr_external_surface instance.
+/// An external surface is mainly used to pass external content (such as video
+/// frames, pre-rendered 2D Android UI) into distortion pass for compositing.
+/// The method gvr_external_surface_get_surface can be used to bridge Android
+/// components with GVR distortion pass via a traditional Android Surface
+/// instance.
+///
+/// @param gvr Pointer to the gvr instance from which to create the external
+///     surface.
+/// @return Pointer to an allocated gvr_external_surface object. The caller
+//      is responsible for calling gvr_external_surface_destroy() on the
+///     returned object when it is no longer needed.
+gvr_external_surface* gvr_external_surface_create(gvr_context* gvr);
+
+/// Frees a gvr_external_surface instance and clears the pointer.
+/// Note that once a gvr_external_surface is destroyed, the Java Surface object
+/// returned from gvr_external_surface_get_surface remains to be accessible and
+/// functioning. It's up to Java's garbage collection to release all resources
+/// behind the Java Surface object.
+///
+/// @param surface Pointer to a pointer to the gvr_external_surface instance to
+///     be destroyed and nulled.
+void gvr_external_surface_destroy(gvr_external_surface** surface);
+
+/// Get an Android Surface as a Java object from the gvr_external_surface. This
+/// API is mainly used by standalone display service (aka when
+/// gvr_using_vr_display_service returns true) to access an Android Surface.
+///
+/// @param surface The gvr_external_surface associated with the Android Surface.
+///     Note that this API has to be called within a JNIEnv and is using the
+///     JNIEnv passed in during gvr_create.
+/// @return A jobject that is an instance of the 'android/view/Surface' Java
+///     class, NULL on failure. Note that the return value is really an opaque
+///     handle to a Java object and the life cycle of that object is maintained
+///     by Java (i.e. it will get garbage collected eventually). Thus, there is
+///     no need for an explicit destroy call.
+void* gvr_external_surface_get_surface(const gvr_external_surface* surface);
+
+/// Get the Surface ID associated with the gvr_external_surface. Note that the
+/// returned ID is used for internal bookkeeping only and should not be used
+/// by the app itself for lookups.
+/// @param surface The gvr_external_surface to query the ID for.
+/// @return The external surface ID associated with the gvr_external_surface.
+int32_t gvr_external_surface_get_surface_id(
+    const gvr_external_surface* surface);
+
+/// Queries whether a particular GVR feature is supported by the underlying
+/// platform.
+///
+/// @param gvr The context to query against.
+/// @param feature The gvr_feature type being queried.
+/// @return true if feature is supported, false otherwise.
+bool gvr_experimental_is_feature_supported(const gvr_context* gvr,
+                                           int32_t feature);
+
+/// Sets the z order of the layer to be created.
+/// Note that this API is a short-term workaround for SysUI work and is never
+/// meant to graduate as is to either gvr.h or gvr_private.h. The proper
+/// solution is tracked in b/33946428 and probably involves setting the
+/// attribute on some data structure that represents a layer.
+///
+/// @param spec Buffer specification.
+/// @param z_order Z order, higher values are displayed on top of lower ones,
+///     the default value is 0.
+void gvr_buffer_spec_set_z_order(gvr_buffer_spec* spec, int z_order);
+
+/// Sets the initial visibility of the layer to be created.
+/// Note that this API is a short-term workaround for SysUI work and is never
+/// meant to graduate as is to either gvr.h or gvr_private.h. The proper
+/// solution is tracked in b/33946428 and probably involves setting the
+/// attribute on some data structure that represents a layer.
+///
+/// @param spec Buffer specification.
+/// @param visibility Initial visibility of the layer, defaults to GVR_VISIBLE.
+///     See enum gvr_visibility for possible values.
+void gvr_buffer_spec_set_visibility(gvr_buffer_spec* spec,
+                                    int32_t visibility);
+
+/// Sets whether to blur layers below the layer to be created.
+/// Blurring is applied only to visible layers and only when the layer is
+/// visible.
+/// Note that this API currently is only implemented by the DreamOS
+/// implementation of GVR and is a no-op in other implementations.
+/// TODO(b/33946428): investigate the proper way to surface this feature
+/// to SysUI.
+///
+/// @param spec Buffer specification.
+/// @param blur_behind whether to blur layers behind, defaults to
+///     GVR_BLUR_BEHIND_TRUE. See enum gvr_blur_behind for possible values.
+void gvr_buffer_spec_set_blur_behind(gvr_buffer_spec* spec,
+                                     int32_t blur_behind);
+
+// ************************************************************************** //
+// *                     Daydream PlexEng experimental APIs                 * //
+// ************************************************************************** //
+
+// Registers a new performance event listener that will be invoked on points
+// of interest. By default no event listener is attached.  If multiple event
+// listeners are attached they will all be invoked.  Failures can be checked
+// with gvr_get_error().
+// @param out_handle The pointer to memory where a successfully created handle
+//     will be written.
+// @param gvr The context to register callbacks for.
+// @param user_data The pointer that will be passed back on callbacks for
+//     user_data.
+// @param event_callback The callback to be invoked when an event is observed.
+//     On performance events callback will be invoked with the
+//     user_data passed here, the gvr_perf_event_callback_type, and a float
+//     value (if applicable) or -1.f.
+// @return Returns GVR_EXPERIMENTAL_ERROR_NONE if a handle was created,
+//     GVR_EXPERIMENTAL_ERROR_UNIMPLEMENTED if this feature is disabled,
+//     or GVR_EXPERIMENTAL_ERROR_INVALID_ARGUMENT if a null pointer was passed.
+bool gvr_experimental_register_perf_event_callback(
+    gvr_context* gvr, int* out_handle, void* user_data,
+    void (*event_callback)(void*, int, float));
+
+// Unregisters a previously registered callback by its handle. Failures can be
+// checked with gvr_get_error().
+// @param handle The handle which was returned when registering the callback.
+// @return Returns GVR_EXPERIMENTAL_ERROR_NONE if callback was unregistered,
+//     GVR_EXPERIMENTAL_ERROR_INVALID_ARGUMENT if the if the handle wasn't
+//     previously
+//     registered.  If this feature is not enabled it will return
+//     GVR_EXPERIMENTAL_ERROR_UNIMPLEMENTED.
+bool gvr_experimental_unregister_perf_event_callback(gvr_context* gvr,
+                                                     int handle);
+
+// ************************************************************************** //
+// *                    GVR Analytics experimental APIs                     * //
+// ************************************************************************** //
+// TODO(b/31634289): These functions are experimental because their main client
+// case is the performance monitoring HUD, whose form and function is still
+// under development. Consequently, the analytics API may change as the HUD's
+// needs become clearer.
+//
+// These functions will be moved into the main API (probably gvr_private.h) once
+// the HUD is ready to be shipped as part of the SDK.
+//
+// Contacts: georgelu@
+
+/// Returns whether the "Performance Monitoring" developer option is enabled.
+///
+/// @param user_prefs Pointer to the gvr_user_prefs object returned by
+///     gvr_get_user_prefs.
+/// @return True if the "Performance Monitoring" developer option is enabled.
+bool gvr_user_prefs_get_performance_monitoring_enabled(
+    const gvr_user_prefs* user_prefs);
+
+// Opaque struct returned by gvr_get_analytics that can be queried through
+// gvr_analytics_get* functions.
+//
+// Note: The struct is never actually defined since gvr_analytics is actually
+// just a static_cast of a gvr_context, similar to how gvr_user_prefs works.
+typedef struct gvr_analytics_ gvr_analytics;
+
+// Returns an opaque struct that can be queried for analytics data. The returned
+// struct remains valid as long as the context is valid.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @return An opaque struct that can be queried through gvr_analytics_*
+//     functions.
+const gvr_analytics* gvr_get_analytics(gvr_context* gvr);
+
+// If the "Performance Monitoring" developer option in VR settings is enabled,
+// returns a gvr_analytics_sample* containing analytics data. Caller is
+// responsible for calling gvr_analytics_destroy_sample on the returned object.
+//
+// @param analytics gvr_analytics* returned by gvr_get_analytics.
+// @return gvr_analytics_sample* containing analytics data.
+const gvr_analytics_sample* gvr_analytics_create_sample(
+    const gvr_analytics* analytics);
+
+// Returns pointer to a buffer containing a serialized AnalyticsSample proto.
+// The buffer is valid only for the lifetime of the gvr_analytics_sample.
+//
+// @param Pointer to a gvr_analytics_sample object.
+// @return Pointer to buffer.
+const char* gvr_analytics_sample_get_buffer(const gvr_analytics_sample* sample);
+
+// Returns the length of the buffer returned by gvr_analytics_sample_get_buffer.
+//
+// @param Pointer to a gvr_analytics_sample object.
+// @return Length of buffer.
+size_t gvr_analytics_sample_get_buffer_length(
+    const gvr_analytics_sample* sample);
+
+// Destroys a gvr_analytics_sample* previously created through
+// gvr_analytics_create_sample.
+//
+// @param sample Pointer to pointer that will be set to null and whose
+//     underlying gvr_analytics_sample will be destroyed.
+void gvr_analytics_destroy_sample(const gvr_analytics_sample** sample);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_GVR_CAPI_SRC_GVR_EXPERIMENTAL_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h
new file mode 100644
index 0000000..0a9d30e
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_private.h
@@ -0,0 +1,378 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
+#define VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
+
+#include <stddef.h>
+
+#include "vr/gvr/capi/include/gvr_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Opaque handle to gvr_tracker_state object containing serialized state.
+typedef struct gvr_tracker_state_ gvr_tracker_state;
+
+// Opaque handle to gvr_display_synchronizer object for display synchronization.
+typedef struct gvr_display_synchronizer_ gvr_display_synchronizer;
+
+// Internal Google VR C API methods. These methods are exposed only to internal
+// targets, but should follow all the same backwards-compatible restrictions
+// as the public C API.
+
+/// Sets whether asynchronous reprojection is currently enabled.
+///
+/// If enabled, frames will be collected by the rendering system and
+/// asynchronously re-projected in sync with the scanout of the display. This
+/// feature may not be available on every platform, and requires a
+/// high-priority render thread with special extensions to function properly.
+///
+/// Note: On Android, this feature can be enabled solely via the GvrLayout Java
+/// instance which (indirectly) owns this gvr_context. The corresponding
+/// method call is GvrLayout.setAsyncReprojectionEnabled().
+///
+/// @param gvr Pointer to the gvr instance.
+/// @Param enabled Whether to enable async reprojection.
+/// @return Whether the setting was succesfully applied.
+bool gvr_set_async_reprojection_enabled(gvr_context* gvr, bool enabled);
+
+// Initializes necessary GL-related objects and uses the current thread and
+// GL context for racing the scanline. This function should only be called
+// by the SDK itself, not by any application, unless that application is
+// providing a high-priority thread and GL context for async reprojection.
+//
+// Note: This method is private as it is intended for use solely by the
+// hidden async reprojection implementation in ScanlineRacingRenderer.java,
+// called in onSurfaceCreated().
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_on_surface_created_reprojection_thread(gvr_context* gvr);
+
+// Renders the scanline layer. This function should only be called
+// in the same thread that gvr_initialize_gl_projection_thread was called in.
+// This function should only be called by the SDK itself, not by any
+// application, unless that application is providing a high-priority
+// thread and GL context for async reprojection.
+//
+// Note: This method is private as it is intended for use solely by the
+// hidden async reprojection implementation in ScanlineRacingRenderer.java.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_render_reprojection_thread(gvr_context* gvr);
+
+// Signals to the reprojection thread that it is paused. This is necessary
+// in case the application render thread is blocked on pending work by the
+// reprojection thread. This function will abort any blocking.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_on_pause_reprojection_thread(gvr_context* gvr);
+
+// Sets the parameters for the external surface managed by the reprojection
+// thread.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param surface_id The ID of the external Surface managed by the reprojection
+//     thread. The ID is issued by the SurfaceTextureManager.
+// @param texture_id The GL texture ID associated with the external Surface.
+// @param timestamp The timestamp of the most recent frame the Surface holds.
+// @param surface_transfrom Matrix that transforms homogeneous texture coords to
+//     the external surface texture space.
+void gvr_update_surface_reprojection_thread(gvr_context* gvr,
+      int32_t surface_id, int32_t texture_id, gvr_clock_time_point timestamp,
+      gvr_mat4f surface_transform);
+
+// Removes all external surfaces managed by the reprojection thread. This does
+// not destoy the surfaces: it removes tracking by the reprojection thread.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_remove_all_surfaces_reprojection_thread(gvr_context* gvr);
+
+// Reconnects the sensors when the sensor producers are created internally.
+//
+// Note: This function is not thread-safe, and should be called only on the
+// rendering thread. It is intended to be used internally by GvrLayout when
+// the target presentation display changes.
+//
+// @param gvr Pointer to the gvr_context instance.
+void gvr_reconnect_sensors(gvr_context* gvr);
+
+// Sets VR viewer params for the current context.
+//
+// Note: This function does not update the viewer proto in the common storage
+// location. Rather, it overrides the viewer params solely for the provided
+// gvr_context.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param serialized_viewer_params A pointer to the payload containing the
+//     serialized viewer params proto.
+// @param serialized_viewer_params_size_bytes The length in bytes of the
+//     serialized viewer params payload.
+// @return Whether the serialized viewer params proto was successfully applied.
+bool gvr_set_viewer_params(gvr_context* gvr,
+                           const void* serialized_viewer_params,
+                           size_t serialized_viewer_params_size_bytes);
+
+// Sets the lens offset.
+//
+// @param offset The offset of the lens center from the expected location in
+// screen space.
+void gvr_set_lens_offset(gvr_context* gvr, gvr_vec2f offset);
+
+// Sets display metrics for the current context.
+//
+// Note: This function does not update the phone proto in the commom storage
+// location. Rather, it overrides the internal metrics solely for the provided
+// |gvr| context.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param size_pixels The dimensions in pixels of the active display.
+// @param meters_per_pixel The density of the current display in meters/pixel.
+// @param border_size_meters The size of the border around the display
+//     in meters.  When the device sits on a surface in the proper
+//     orientation this is the distance from the surface to the edge
+//     of the display.
+void gvr_set_display_metrics(gvr_context* gvr, gvr_sizei size_pixels,
+                             gvr_vec2f meters_per_pixel,
+                             float border_size_meters);
+
+// Sets the display rotation offset that is applied at distortion correction
+// time to take into account the device's display orientation.
+//
+// For instance, calling this with display_output_rotation set to 1 allows
+// clients to lock their phone orientation to portrait on an Android phone and
+// still get a correctly rendered VR mode with the two eyes stacked up along the
+// longer phone dimension.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param display_output_rotation Value encoding the rotation used when
+//     performing distortion correction. Supported values are:
+//     0 - Default mode. Eye viewports are positioned side-by-side along the
+//         "width" dimension, with left eye in the x < 0.5 half.
+//     1 - Applies a clock-wise rotation of 90 degrees on the display when
+//         doing distortion correction. Eye viewports are positioned
+//         side-by-side along the "height" dimension, with left eye in the
+//         y > 0.5 half.
+// Rotation modes used when performing distortion correction.
+enum {
+  GVR_PRIVATE_DISPLAY_OUTPUT_ROTATION_0 = 0,
+  GVR_PRIVATE_DISPLAY_OUTPUT_ROTATION_90 = 1,
+};
+void gvr_set_display_output_rotation(gvr_context* gvr,
+                                     int32_t display_output_rotation);
+
+// Gets the size of the border around the display used by the given gvr_context.
+//
+// @param gvr Pointer to the gvr_context instance.
+float gvr_get_border_size_meters(const gvr_context* gvr);
+
+// Returns whether the surface size was changed since the last call to this
+// function (it's changed with gvr_set_surface_size()).
+//
+// @param gvr Pointer to the gvr_context instance.
+// @return Whether the surface size was changed.
+bool gvr_check_surface_size_changed(gvr_context* gvr);
+
+// Returns the current surface size in pixels, or (0, 0) if the surface size
+// matches that of the active display (which is the default).
+//
+// @param gvr Pointer to the gvr_context instance.
+// @return The current surface size in pixels.
+gvr_sizei gvr_get_surface_size(const gvr_context* gvr);
+
+// Sets a handler that is called back when the back gesture is detected,
+// which is when the phone changes from landscape to portrait orientation
+// within a few seconds.
+//
+// @param gvr Pointer to the gvr_context instance.
+// @param handler The event_handler callback. May be null to clear the
+//     registered event_handler.
+// @param user_data An opaque pointer to user_data which will be supplied
+//     as the callback argument. The caller is responsible for ensuring the
+//     validity of this data for the duration of the handler registration.
+typedef void (*event_handler)(void* user_data);
+void gvr_set_back_gesture_event_handler(gvr_context* gvr, event_handler handler,
+                                        void* user_data);
+
+// Internal method to pause head tracking used by GvrLayout. Disables all
+// sensors (to save power) and gets the serialized tracker state.
+//
+// @param gvr Pointer to the gvr instance for which tracking will be paused and
+//     sensors disabled.
+//
+// @return Pointer to a tracker_state object containing the serialized tracker
+//     state. The caller is responsible for calling destroy on the returned
+//     handle.
+gvr_tracker_state* gvr_pause_tracking_get_state(gvr_context* gvr);
+
+// Internal method to resume head tracking used by GvrLayout. Re-enables all
+// sensors and sets the tracker state.
+//
+// @param gvr Pointer to the gvr instance for which tracking will be resumed.
+//     serialized tracker state object.
+// @param tracker_state Pointer to a tracker_state object containing the
+//     serialized tracker state object.
+void gvr_resume_tracking_set_state(
+    gvr_context* gvr, gvr_tracker_state* tracker_state);
+
+// Sets the internal flag that ignores calls to the public API's
+// gvr_pause_tracking and gvr_resume_tracking.
+// When true, the tracker is handled through GvrLayout
+// gvr_pause_tracking_private / gvr_resume_tracking_private direct calls through
+// the GvrApi instance are ignored. This is workaround to temporarily support
+// clients using GvrLayout that manually call pause/ resume tracking.
+// TODO(b/30404822) : clean this up once all existing clients move away from the
+// obsolete behavior.
+//
+// @param gvr Pointer to the gvr instance.
+// @param should_ignore Whether manual pause / resume tracker should be ignored.
+void gvr_set_ignore_manual_tracker_pause_resume(gvr_context* gvr,
+                                                bool should_ignore);
+
+// Creates a new tracker state object from the serialized tracker state buffer.
+//
+// @param tracker_state_buffer Pointer to buffer containing the serialized
+// tracker state.
+// @param buf_size Size of the tracker state buffer.
+//
+// @return Pointer to a tracker_state object containing the serialized tracker
+// state string. The caller is responsible for calling destroy on the returned
+// handle.
+gvr_tracker_state* gvr_tracker_state_create(const char* tracker_state_buffer,
+                                            size_t buf_size);
+
+// Gets the size of the buffer that is required to hold the serialized
+// gvr_tracker_state.
+//
+// @param Pointer to a gvr_tracker_state object containing the serialized
+// tracker state.
+//
+// @return Size of the buffer,
+size_t gvr_tracker_state_get_buffer_size(gvr_tracker_state* tracker_state);
+
+// Gets the buffer that holds the serialized gvr_tracker_state.
+//
+// @param Pointer to a tracker_state object containing the serialized tracker
+// state.
+//
+// @return Pointer to the buffer.
+const char* gvr_tracker_state_get_buffer(gvr_tracker_state* tracker_state);
+
+// Destroys a gvr_tracker_state instance.
+//
+// @param tracker_state Pointer to a pointer of the gvr_tracker_state instance
+// to be destroyed and nulled.
+void gvr_tracker_state_destroy(gvr_tracker_state** tracker_state);
+
+// Creates a new synchronizer instance.
+//
+// @return synchronizer Pointer to the new gvr_display_synchronizer instance.
+gvr_display_synchronizer* gvr_display_synchronizer_create();
+
+// Destroy the synchonronizer instance and null the pointer.
+//
+// @param synchronizer Pointer to a pointer to the gvr_display_synchronizer
+//     instance.
+void gvr_display_synchronizer_destroy(gvr_display_synchronizer** synchronizer);
+
+// Resets the synchronizer with updated vsync timing data.
+//
+// @param synchronizer Pointer to the new gvr_display_synchronizer instance.
+// @param expected_interval_nanos The expected average time between
+//     synchronization times, in nanoseconds, or 0 if unknown.
+// @param vsync_offset_nanos The duration, in nanos, such that the current sync
+//     time minus the display vsync offset is the time when the physical
+//     scan-out hardware begins to read data from the frame buffer.
+void gvr_display_synchronizer_reset(gvr_display_synchronizer* synchronizer,
+                                    int64_t expected_interval_nanos,
+                                    int64_t vsync_offset_nanos);
+
+// Updates the synchronizer with dispplay data for a new frame.
+//
+// @param vsync_time The new frame's vsync time.
+// @param rotation_degrees The screen rotation from sensor space to display
+//     space in degrees.
+void gvr_display_synchronizer_update(gvr_display_synchronizer* synchronizer,
+                                     gvr_clock_time_point vsync_time,
+                                     int32_t rotation);
+
+// Installs the display synchronizer into a GVR context.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param synchronizer Pointer to the gvr_display_synchronizer instance, to be
+//     used by the context implementation during rendering.
+void gvr_set_display_synchronizer(gvr_context* gvr,
+                                  gvr_display_synchronizer* synchronizer);
+
+// Sets the current error code. Overwrites any existing error code.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param error_code The error code to set.
+void gvr_set_error(gvr_context* gvr, int32_t error_code);
+
+// Called by the platform layer to to indicate the application is paused. (e.g.
+// On Android, this function is called by GvrLayout.OnPause().)
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_pause(gvr_context* gvr);
+
+// Called by the platform layer to to indicate the application has resumed.
+// (e.g. On Android, this function is called by GvrLayout.OnResume().)
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_resume(gvr_context* gvr);
+
+// Dumps additional data to logcat or disk to be included in bug reports.
+//
+// @param gvr Pointer to the current gvr_context instance.
+void gvr_dump_debug_data(gvr_context* gvr);
+
+// Returns true if the libgvr implementation is using the dedicated VR display
+// service, false otherwise.
+//
+// @param gvr Pointer to the current gvr_context instance.
+bool gvr_using_vr_display_service(gvr_context* gvr);
+
+// Creates a new gvr_context using the supplied tracker, only for testing.
+//
+// Note: The pose returned is *in start space*. This is *not* the same space as
+// the pose normally returned by |gvr_get_head_space_from_start_space_rotation|.
+//
+// @param tracker The test pose tracker to use.
+// @param user_data An opaque pointer to user_data which will be supplied
+//     as the callback argument. The caller is responsible for ensuring the
+//     validity of this data for the duration of the handler registration.
+typedef gvr_mat4f (*gvr_test_pose_tracker)(void*, gvr_clock_time_point);
+gvr_context* gvr_create_with_tracker_for_testing(gvr_test_pose_tracker tracker,
+                                                 void* user_data);
+
+// Request resource sharing between the application's OpenGL context and the
+// scanline racing context.  This must be called before gvr_initialize_gl.
+// <p>
+// This is a best effort request rather than an explicit toggle; it is a no-op
+// if the client does not enable async reprojection, or if the platform does not
+// support resource sharing.
+// <p>
+// The only OpenGL resource that we need sharing for is the framebuffer texture
+// that the app renders to, and that distortion samples from.  If resource
+// sharing is disabled, then we use an EGLImage so that it can be accessed from
+// both contexts.
+// <p>
+// Also sets a callback function that is called at the end of gvr_initialize_gl,
+// while the application's OpenGL context is still active on the current thread.
+// This is used internally to notify the scanline racing renderer that the
+// application's OpenGL context has been created.
+//
+// @param gvr Pointer to the current gvr_context instance.
+// @param handler Callback that gets called when the app context becomes ready.
+// @param user_data An opaque pointer to user data which will be supplied
+//     as the callback argument. The caller is responsible for ensuring the
+//     validity of this data for the duration of the handler registration.
+typedef void (*gvr_egl_context_listener)(void*);
+void gvr_request_context_sharing(gvr_context* gvr,
+                                 gvr_egl_context_listener handler,
+                                 void* user_data);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_GVR_CAPI_SRC_GVR_PRIVATE_H_
diff --git a/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h
new file mode 100644
index 0000000..1df2443
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/include/vr/gvr/capi/src/gvr_types_experimental.h
@@ -0,0 +1,68 @@
+#ifndef VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
+#define VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
+
+#include <string>
+
+// ************************************************************************** //
+// *                     DaydreamOS experimental Types                * //
+// ************************************************************************** //
+
+// Visibility of a layer.
+typedef enum {
+  GVR_INVISIBLE = 0,
+  GVR_VISIBLE = 1,
+} gvr_visibility;
+
+// Whether to blur layers behind a layer.
+typedef enum {
+  GVR_BLUR_BEHIND_FALSE = 0,
+  GVR_BLUR_BEHIND_TRUE = 1,
+} gvr_blur_behind;
+
+// GVR external surface
+typedef struct gvr_external_surface_ gvr_external_surface;
+
+// ************************************************************************** //
+// *                     Daydream PlexEng experimental Types                * //
+// ************************************************************************** //
+
+// Types of events that can have callbacks registered.
+// If documented, type will return a payload value when called, or will
+// otherwise be invoked with -1.f.
+// This enum has to be duplicated because there is no way to include from
+// /vr/gvr/render/performance_registry.h.  Duplicate changes made here there.
+typedef enum {
+  // Will be invoked with value -1.f.
+  GVR_ON_ASYNC_REPROJECTION_FRAME_START = 0,
+  // Will be invoked with value -1.f.
+  GVR_ON_ASYNC_REPROJECTION_FRAME_STOP = 1,
+  // When invoked will be called with how late in microseconds the frame was.
+  GVR_ON_ASYNC_REPROJECTION_FRAME_DROP = 2,
+  // The number of types of performance events you can have.
+  // Also note that this value is considered invalid.
+  GVR_NUM_PERF_EVENT_CALLBACK_TYPES = 3,
+} gvr_perf_event_callback_type;
+
+// Types of VR-specific features which may or may not be supported on the
+// underlying platform.
+typedef enum {
+  // Asynchronous reprojection warps the app's rendered frame using the most
+  // recent head pose just before pushing the frame to the display.
+  GVR_ASYNC_REPROJECTION = 0,
+  // Head tracking with 6 degrees of freedom (position & rotation)
+  GVR_6DOF_HEAD_POSE = 1,
+} gvr_feature;
+
+// ************************************************************************** //
+// *                    GVR Analytics experimental APIs                     * //
+// ************************************************************************** //
+
+// Opaque struct returned by gvr_analytics_create_sample, used to transmit an
+// AnaylticsSample proto across the native layer.
+typedef struct gvr_analytics_sample_ {
+  // Serialized AnalyticsSample proto. Note that this is not a C string, meaning
+  // it is not null-terminated and may contain non-terminating nulls.
+  std::string serialized_proto;
+} gvr_analytics_sample;
+
+#endif  // VR_GVR_CAPI_SRC_GVR_TYPES_EXPERIMENTAL_H_
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so
new file mode 100644
index 0000000..1d0ba50
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so
new file mode 100644
index 0000000..905ca64
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm/libgvr_audio.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so
new file mode 100644
index 0000000..d62f7ca
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so
new file mode 100644
index 0000000..e342f6a
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/android_arm64/libgvr_audio.so
Binary files differ
diff --git a/libs/vr/libgvr/prebuilt/lib/common_library.aar b/libs/vr/libgvr/prebuilt/lib/common_library.aar
new file mode 100644
index 0000000..13147fe
--- /dev/null
+++ b/libs/vr/libgvr/prebuilt/lib/common_library.aar
Binary files differ
diff --git a/libs/vr/libgvr/shim_gvr.cpp b/libs/vr/libgvr/shim_gvr.cpp
new file mode 100644
index 0000000..4b074e7
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr.cpp
@@ -0,0 +1,1358 @@
+#define LOG_TAG "libgvr_shim"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl31.h>
+#include <GLES3/gl3ext.h>
+#include <algorithm>
+#include <cmath>
+
+#ifdef __ARM_NEON
+#include <arm_neon.h>
+#else
+#ifndef __FLOAT32X4T_86
+#define __FLOAT32X4T_86
+typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
+typedef struct float32x4x4_t { float32x4_t val[4]; };
+#endif
+#endif
+
+#include <cutils/log.h>
+#include <dvr/graphics.h>
+#include <dvr/performance_client_api.h>
+#include <dvr/pose_client.h>
+#include <private/dvr/buffer_hub_queue_core.h>
+#include <private/dvr/buffer_hub_queue_producer.h>
+#include <private/dvr/clock_ns.h>
+#include <private/dvr/display_client.h>
+#include <private/dvr/graphics_private.h>
+#include <private/dvr/internal_types.h>
+#include <private/dvr/numeric.h>
+#include <private/dvr/types.h>
+#include <private/dvr/video_mesh_surface_client.h>
+#include <sys/system_properties.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/include/gvr_ext.h>
+#include <vr/gvr/capi/include/gvr_util.h>
+#include <vr/gvr/capi/src/gvr_experimental.h>
+#include <vr/gvr/capi/src/gvr_private.h>
+
+#include <android_runtime/android_view_Surface.h>
+#include <gui/Surface.h>
+
+using android::dvr::DisplayClient;
+using android::dvr::EigenToGvrMatrix;
+using android::dvr::FieldOfView;
+using android::dvr::FovRadiansToDegrees;
+using android::dvr::GetSystemClockNs;
+using android::dvr::GvrIdentityMatrix;
+using android::dvr::GvrMatrixToPosef;
+using android::dvr::GvrToDvrFov;
+using android::dvr::GvrToEigenMatrix;
+using android::dvr::GvrToEigenRotation;
+using android::dvr::GvrTranslationMatrix;
+using android::dvr::IsEqual;
+using android::dvr::PosefToGvrMatrix;
+using android::dvr::mat3;
+using android::dvr::mat4;
+using android::dvr::Posef;
+using android::dvr::quat;
+using android::dvr::vec3;
+
+namespace {
+
+constexpr static int32_t GVR_SDK_MAJOR_VERSION = 2;
+constexpr static int32_t GVR_SDK_MINOR_VERSION = 0;
+constexpr static int32_t GVR_SDK_PATCH_VERSION = 0;
+
+// The "DaydreamOS" part has been appended to make easier to see when VrCore
+// dynamic GVR API loading is effectively working.
+static const char* kVersionString = "2.0.0 DaydreamOS";
+static const char* kViewerVendor = "Google";
+static const char* kViewerModel = "Lucid";
+
+// Experimental system property used to provide 6DoF information on 3DoF APIs.
+static const char* kForce6DofProp = "experimental.force_6dof";
+
+static constexpr int kControllerCount = 2;
+
+gvr_frame* GetFrameFromSwapChain(gvr_swap_chain* swap_chain) {
+  return reinterpret_cast<gvr_frame*>(swap_chain);
+}
+
+gvr_swap_chain* GetSwapChainForFrame(gvr_frame* frame) {
+  return reinterpret_cast<gvr_swap_chain*>(frame);
+}
+
+const gvr_swap_chain* GetSwapChainForFrame(const gvr_frame* frame) {
+  return reinterpret_cast<const gvr_swap_chain*>(frame);
+}
+
+// Returns the world to head transform as a Posef.
+Posef ToPosef(const DvrPoseAsync& pose) {
+  return Posef(
+      quat(pose.orientation[3], pose.orientation[0], pose.orientation[1],
+           pose.orientation[2]),
+      vec3(pose.translation[0], pose.translation[1], pose.translation[2]));
+}
+
+// Returns the world to head transform, with 0 position, as a gvr matrix
+gvr_mat4f Gvr6dofTo3dof(const gvr_mat4f& pose) {
+  gvr_mat4f ret = pose;
+  ret.m[0][3] = 0;
+  ret.m[1][3] = 0;
+  ret.m[2][3] = 0;
+  return ret;
+}
+
+void GvrToDvrPose(gvr_mat4f world_to_head_transform,
+                  /*out*/ float32x4_t* orientation,
+                  /*out */ float32x4_t* translation) {
+  Posef pose = GvrMatrixToPosef(world_to_head_transform);
+  (*orientation)[0] = pose.GetRotation().x();
+  (*orientation)[1] = pose.GetRotation().y();
+  (*orientation)[2] = pose.GetRotation().z();
+  (*orientation)[3] = pose.GetRotation().w();
+  (*translation)[0] = pose.GetPosition().x();
+  (*translation)[1] = pose.GetPosition().y();
+  (*translation)[2] = pose.GetPosition().z();
+  (*translation)[3] = 0;
+}
+
+bool MatricesAlmostEqual(const gvr_mat4f& m1, const gvr_mat4f& m2,
+                         float tolerance) {
+  for (int row = 0; row < 4; ++row) {
+    for (int col = 0; col < 4; ++col) {
+      if (!IsEqual(m1.m[row][col], m2.m[row][col], tolerance))
+        return false;
+    }
+  }
+  return true;
+}
+
+gvr_mat4f FovToViewportTransform(const gvr_rectf& fov) {
+  // Depth range (1 1000) is chosen to match gvr impl in google3, which is
+  // chosen to match Unity integration.
+  return EigenToGvrMatrix(
+      GvrToDvrFov(fov).GetProjectionMatrix(1.f, 1000.f).inverse());
+}
+
+gvr_rectf ViewportTransformToFov(const gvr_mat4f& transform) {
+  return DvrToGvrFov(
+      FieldOfView::FromProjectionMatrix(GvrToEigenMatrix(transform).inverse()));
+}
+
+bool GetGlColorFormat(int32_t gvr_color_format,
+                      /*out*/ GLenum* gl_color_format) {
+  switch (gvr_color_format) {
+    case GVR_COLOR_FORMAT_RGBA_8888:
+      *gl_color_format = GL_RGBA8;
+      break;
+    case GVR_COLOR_FORMAT_RGB_565:
+      *gl_color_format = GL_RGB565;
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+bool GetGlDepthFormat(int32_t gvr_depth_format,
+                      /*out*/ GLenum* gl_depth_format) {
+  switch (gvr_depth_format) {
+    case GVR_DEPTH_STENCIL_FORMAT_DEPTH_16:
+      *gl_depth_format = GL_DEPTH_COMPONENT16;
+      break;
+    case GVR_DEPTH_STENCIL_FORMAT_DEPTH_24:
+      *gl_depth_format = GL_DEPTH_COMPONENT24;
+      break;
+    case GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8:
+      *gl_depth_format = GL_DEPTH24_STENCIL8;
+      break;
+    case GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F:
+      *gl_depth_format = GL_DEPTH_COMPONENT32F;
+      break;
+    case GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8:
+      *gl_depth_format = GL_DEPTH32F_STENCIL8;
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+// Returns true on success, false on failure. If the swap_chain already has a
+// DvrGraphicsContext and gvr buffer, they'll be freed first. If creation fails,
+// the DvrGraphicsContext in the swap_chain will be set to null and the
+// corresponding gvr buffer will be freed.
+bool CreateDvrGraphicsContextAndGvrBuffer(gvr_swap_chain* swap_chain) {
+  if (swap_chain->buffers_.empty()) {
+    ALOGE("Can't create a graphics context for an empty swap chain");
+    return false;
+  }
+
+  // We currently only render the first gvr buffer. Create a DvrGraphicsContext
+  // for the first buffer only.
+  gvr_buffer& buf = swap_chain->buffers_[0];
+  buf.FreeGl();
+
+  bool visible;
+  int z_order;
+  if (swap_chain->graphics_context_ != nullptr) {
+    visible = dvrGraphicsSurfaceGetVisible(swap_chain->graphics_context_);
+    z_order = dvrGraphicsSurfaceGetZOrder(swap_chain->graphics_context_);
+    dvrGraphicsContextDestroy(swap_chain->graphics_context_);
+    swap_chain->graphics_context_ = nullptr;
+  } else {
+    visible = buf.spec.initially_visible;
+    z_order = buf.spec.z_order;
+  }
+
+  int width = 0, height = 0;
+  GLuint texture_id = 0;
+  GLenum texture_target = 0;
+  DvrSurfaceParameter surface_params[] = {
+      DVR_SURFACE_PARAMETER_IN(DISABLE_DISTORTION, false),
+      DVR_SURFACE_PARAMETER_IN(CREATE_GL_CONTEXT, 0),
+      DVR_SURFACE_PARAMETER_IN(WIDTH, buf.spec.size.width),
+      DVR_SURFACE_PARAMETER_IN(HEIGHT, buf.spec.size.height),
+      DVR_SURFACE_PARAMETER_IN(BLUR_BEHIND, buf.spec.blur_behind),
+      DVR_SURFACE_PARAMETER_IN(VISIBLE, visible),
+      DVR_SURFACE_PARAMETER_IN(Z_ORDER, z_order),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_WIDTH, &width),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_HEIGHT, &height),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_TEXTURE_TARGET_TYPE, &texture_target),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_TEXTURE_TARGET_ID, &texture_id),
+      DVR_SURFACE_PARAMETER_LIST_END,
+  };
+
+  DvrGraphicsContext* graphics_context;
+  int ret = dvrGraphicsContextCreate(surface_params, &graphics_context);
+  if (ret < 0) {
+    ALOGE("dvrGraphicsContextCreate failed: %d (%s)", ret, strerror(-ret));
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return false;
+  }
+
+  // Sanity check that the size of the buffer we allocated from the system is
+  // what we expect
+  if (buf.spec.size != gvr_sizei{width, height}) {
+    ALOGE(
+        "The created surface is the wrong size."
+        " Should be %dx%d, instead got %dx%d.",
+        buf.spec.size.width, buf.spec.size.height, width, height);
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    dvrGraphicsContextDestroy(graphics_context);
+    return false;
+  }
+
+  buf = gvr_buffer(swap_chain->context, buf.spec, texture_id, texture_target);
+  if (buf.frame_buffer == 0) {
+    dvrGraphicsContextDestroy(graphics_context);
+    return false;
+  }
+
+  swap_chain->graphics_context_ = graphics_context;
+  return true;
+}
+
+bool SwapChainResizeBuffer(gvr_swap_chain* swap_chain, int buffer_index) {
+  gvr_buffer& buf = swap_chain->buffers_[buffer_index];
+  buf.FreeGl();
+  gvr_sizei orig_size = buf.spec.size;
+  buf.spec.size = buf.requested_size;
+  bool resize_successful = false;
+  if (buffer_index == 0) {
+    resize_successful = CreateDvrGraphicsContextAndGvrBuffer(swap_chain);
+  } else {
+    buf = gvr_buffer(swap_chain->context, buf.spec, 0, GL_TEXTURE_2D);
+    resize_successful = buf.frame_buffer != 0;
+  }
+
+  if (resize_successful) {
+    // The resize was successful, so clear the resize request
+    buf.requested_size = {-1, -1};
+  } else {
+    ALOGE("Failed to resize buffer. orig_size=%dx%d requested_size=%dx%d.",
+          orig_size.width, orig_size.height, buf.requested_size.width,
+          buf.requested_size.height);
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    buf.spec.size = orig_size;
+  }
+
+  return resize_successful;
+}
+
+void WaitNextFrame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+                   gvr_frame_schedule* out_next_frame_schedule,
+                   bool called_by_app) {
+  if (called_by_app)
+    swap_chain->wait_next_frame_called_by_app_ = true;
+
+  DvrFrameSchedule dvr_schedule;
+  int ret = dvrGraphicsWaitNextFrame(swap_chain->graphics_context_,
+                                     start_delay_nanos, &dvr_schedule);
+  if (ret < 0) {
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return;
+  }
+  if (out_next_frame_schedule) {
+    out_next_frame_schedule->vsync_count = dvr_schedule.vsync_count;
+    out_next_frame_schedule->scheduled_finish.monotonic_system_time_nanos =
+        dvr_schedule.scheduled_frame_finish_ns;
+  }
+
+  DvrPoseAsync pose;
+  ret = dvrPoseGet(swap_chain->context->pose_client_, dvr_schedule.vsync_count,
+                   &pose);
+  if (ret < 0) {
+    ALOGW("dvrPoseGet failed: %d", ret);
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return;
+  }
+
+  swap_chain->context->next_frame_6dof_pose_ = PosefToGvrMatrix(ToPosef(pose));
+
+  for (int i = 0; i < kControllerCount; ++i) {
+    ret = dvrPoseGetController(swap_chain->context->pose_client_, i,
+                               dvr_schedule.vsync_count, &pose);
+    if (ret == 0) {
+      // Silently fail when there are no controllers.
+      swap_chain->context->next_frame_controller_pose_[i] =
+          PosefToGvrMatrix(ToPosef(pose).Inverse());
+    }
+  }
+}
+
+bool VerifyBufferIndex(const std::string& function_name,
+                       const gvr_swap_chain* swap_chain, int index) {
+  if (index > static_cast<int32_t>(swap_chain->buffers_.size())) {
+    ALOGE("%s out of range buffer index. index=%d num_buffers=%zu.",
+          function_name.c_str(), index, swap_chain->buffers_.size());
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return false;
+  }
+  return true;
+}
+
+}  // anonymous namespace
+
+gvr_context* gvr_create(JNIEnv* env, jobject /* app_context */,
+                        jobject /* class_loader */) {
+  std::unique_ptr<gvr_context> context(new gvr_context);
+
+  // Set cpu set to avoid default scheduling randomness.
+  dvrSetCpuPartition(0, "/application/performance");
+
+  context->jni_env_ = env;
+  context->pose_client_ = dvrPoseCreate();
+  if (!context->pose_client_) {
+    ALOGE("Failed to create pose client");
+    return nullptr;
+  }
+
+  context->display_client_ = DisplayClient::Create();
+  if (!context->display_client_) {
+    ALOGE("Failed to create display client");
+    return nullptr;
+  }
+
+  int ret =
+      context->display_client_->GetDisplayMetrics(&context->display_metrics_);
+  if (ret < 0) {
+    ALOGE("Failed to get display metrics: %d (%s)", ret, strerror(-ret));
+    return nullptr;
+  }
+
+  const float* left_fov = context->display_metrics_.left_fov_lrbt.data();
+  context->left_eye_viewport_transform_ =
+      FovToViewportTransform(FovRadiansToDegrees(
+          gvr_rectf{left_fov[0], left_fov[1], left_fov[2], left_fov[3]}));
+
+  const float* right_fov = context->display_metrics_.right_fov_lrbt.data();
+  context->right_eye_viewport_transform_ =
+      FovToViewportTransform(FovRadiansToDegrees(
+          gvr_rectf{right_fov[0], right_fov[1], right_fov[2], right_fov[3]}));
+
+  context->next_frame_6dof_pose_ = GvrIdentityMatrix();
+
+  for (int i = 0; i < kControllerCount; ++i) {
+    context->next_frame_controller_pose_[i] = GvrIdentityMatrix();
+  }
+
+  // Check the system property to force 6DoF when requested 3DoF.
+  char prop_buffer[PROP_VALUE_MAX];
+  if (__system_property_get(kForce6DofProp, prop_buffer) &&
+      (!strncasecmp("1", prop_buffer, PROP_VALUE_MAX) ||
+       !strncasecmp("true", prop_buffer, PROP_VALUE_MAX))) {
+    context->force_6dof_ = true;
+  }
+
+  return context.release();
+}
+
+gvr_version gvr_get_version() {
+  gvr_version version = {};
+  version.major = GVR_SDK_MAJOR_VERSION;
+  version.minor = GVR_SDK_MINOR_VERSION;
+  version.patch = GVR_SDK_PATCH_VERSION;
+  return version;
+}
+
+const char* gvr_get_version_string() { return kVersionString; }
+
+int32_t gvr_get_error(gvr_context* gvr) { return gvr->last_error_; }
+
+int32_t gvr_clear_error(gvr_context* gvr) {
+  int32_t last_error = gvr->last_error_;
+  gvr->last_error_ = GVR_ERROR_NONE;
+  return last_error;
+}
+
+const char* gvr_get_error_string(int32_t error_code) {
+  switch (error_code) {
+    case GVR_ERROR_NONE:
+      return "No error";
+    case GVR_ERROR_CONTROLLER_CREATE_FAILED:
+      return "Creation of GVR controller context failed";
+    case GVR_ERROR_NO_FRAME_AVAILABLE:
+      return "No frame available in swap chain";
+    case GVR_ERROR_INTERNAL:
+      return "Internal error";
+    default:
+      return "(Internal error: unknown error code)";
+  }
+}
+
+const gvr_user_prefs* gvr_get_user_prefs(gvr_context* gvr) {
+  return &gvr->user_prefs_;
+}
+
+int32_t gvr_user_prefs_get_controller_handedness(
+    const gvr_user_prefs* /* user_prefs */) {
+  return GVR_CONTROLLER_RIGHT_HANDED;
+}
+
+gvr_context_::~gvr_context_() {
+  for (gvr_swap_chain* swap_chain : swap_chains_)
+    swap_chain->context = nullptr;
+  if (pose_client_)
+    dvrPoseDestroy(pose_client_);
+}
+
+void gvr_destroy(gvr_context** gvr) {
+  if (!gvr || !(*gvr)) {
+    ALOGW("gvr_destroy: Invalid gvr_context pointer.");
+    return;
+  }
+  delete *gvr;
+  *gvr = nullptr;
+}
+
+void gvr_initialize_gl(gvr_context* /* gvr */) {}
+
+bool gvr_get_async_reprojection_enabled(const gvr_context* /* gvr */) {
+  return true;
+}
+
+void gvr_get_recommended_buffer_viewports(
+    const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list) {
+  gvr_buffer_viewport left(
+      /*buffer_index*/ 0,
+      /*uv*/ {0, .5f, 0, 1}, gvr->left_eye_viewport_transform_, GVR_LEFT_EYE,
+      GVR_EXTERNAL_SURFACE_ID_NONE, GVR_REPROJECTION_FULL);
+
+  gvr_buffer_viewport right(
+      /*buffer_index*/ 0,
+      /*uv*/ {.5f, 1, 0, 1}, gvr->right_eye_viewport_transform_, GVR_RIGHT_EYE,
+      GVR_EXTERNAL_SURFACE_ID_NONE, GVR_REPROJECTION_FULL);
+
+  viewport_list->viewports.resize(2);
+  viewport_list->viewports[0] = left;
+  viewport_list->viewports[1] = right;
+}
+
+void gvr_get_screen_buffer_viewports(const gvr_context* gvr,
+                                     gvr_buffer_viewport_list* viewport_list) {
+  gvr_get_recommended_buffer_viewports(gvr, viewport_list);
+}
+
+gvr_sizei gvr_get_maximum_effective_render_target_size(const gvr_context* gvr) {
+  return gvr_sizei{
+      static_cast<int32_t>(gvr->display_metrics_.distorted_width),
+      static_cast<int32_t>(gvr->display_metrics_.distorted_height)};
+}
+
+gvr_sizei gvr_get_screen_target_size(const gvr_context* gvr) {
+  // DisplayMetrics returns native_width and native_height for the display in
+  // portrait orientation, which our device is never in. Swap the width and
+  // height to account for this.
+  return gvr_sizei{
+      static_cast<int32_t>(gvr->display_metrics_.display_native_height),
+      static_cast<int32_t>(gvr->display_metrics_.display_native_width)};
+}
+
+void gvr_set_surface_size(gvr_context* gvr,
+                          gvr_sizei /* surface_size_pixels */) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_set_surface_size not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+void gvr_distort_to_screen(
+    gvr_context* gvr, int32_t /* texture_id */,
+    const gvr_buffer_viewport_list* /* viewport_list */,
+    gvr_mat4f /* head_space_from_start_space */,
+    gvr_clock_time_point /* target_presentation_time */) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_distort_to_screen not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Viewports and viewport lists
+/////////////////////////////////////////////////////////////////////////////
+
+bool gvr_buffer_viewport::operator==(const gvr_buffer_viewport_& other) const {
+  return buffer_index == other.buffer_index && uv == other.uv &&
+         eye == other.eye && external_surface_id == other.external_surface_id &&
+         reprojection == other.reprojection &&
+         MatricesAlmostEqual(transform, other.transform, 1e-5f);
+}
+
+gvr_buffer_viewport* gvr_buffer_viewport_create(gvr_context* /* gvr */) {
+  return new gvr_buffer_viewport;
+}
+
+void gvr_buffer_viewport_destroy(gvr_buffer_viewport** viewport) {
+  if (viewport) {
+    delete *viewport;
+    *viewport = nullptr;
+  }
+}
+
+gvr_rectf gvr_buffer_viewport_get_source_uv(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->uv;
+}
+
+void gvr_buffer_viewport_set_source_uv(gvr_buffer_viewport* viewport,
+                                       gvr_rectf uv) {
+  viewport->uv = uv;
+}
+
+gvr_rectf gvr_buffer_viewport_get_source_fov(
+    const gvr_buffer_viewport* viewport) {
+  return ViewportTransformToFov(viewport->transform);
+}
+
+void gvr_buffer_viewport_set_source_fov(gvr_buffer_viewport* viewport,
+                                        gvr_rectf fov) {
+  viewport->transform = FovToViewportTransform(fov);
+}
+
+gvr_mat4f gvr_buffer_viewport_get_transform(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->transform;
+}
+
+void gvr_buffer_viewport_set_transform(gvr_buffer_viewport* viewport,
+                                       gvr_mat4f transform) {
+  viewport->transform = transform;
+}
+
+int32_t gvr_buffer_viewport_get_target_eye(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->eye;
+}
+
+void gvr_buffer_viewport_set_target_eye(gvr_buffer_viewport* viewport,
+                                        int32_t index) {
+  viewport->eye = index;
+}
+
+int32_t gvr_buffer_viewport_get_source_buffer_index(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->buffer_index;
+}
+
+void gvr_buffer_viewport_set_source_buffer_index(gvr_buffer_viewport* viewport,
+                                                 int32_t buffer_index) {
+  viewport->buffer_index = buffer_index;
+}
+
+int32_t gvr_buffer_viewport_get_external_surface_id(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->external_surface_id;
+}
+
+void gvr_buffer_viewport_set_external_surface_id(gvr_buffer_viewport* viewport,
+                                                 int32_t external_surface_id) {
+  viewport->external_surface_id = external_surface_id;
+}
+
+int32_t gvr_buffer_viewport_get_reprojection(
+    const gvr_buffer_viewport* viewport) {
+  return viewport->reprojection;
+}
+
+void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport,
+                                          int32_t reprojection) {
+  viewport->reprojection = static_cast<gvr_reprojection>(reprojection);
+}
+
+bool gvr_buffer_viewport_equal(const gvr_buffer_viewport* a,
+                               const gvr_buffer_viewport* b) {
+  return *a == *b;
+}
+
+gvr_buffer_viewport_list* gvr_buffer_viewport_list_create(
+    const gvr_context* /* gvr */) {
+  return new gvr_buffer_viewport_list;
+}
+
+void gvr_buffer_viewport_list_destroy(
+    gvr_buffer_viewport_list** viewport_list) {
+  if (!viewport_list || !(*viewport_list)) {
+    ALOGW("gvr_buffer_viewport_list_destroy: Invalid list pointer.");
+    return;
+  }
+  delete *viewport_list;
+  *viewport_list = nullptr;
+}
+
+size_t gvr_buffer_viewport_list_get_size(
+    const gvr_buffer_viewport_list* viewport_list) {
+  return viewport_list->viewports.size();
+}
+
+void gvr_buffer_viewport_list_get_item(
+    const gvr_buffer_viewport_list* viewport_list, size_t index,
+    gvr_buffer_viewport* viewport) {
+  *viewport = viewport_list->viewports[index];
+}
+
+void gvr_buffer_viewport_list_set_item(gvr_buffer_viewport_list* viewport_list,
+                                       size_t index,
+                                       const gvr_buffer_viewport* viewport) {
+  if (index < viewport_list->viewports.size())
+    viewport_list->viewports[index] = *viewport;
+  else
+    viewport_list->viewports.push_back(*viewport);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Swapchains and frames
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_buffer_spec* gvr_buffer_spec_create(gvr_context* /* gvr */) {
+  return new gvr_buffer_spec;
+}
+
+void gvr_buffer_spec_destroy(gvr_buffer_spec** spec) {
+  if (spec) {
+    delete *spec;
+    *spec = nullptr;
+  }
+}
+
+gvr_sizei gvr_buffer_spec_get_size(const gvr_buffer_spec* spec) {
+  return spec->size;
+}
+
+void gvr_buffer_spec_set_size(gvr_buffer_spec* spec, gvr_sizei size) {
+  spec->size = size;
+}
+
+int32_t gvr_buffer_spec_get_samples(const gvr_buffer_spec* spec) {
+  return spec->msaa_samples;
+}
+
+void gvr_buffer_spec_set_samples(gvr_buffer_spec* spec, int32_t num_samples) {
+  spec->msaa_samples = num_samples;
+}
+
+void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec,
+                                      int32_t color_format) {
+  spec->color_format = color_format;
+}
+
+void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec,
+                                              int32_t depth_stencil_format) {
+  spec->depth_stencil_format = depth_stencil_format;
+}
+
+void gvr_buffer_spec_set_z_order(gvr_buffer_spec* spec, int z_order) {
+  spec->z_order = z_order;
+}
+
+void gvr_buffer_spec_set_visibility(gvr_buffer_spec* spec,
+                                    int32_t visibility) {
+  spec->initially_visible = (visibility != GVR_INVISIBLE);
+}
+
+void gvr_buffer_spec_set_blur_behind(gvr_buffer_spec* spec,
+                                     int32_t blur_behind) {
+  spec->blur_behind = (blur_behind != GVR_BLUR_BEHIND_FALSE);
+}
+
+void gvr_buffer::SetDefaults() {
+  spec = gvr_buffer_spec();
+  frame_buffer = 0;
+  color_render_buffer = 0;
+  depth_stencil_render_buffer = 0;
+  requested_size = {-1, -1};
+}
+
+gvr_buffer::gvr_buffer() { SetDefaults(); }
+
+gvr_buffer::gvr_buffer(gvr_context* gvr, const gvr_buffer_spec& spec_in,
+                       GLuint texture_id, GLenum texture_target) {
+  SetDefaults();
+  spec = spec_in;
+
+  glGetError();  // Clear error state
+  glGenFramebuffers(1, &frame_buffer);
+  glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);
+
+  if (texture_id == 0) {
+    GLenum gl_color_format;
+    if (!GetGlColorFormat(spec.color_format, &gl_color_format)) {
+      ALOGE("Unknown color format: %d", spec.color_format);
+      gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+      FreeGl();
+      return;
+    }
+
+    glGenRenderbuffers(1, &color_render_buffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, color_render_buffer);
+    if (spec.msaa_samples < 2) {
+      glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format, spec.size.width,
+                            spec.size.height);
+    } else {
+      glRenderbufferStorageMultisample(GL_RENDERBUFFER, spec.msaa_samples,
+                                       gl_color_format, spec.size.width,
+                                       spec.size.height);
+    }
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                              GL_RENDERBUFFER, color_render_buffer);
+  } else {
+    if (spec.msaa_samples < 2) {
+      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                             texture_target, texture_id, 0);
+    } else {
+      glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                           texture_target, texture_id, 0,
+                                           spec.msaa_samples);
+    }
+  }
+
+  if (spec.depth_stencil_format != GVR_DEPTH_STENCIL_FORMAT_NONE) {
+    GLenum gl_depth_format;
+    if (!GetGlDepthFormat(spec.depth_stencil_format, &gl_depth_format)) {
+      ALOGE("Unknown depth/stencil format: %d", spec.depth_stencil_format);
+      gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+      FreeGl();
+      return;
+    }
+
+    glGenRenderbuffers(1, &depth_stencil_render_buffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_render_buffer);
+    if (spec.msaa_samples < 2) {
+      glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format, spec.size.width,
+                            spec.size.height);
+    } else {
+      glRenderbufferStorageMultisample(GL_RENDERBUFFER, spec.msaa_samples,
+                                       gl_depth_format, spec.size.width,
+                                       spec.size.height);
+    }
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                              GL_RENDERBUFFER, depth_stencil_render_buffer);
+  }
+
+  GLenum gl_error = glGetError();
+  if (gl_error != GL_NO_ERROR) {
+    ALOGE("GL error after creating framebuffer: %d", gl_error);
+    gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+    FreeGl();
+    return;
+  }
+
+  GLenum framebuffer_complete_result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+  if (framebuffer_complete_result != GL_FRAMEBUFFER_COMPLETE) {
+    ALOGE("Framebuffer setup failed. glCheckFramebufferStatus returned %d",
+          framebuffer_complete_result);
+    gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+    FreeGl();
+    return;
+  }
+}
+
+void gvr_buffer::FreeGl() {
+  if (frame_buffer != 0) {
+    glDeleteFramebuffers(1, &frame_buffer);
+    frame_buffer = 0;
+  }
+  if (color_render_buffer != 0) {
+    glDeleteRenderbuffers(1, &color_render_buffer);
+    color_render_buffer = 0;
+  }
+  if (depth_stencil_render_buffer != 0) {
+    glDeleteRenderbuffers(1, &depth_stencil_render_buffer);
+    depth_stencil_render_buffer = 0;
+  }
+}
+
+gvr_buffer::~gvr_buffer() { FreeGl(); }
+
+gvr_buffer::gvr_buffer(gvr_buffer&& other) {
+  spec = other.spec;
+  frame_buffer = other.frame_buffer;
+  color_render_buffer = other.color_render_buffer;
+  depth_stencil_render_buffer = other.depth_stencil_render_buffer;
+  requested_size = other.requested_size;
+  other.SetDefaults();
+}
+
+gvr_buffer& gvr_buffer::operator=(gvr_buffer&& other) {
+  if (this == &other)
+    return *this;
+  spec = other.spec;
+  frame_buffer = other.frame_buffer;
+  color_render_buffer = other.color_render_buffer;
+  depth_stencil_render_buffer = other.depth_stencil_render_buffer;
+  requested_size = other.requested_size;
+  other.SetDefaults();
+  return *this;
+}
+
+gvr_swap_chain* gvr_swap_chain_create(gvr_context* gvr,
+                                      const gvr_buffer_spec** buffers,
+                                      int32_t count) {
+  if (count == 0) {
+    ALOGE("At least one buffer must be requested");
+    gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+    return nullptr;
+  }
+
+  // We only support one buffer, but it's common for gvr apps to use more than
+  // one. Print an error to the log if the app requests more than one buffer,
+  // but continue on. We'll only render the first buffer in that case.
+  if (count > 1) {
+    ALOGE(
+        "Only one buffer is supported but the app requested %d."
+        " Only the first buffer will be rendered.",
+        count);
+  }
+
+  std::unique_ptr<gvr_swap_chain> swap_chain(new gvr_swap_chain(gvr));
+
+  // The first buffer gets a DvrGraphicsContext, which contains the surface we
+  // pass to displayd for rendering.
+  swap_chain->buffers_.push_back(gvr_buffer());
+  swap_chain->buffers_.back().spec = *buffers[0];
+  if (!CreateDvrGraphicsContextAndGvrBuffer(swap_chain.get()))
+    return nullptr;
+
+  // The rest of the buffers, which we don't render for now, get color render
+  // buffers.
+  for (int i = 1; i < count; ++i) {
+    swap_chain->buffers_.push_back(
+        gvr_buffer(gvr, *buffers[i], 0, GL_TEXTURE_2D));
+    if (swap_chain->buffers_.back().frame_buffer == 0)
+      return nullptr;
+  }
+
+  gvr->swap_chains_.push_back(swap_chain.get());
+  return swap_chain.release();
+}
+
+gvr_swap_chain_::~gvr_swap_chain_() {
+  if (context) {
+    auto iter = std::find(std::begin(context->swap_chains_),
+                          std::end(context->swap_chains_), this);
+    if (iter != context->swap_chains_.end())
+      context->swap_chains_.erase(iter);
+  }
+  buffers_.clear();
+  if (graphics_context_ != nullptr)
+    dvrGraphicsContextDestroy(graphics_context_);
+}
+
+void gvr_swap_chain_destroy(gvr_swap_chain** swap_chain) {
+  if (!swap_chain || !(*swap_chain)) {
+    ALOGW("gvr_swap_chain_destroy: Invalid swap chain pointer.");
+    return;
+  }
+  delete *swap_chain;
+  *swap_chain = nullptr;
+}
+
+int32_t gvr_swap_chain_get_buffer_count(const gvr_swap_chain* swap_chain) {
+  return swap_chain ? static_cast<int32_t>(swap_chain->buffers_.size()) : 0;
+}
+
+gvr_sizei gvr_swap_chain_get_buffer_size(gvr_swap_chain* swap_chain,
+                                         int32_t index) {
+  if (!VerifyBufferIndex("gvr_swap_chain_get_buffer_size", swap_chain, index))
+    return gvr_sizei{0, 0};
+
+  gvr_buffer& buf = swap_chain->buffers_[index];
+  if (buf.requested_size != gvr_sizei{-1, -1})
+    return buf.requested_size;
+  else
+    return buf.spec.size;
+}
+
+void gvr_swap_chain_resize_buffer(gvr_swap_chain* swap_chain, int32_t index,
+                                  gvr_sizei size) {
+  if (!VerifyBufferIndex("gvr_swap_chain_resize_buffer", swap_chain, index))
+    return;
+
+  gvr_buffer& buf = swap_chain->buffers_[index];
+  if (size != buf.spec.size)
+    buf.requested_size = size;
+  else
+    buf.requested_size = {-1, -1};
+}
+
+gvr_frame* gvr_swap_chain_acquire_frame(gvr_swap_chain* swap_chain) {
+  if (!swap_chain)
+    return nullptr;
+
+  if (swap_chain->frame_acquired_) {
+    gvr_set_error(swap_chain->context, GVR_ERROR_NO_FRAME_AVAILABLE);
+    return nullptr;
+  }
+
+  // Resize buffers if necessary
+  for (int i = 0; i < static_cast<int>(swap_chain->buffers_.size()); ++i) {
+    gvr_buffer& buf = swap_chain->buffers_[i];
+    if (buf.requested_size != gvr_sizei{-1, -1}) {
+      if (!SwapChainResizeBuffer(swap_chain, i))
+        return nullptr;
+    }
+  }
+
+  // Only call gvr_wait_next_frame() if the app didn't call it already.
+  if (!swap_chain->wait_next_frame_called_by_app_)
+    WaitNextFrame(swap_chain, 0, nullptr, /*called_by_app*/ false);
+
+  int ret = dvrBeginRenderFrame(swap_chain->graphics_context_);
+  if (ret < 0) {
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return nullptr;
+  }
+
+  swap_chain->frame_acquired_ = true;
+  return GetFrameFromSwapChain(swap_chain);
+}
+
+void gvr_frame_bind_buffer(gvr_frame* frame, int32_t index) {
+  gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+  if (!VerifyBufferIndex("gvr_frame_bind_buffer", swap_chain, index))
+    return;
+  glBindFramebuffer(GL_FRAMEBUFFER, swap_chain->buffers_[index].frame_buffer);
+}
+
+void gvr_frame_unbind(gvr_frame* /* frame */) {
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+gvr_sizei gvr_frame_get_buffer_size(const gvr_frame* frame, int32_t index) {
+  const gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+  if (!VerifyBufferIndex("gvr_frame_get_buffer_size", swap_chain, index))
+    return gvr_sizei{0, 0};
+  return swap_chain->buffers_[index].spec.size;
+}
+
+int32_t gvr_frame_get_framebuffer_object(const gvr_frame* frame,
+                                         int32_t index) {
+  const gvr_swap_chain* swap_chain = GetSwapChainForFrame(frame);
+  if (!VerifyBufferIndex("gvr_frame_get_framebuffer_object", swap_chain, index))
+    return 0;
+  return swap_chain->buffers_[index].frame_buffer;
+}
+
+void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list,
+                      gvr_mat4f head_space_from_start_space) {
+  if (!frame)
+    return;
+
+  gvr_swap_chain* swap_chain = GetSwapChainForFrame(*frame);
+
+  if (!swap_chain->frame_acquired_) {
+    ALOGE("Frame was never acquired before being submitted");
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return;
+  }
+
+  *frame = nullptr;
+  swap_chain->frame_acquired_ = false;
+
+  // Currently, support for arbitrary buffer viewport configs is very limited.
+  // We assume that the first two viewports have to be the recommended color
+  // buffer viewports, followed by pairs of external external buffer viewports
+  // for video rendering.
+  gvr_buffer_viewport_list supported_viewports;
+  gvr_get_recommended_buffer_viewports(swap_chain->context,
+                                       &supported_viewports);
+  for (size_t i = 0; i < supported_viewports.viewports.size(); ++i) {
+    if (i >= list->viewports.size() ||
+        supported_viewports.viewports[i] != list->viewports[i]) {
+      ALOGE("Custom viewport configurations are not fully supported.");
+      gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+      return;
+    }
+  }
+
+  for (size_t i = supported_viewports.viewports.size();
+       i < list->viewports.size(); ++i) {
+    int32_t external_surface_id = list->viewports[i].external_surface_id;
+    // Ignore additional custom buffer viewport for now, only those buffer
+    // viewports backed by external surfaces are supported.
+    // TODO(b/31442094, b/31771861, 28954457) Add full GVR buffer viewport
+    // support.
+    if (external_surface_id == GVR_EXTERNAL_SURFACE_ID_NONE)
+      continue;
+
+    auto surface_it = swap_chain->external_surfaces_.find(external_surface_id);
+    if (surface_it == swap_chain->external_surfaces_.end()) {
+      ALOGE("Cannot find external_surface by id: %d.", external_surface_id);
+      gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+      return;
+    }
+
+    // Pass the transfrom matrix of video mesh to displayd.
+    dvrGraphicsVideoMeshSurfacePresent(
+        swap_chain->graphics_context_, surface_it->second->video_surface,
+        list->viewports[i].eye,
+        GvrToEigenMatrix(list->viewports[i].transform).data());
+  }
+
+  float32x4_t pose_orientation, pose_translation;
+  GvrToDvrPose(head_space_from_start_space, &pose_orientation,
+               &pose_translation);
+  int ret = dvrSetEdsPose(swap_chain->graphics_context_, pose_orientation,
+                          pose_translation);
+  if (ret < 0)
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+
+  ret = dvrPresent(swap_chain->graphics_context_);
+  if (ret < 0) {
+    gvr_set_error(swap_chain->context, GVR_ERROR_INTERNAL);
+    return;
+  }
+}
+
+void gvr_bind_default_framebuffer(gvr_context* /* gvr */) {
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head tracking
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_clock_time_point gvr_get_time_point_now() {
+  return gvr_clock_time_point{GetSystemClockNs()};
+}
+
+gvr_mat4f gvr_get_head_space_from_start_space_rotation(
+    const gvr_context* gvr, const gvr_clock_time_point /* time */) {
+  // TODO(steventhomas): Implement prediction according to the supplied time
+  // value.
+  return gvr->force_6dof_ ? gvr->next_frame_6dof_pose_
+                          : Gvr6dofTo3dof(gvr->next_frame_6dof_pose_);
+}
+
+gvr_mat4f gvr_apply_neck_model(const gvr_context* /* gvr */,
+                               gvr_mat4f head_space_from_start_space_rotation,
+                               float /* factor */) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_apply_neck_model not implemented.");
+  return head_space_from_start_space_rotation;
+}
+
+// This is used to turn off sensors to save power. Not relevant for our all in
+// one device.
+void gvr_pause_tracking(gvr_context* /* gvr */) {}
+
+// This is used to turn on sensors. Not relevant for our all in one device.
+void gvr_resume_tracking(gvr_context* /* gvr */) {}
+
+void gvr_reset_tracking(gvr_context* gvr) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_reset_tracking not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+void gvr_recenter_tracking(gvr_context* gvr) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_recenter_tracking not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Head mounted display
+/////////////////////////////////////////////////////////////////////////////
+
+bool gvr_set_default_viewer_profile(gvr_context* gvr,
+                                    const char* /* viewer_profile_uri */) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_set_default_viewer_profile not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+  return false;
+}
+
+void gvr_refresh_viewer_profile(gvr_context* /* gvr */) {}
+
+const char* gvr_get_viewer_vendor(const gvr_context* /* gvr */) {
+  return kViewerVendor;
+}
+
+const char* gvr_get_viewer_model(const gvr_context* /* gvr */) {
+  return kViewerModel;
+}
+
+int32_t gvr_get_viewer_type(const gvr_context* /* gvr */) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  // In this case, we will probably need to define a new viewer type that
+  // has 6DoF support.
+  return GVR_VIEWER_TYPE_DAYDREAM;
+}
+
+gvr_mat4f gvr_get_eye_from_head_matrix(const gvr_context* gvr,
+                                       const int32_t eye) {
+  float eye_mult = eye == GVR_LEFT_EYE ? 1 : -1;
+  return GvrTranslationMatrix(
+      .5f * eye_mult * gvr->display_metrics_.inter_lens_distance_m, 0, 0);
+}
+
+gvr_recti gvr_get_window_bounds(const gvr_context* gvr) {
+  // Our app windows are always full screen
+  gvr_sizei screen_size = gvr_get_screen_target_size(gvr);
+  return gvr_recti{0, screen_size.width, 0, screen_size.height};
+}
+
+void gvr_compute_distorted_point(const gvr_context* /* gvr */,
+                                 const int32_t /* eye */,
+                                 const gvr_vec2f /* uv_in */,
+                                 gvr_vec2f /* uv_out */[3]) {
+  // TODO(leandrogracia): this needs to be properly implemented.
+  ALOGE("gvr_compute_distorted_point not implemented.");
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GVR API extension (from gvr_ext.h)
+/////////////////////////////////////////////////////////////////////////////
+
+gvr_frame_schedule* gvr_frame_schedule_create() {
+  return new gvr_frame_schedule;
+}
+
+void gvr_frame_schedule_destroy(gvr_frame_schedule** schedule) {
+  if (!schedule || !(*schedule)) {
+    ALOGW("gvr_frame_schedule_destroy: Invalid frame schedule pointer.");
+    return;
+  }
+  delete *schedule;
+  *schedule = nullptr;
+}
+
+uint32_t gvr_frame_schedule_get_vsync_count(gvr_frame_schedule* schedule) {
+  return schedule->vsync_count;
+}
+
+gvr_clock_time_point gvr_frame_schedule_get_scheduled_finish(
+    gvr_frame_schedule* schedule) {
+  return schedule->scheduled_finish;
+}
+
+void gvr_wait_next_frame(gvr_swap_chain* swap_chain, int64_t start_delay_nanos,
+                         gvr_frame_schedule* out_next_frame_schedule) {
+  WaitNextFrame(swap_chain, start_delay_nanos, out_next_frame_schedule,
+                /*called_by_app*/ true);
+}
+
+gvr_mat4f gvr_get_6dof_head_pose_in_start_space(gvr_context* gvr,
+                                                uint32_t vsync_count) {
+  DvrPoseAsync pose;
+  int ret = dvrPoseGet(gvr->pose_client_, vsync_count, &pose);
+  if (ret < 0) {
+    ALOGW("dvrPoseGet failed: %d", ret);
+    gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+    return GvrIdentityMatrix();
+  }
+
+  return PosefToGvrMatrix(ToPosef(pose));
+}
+
+gvr_mat4f gvr_get_head_space_from_start_space_pose(
+    gvr_context* gvr, const gvr_clock_time_point /* time */) {
+  // TODO(leandrogracia): implement prediction based on the provided time.
+  // We need to do the same for the 3dof version too.
+  return gvr->next_frame_6dof_pose_;
+}
+
+void gvr_swap_chain_set_z_order(const gvr_swap_chain* swap_chain, int z_order) {
+  dvrGraphicsSurfaceSetZOrder(swap_chain->graphics_context_, z_order);
+}
+
+bool gvr_experimental_is_feature_supported(const gvr_context* /* gvr */,
+                                           int32_t feature) {
+  switch (feature) {
+    case GVR_ASYNC_REPROJECTION:
+    case GVR_6DOF_HEAD_POSE:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool gvr_experimental_register_perf_event_callback(
+    gvr_context* gvr, int* /* out_handle */, void* /* user_data */,
+    void (* /* event_callback */)(void*, int, float)) {
+  ALOGE("gvr_experimental_register_perf_event_callback not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+  return false;
+}
+
+bool gvr_experimental_unregister_perf_event_callback(gvr_context* gvr,
+                                                     int /* handle */) {
+  ALOGE("gvr_experimental_unregister_perf_event_callback not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+  return false;
+}
+
+const gvr_analytics* gvr_get_analytics(gvr_context* gvr) {
+  ALOGE("gvr_get_analytics not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+  return nullptr;
+}
+
+const gvr_analytics_sample* gvr_analytics_create_sample(
+    const gvr_analytics* analytics) {
+  ALOGE("gvr_analytics_create_sample not implemented.");
+  return nullptr;
+}
+
+const char* gvr_analytics_sample_get_buffer(const gvr_analytics_sample* sample) {
+  ALOGE("gvr_analytics_sample_get_buffer not implemented.");
+  return nullptr;
+}
+
+size_t gvr_analytics_sample_get_buffer_length(
+    const gvr_analytics_sample* sample) {
+  ALOGE("gvr_analytics_sample_get_buffer_length not implemented.");
+  return 0;
+}
+
+void gvr_analytics_destroy_sample(const gvr_analytics_sample** sample) {
+  ALOGE("gvr_analytics_destroy_sample not implemented.");
+}
+
+bool gvr_user_prefs_get_performance_monitoring_enabled(
+    const gvr_user_prefs* /* user_prefs */) {
+  ALOGW("gvr_user_prefs_get_performance_monitoring_enabled not implemented.");
+  return false;
+}
+
+void gvr_enable_context_sharing(gvr_context* gvr,
+                                gvr_egl_context_listener /* handler */,
+                                void* /* user_data */) {
+  ALOGW("gvr_enable_context_sharing not implemented.");
+  gvr_set_error(gvr, GVR_ERROR_INTERNAL);
+}
+
+gvr_mat4f gvr_get_start_space_from_controller_space_pose(
+    gvr_context* gvr, int controller_id,
+    const gvr_clock_time_point /* time */) {
+  if (controller_id < 0 || controller_id >= kControllerCount) {
+    return GvrIdentityMatrix();
+  }
+
+  // TODO(leandrogracia): implement prediction based on the provided time.
+  // We need to do the same for the 3dof version too.
+  return gvr->next_frame_controller_pose_[controller_id];
+}
+
+gvr_external_surface* gvr_external_surface_create(gvr_context* context) {
+  // A |gvr_external_surface| is bound to a DVR Graphics context at the
+  // moment, which means we need an |gvr_swap_chain| created prior to the call
+  // of |gvr_external_surface_create|. Check whether the current GVR context
+  // has |gvr_swap_chain| created. Fail if there is no swap chain created
+  // already.
+  if (context->swap_chains_.empty()) {
+    ALOGE("gvr_external_surface_create: No swapchain has been created yet.");
+    return nullptr;
+  }
+
+  // In case there are multiple swap chains in the context, the first is
+  // implicitly chosen. Actually, this should not happen as current scanline
+  // racing based GVR implementation only supports single swap chain per GVR
+  // context.
+  if (context->swap_chains_.size() > 1) {
+    ALOGW("gvr_external_surface_create: Multiple swap chains detected. "
+          "Choosing the first one but this may yield unexpected results.");
+  }
+  gvr_swap_chain* swap_chain = context->swap_chains_[0];
+  DvrVideoMeshSurface* video_surface = dvrGraphicsVideoMeshSurfaceCreate(
+      swap_chain->graphics_context_);
+
+  if (video_surface == nullptr) {
+    ALOGE("gvr_external_surface_create: Failed to create video mesh surface.");
+    return nullptr;
+  }
+
+  gvr_external_surface* surface = new gvr_external_surface;
+  surface->id = swap_chain->next_external_surface_id_++;
+  surface->swap_chain = swap_chain;
+  surface->video_surface = video_surface;
+
+  // Insert the surface into a lookup table in swap_chain. This will be
+  // needed to by the external_surface_id in |gvr_buffer_viewport|.
+  swap_chain->external_surfaces_.insert({surface->id, surface});
+  return surface;
+}
+
+void gvr_external_surface_destroy(gvr_external_surface** surface) {
+  if (!surface || !(*surface)) {
+    ALOGW("gvr_external_surface_destroy: Invalid external surface pointer.");
+    return;
+  }
+
+  (*surface)->swap_chain->external_surfaces_.erase((*surface)->id);
+  if ((*surface)->video_surface != nullptr) {
+    dvrGraphicsVideoMeshSurfaceDestroy((*surface)->video_surface);
+  }
+
+  delete *surface;
+  *surface = nullptr;
+}
+
+void* gvr_external_surface_get_surface(const gvr_external_surface* surface) {
+  CHECK(surface->swap_chain != nullptr &&
+        surface->swap_chain->context != nullptr &&
+        surface->swap_chain->context->jni_env_ != nullptr)
+      << "gvr_external_surface_get_surface: Surface must be constructed within "
+      << "a JNIEnv. Check |gvr_create| call.";
+
+  CHECK(surface->video_surface != nullptr)
+      << "gvr_external_surface_get_surface: Invalid surface.";
+
+  std::shared_ptr<android::dvr::ProducerQueue> producer_queue =
+      surface->video_surface->client->GetProducerQueue();
+  std::shared_ptr<android::dvr::BufferHubQueueCore> core =
+      android::dvr::BufferHubQueueCore::Create(producer_queue);
+
+  return android_view_Surface_createFromIGraphicBufferProducer(
+      surface->swap_chain->context->jni_env_,
+      new android::dvr::BufferHubQueueProducer(core));
+}
+
+int32_t gvr_external_surface_get_surface_id(
+    const gvr_external_surface* surface) {
+  return surface->id;
+}
diff --git a/libs/vr/libgvr/shim_gvr_controller.cpp b/libs/vr/libgvr/shim_gvr_controller.cpp
new file mode 100644
index 0000000..54bc270
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr_controller.cpp
@@ -0,0 +1,168 @@
+#define LOG_TAG "libgvr_controller_shim"
+
+#include <cutils/log.h>
+#include <vr/gvr/capi/include/gvr_controller.h>
+#include <vr/gvr/capi/include/gvr_types.h>
+
+gvr_controller_context* gvr_controller_create_and_init(int32_t options,
+                                                       gvr_context* context) {
+  ALOGE("gvr_controller_create_and_init not implemented.");
+  return nullptr;
+}
+
+gvr_controller_context* gvr_controller_create_and_init_android(
+    JNIEnv* env, jobject android_context, jobject class_loader, int32_t options,
+    gvr_context* context) {
+  ALOGE("gvr_controller_create_and_init_android not implemented.");
+  return nullptr;
+}
+
+void gvr_controller_destroy(gvr_controller_context** api) {
+  ALOGE("gvr_controller_destroy not implemented.");
+}
+
+gvr_controller_state* gvr_controller_state_create() {
+  ALOGE("gvr_controller_state_create not implemented.");
+  return nullptr;
+}
+
+void gvr_controller_state_destroy(gvr_controller_state** state) {
+  ALOGE("gvr_controller_state_destroy not implemented.");
+}
+
+void gvr_controller_state_update(gvr_controller_context* api, int32_t flags,
+                                 gvr_controller_state* out_state) {
+  ALOGE("gvr_controller_state_update not implemented.");
+}
+
+int64_t gvr_controller_state_get_last_button_timestamp(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_last_button_timestamp not implemented.");
+  return 0;
+}
+
+bool gvr_controller_state_get_button_state(const gvr_controller_state* state,
+                                           int32_t button) {
+  ALOGE("gvr_controller_state_get_button_state not implemented.");
+  return false;
+}
+
+bool gvr_controller_state_get_button_down(const gvr_controller_state* state,
+                                          int32_t button) {
+  ALOGE("gvr_controller_state_get_button_down not implemented.");
+  return false;
+}
+
+bool gvr_controller_state_get_button_up(const gvr_controller_state* state,
+                                        int32_t button) {
+  ALOGE("gvr_controller_state_get_button_up not implemented.");
+  return false;
+}
+
+bool gvr_controller_state_is_touching(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_is_touching not implemented.");
+  return false;
+}
+
+gvr_vec2f gvr_controller_state_get_touch_pos(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_touch_pos not implemented.");
+  return {0.0f, 0.0f};
+}
+
+bool gvr_controller_state_get_touch_down(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_touch_down not implemented.");
+  return false;
+}
+
+bool gvr_controller_state_get_touch_up(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_touch_up not implemented.");
+  return false;
+}
+
+int64_t gvr_controller_state_get_last_touch_timestamp(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_last_touch_timestamp not implemented.");
+  return 0;
+}
+
+gvr_quatf gvr_controller_state_get_orientation(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_orientation not implemented.");
+  return {0.0f, 0.0f, 0.0f, 0.0f};
+}
+
+int64_t gvr_controller_state_get_last_orientation_timestamp(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_last_orientation_timestamp not implemented.");
+  return 0;
+}
+
+const char* gvr_controller_api_status_to_string(int32_t status) {
+  ALOGE("gvr_controller_api_status_to_string not implemented.");
+  return nullptr;
+}
+
+const char* gvr_controller_connection_state_to_string(int32_t state) {
+  ALOGE("gvr_controller_connection_state_to_string not implemented.");
+  return nullptr;
+}
+
+const char* gvr_controller_button_to_string(int32_t button) {
+  ALOGE("gvr_controller_button_to_string not implemented.");
+  return nullptr;
+}
+
+int32_t gvr_controller_get_default_options() {
+  ALOGE("gvr_controller_get_default_options not implemented.");
+  return 0;
+}
+
+void gvr_controller_pause(gvr_controller_context* api) {
+  ALOGE("gvr_controller_pause not implemented.");
+}
+
+void gvr_controller_resume(gvr_controller_context* api) {
+  ALOGE("gvr_controller_resume not implemented.");
+}
+
+int32_t gvr_controller_state_get_api_status(const gvr_controller_state* state) {
+  return GVR_CONTROLLER_API_OK;
+}
+
+int32_t gvr_controller_state_get_connection_state(
+    const gvr_controller_state* state) {
+  return GVR_CONTROLLER_CONNECTED;
+}
+
+gvr_vec3f gvr_controller_state_get_gyro(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_gyro not implemented.");
+  return {0.0, 0.0, 0.0};
+}
+
+gvr_vec3f gvr_controller_state_get_accel(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_accel not implemented.");
+  return {0.0, 0.0, 0.0};
+}
+
+int64_t gvr_controller_state_get_last_gyro_timestamp(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_last_gyro_timestamp not implemented.");
+  return 0;
+}
+
+int64_t gvr_controller_state_get_last_accel_timestamp(
+    const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_last_accel_timestamp not implemented.");
+  return 0;
+}
+
+bool gvr_controller_state_get_recentered(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_recentered not implemented.");
+  return false;
+}
+
+bool gvr_controller_state_get_recentering(const gvr_controller_state* state) {
+  ALOGE("gvr_controller_state_get_recentering not implemented.");
+  return false;
+}
diff --git a/libs/vr/libgvr/shim_gvr_private.cpp b/libs/vr/libgvr/shim_gvr_private.cpp
new file mode 100644
index 0000000..6ab6971
--- /dev/null
+++ b/libs/vr/libgvr/shim_gvr_private.cpp
@@ -0,0 +1,234 @@
+#define LOG_TAG "libgvr_shim_private"
+
+#include <cutils/log.h>
+#include <private/dvr/display_rpc.h>
+#include <private/dvr/internal_types.h>
+#include <vr/gvr/capi/include/gvr.h>
+#include <vr/gvr/capi/src/gvr_private.h>
+
+#include <pdx/rpc/remote_method.h>
+#include "deviceparams/CardboardDevice.nolite.pb.h"
+
+bool gvr_set_async_reprojection_enabled(gvr_context* /* gvr */,
+                                        bool /* enabled */) {
+  return true;
+}
+
+void gvr_on_surface_created_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_render_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_on_pause_reprojection_thread(gvr_context* /* gvr */) {}
+
+void gvr_update_surface_reprojection_thread(
+    gvr_context* /* gvr */, int32_t /* surface_id */, int32_t /* texture_id */,
+    gvr_clock_time_point /* timestamp */, gvr_mat4f /* surface_transform */) {
+  ALOGE("gvr_update_surface_reprojection_thread not implemented");
+}
+
+void gvr_remove_all_surfaces_reprojection_thread(gvr_context* /* gvr */) {
+  ALOGE("gvr_remove_all_surfaces_reprojection_thread not implemented");
+}
+
+void gvr_reconnect_sensors(gvr_context* /* gvr */) {
+  ALOGE("gvr_reconnect_sensors not implemented");
+}
+
+bool gvr_set_viewer_params(gvr_context* gvr,
+                           const void* serialized_viewer_params,
+                           size_t serialized_viewer_params_size_bytes) {
+  std::string serialized_device_params_string(
+      reinterpret_cast<const char*>(serialized_viewer_params),
+      serialized_viewer_params_size_bytes);
+  std::unique_ptr<proto::DeviceParams> device_params(new proto::DeviceParams);
+  if (!device_params->ParseFromString(serialized_device_params_string)) {
+    LOG(ERROR) << "Invalid serialized Cardboard DeviceParams";
+    return false;
+  }
+
+  android::dvr::ViewerParams viewer_params;
+
+  viewer_params.screen_to_lens_distance =
+      device_params->screen_to_lens_distance();
+  viewer_params.inter_lens_distance = device_params->inter_lens_distance();
+  for (int i = 0; i < device_params->left_eye_field_of_view_angles_size();
+       ++i) {
+    viewer_params.left_eye_field_of_view_angles.push_back(
+        device_params->left_eye_field_of_view_angles(i));
+  }
+
+  viewer_params.vertical_alignment =
+      static_cast<android::dvr::ViewerParams::VerticalAlignmentType>(
+          device_params->vertical_alignment());
+  viewer_params.tray_to_lens_distance = device_params->tray_to_lens_distance();
+
+  // TODO(hendrikw) Leave the g and b coefficients empty until we support
+  // chromatic aberration correction.
+  for (int i = 0; i < device_params->distortion_coefficients_size(); ++i) {
+    viewer_params.distortion_coefficients_r.push_back(
+        device_params->distortion_coefficients(i));
+  }
+
+  viewer_params.screen_center_to_lens_distance =
+      viewer_params.inter_lens_distance / 2.0;
+  if (device_params->has_internal()) {
+    for (int i = 0; i < device_params->internal().eye_orientations_size();
+         ++i) {
+      viewer_params.eye_orientations.push_back(
+          static_cast<android::dvr::ViewerParams::EyeOrientation>(
+              device_params->internal().eye_orientations(i)));
+    }
+
+    if (device_params->internal().has_screen_center_to_lens_distance())
+      viewer_params.screen_center_to_lens_distance =
+          device_params->internal().screen_center_to_lens_distance();
+  }
+
+  if (device_params->has_daydream_internal()) {
+    viewer_params.daydream_internal.version =
+        device_params->daydream_internal().version();
+    for (int i = 0;
+         i < device_params->daydream_internal().alignment_markers_size(); ++i) {
+      viewer_params.daydream_internal.alignment_markers.push_back(
+          {device_params->daydream_internal().alignment_markers(i).horizontal(),
+           device_params->daydream_internal().alignment_markers(i).vertical()});
+    }
+  }
+
+  gvr->display_client_->SetViewerParams(viewer_params);
+  return true;
+}
+
+void gvr_set_lens_offset(gvr_context* /* gvr */, gvr_vec2f /* offset */) {
+  ALOGE("gvr_set_lens_offset not implemented");
+}
+
+void gvr_set_display_metrics(gvr_context* /* gvr */,
+                             gvr_sizei /* size_pixels */,
+                             gvr_vec2f /* meters_per_pixel */,
+                             float /* border_size_meters */) {
+  ALOGE("gvr_set_display_metrics not implemented");
+}
+
+void gvr_set_display_output_rotation(gvr_context* /* gvr */,
+                                     int /* display_output_rotation */) {
+  ALOGE("gvr_set_display_output_rotation not implemented");
+}
+
+float gvr_get_border_size_meters(const gvr_context* /* gvr */) {
+  ALOGE("gvr_get_border_size_meters not implemented");
+  return 0.0f;
+}
+
+bool gvr_check_surface_size_changed(gvr_context* /* gvr */) { return false; }
+
+gvr_sizei gvr_get_surface_size(const gvr_context* /* gvr */) {
+  ALOGE("gvr_get_surface_size not implemented");
+  return {0, 0};
+}
+
+void gvr_set_back_gesture_event_handler(gvr_context* /* gvr */,
+                                        event_handler /* handler */,
+                                        void* /* user_data */) {
+  ALOGE("gvr_set_back_gesture_event_handler not implemented");
+}
+
+gvr_tracker_state* gvr_pause_tracking_get_state(gvr_context* /* gvr */) {
+  ALOGE("gvr_pause_tracking_get_state not implemented");
+  return nullptr;
+}
+
+void gvr_resume_tracking_set_state(gvr_context* /* gvr */,
+                                   gvr_tracker_state* /* tracker_state */) {
+  ALOGE("gvr_resume_tracking_set_state not implemented");
+}
+
+void gvr_set_ignore_manual_tracker_pause_resume(gvr_context* /* gvr */,
+                                                bool /* should_ignore */) {
+  ALOGE("gvr_set_ignore_manual_tracker_pause_resume not implemented");
+}
+
+gvr_tracker_state* gvr_tracker_state_create(
+    const char* /* tracker_state_buffer */, size_t /* buf_size */) {
+  ALOGE("gvr_tracker_state_create not implemented");
+  return nullptr;
+}
+
+size_t gvr_tracker_state_get_buffer_size(
+    gvr_tracker_state* /* tracker_state */) {
+  ALOGE("gvr_tracker_state_get_buffer_size not implemented");
+  return 0;
+}
+
+const char* gvr_tracker_state_get_buffer(
+    gvr_tracker_state* /* tracker_state */) {
+  ALOGE("gvr_tracker_state_get_buffer not implemented");
+  return nullptr;
+}
+
+void gvr_tracker_state_destroy(gvr_tracker_state** /* tracker_state */) {
+  ALOGE("gvr_tracker_state_destroy not implemented");
+}
+
+gvr_display_synchronizer* gvr_display_synchronizer_create() {
+  // We don't actually support (or need) any of the synchronizer functionality,
+  // but if we return null here the gvr setup code in the app fails. Instead
+  // return a dummy object that does nothing, which allows gvr apps to work.
+  return new gvr_display_synchronizer;
+}
+
+void gvr_display_synchronizer_destroy(gvr_display_synchronizer** synchronizer) {
+  if (synchronizer) {
+    delete *synchronizer;
+    *synchronizer = nullptr;
+  }
+}
+
+void gvr_display_synchronizer_reset(
+    gvr_display_synchronizer* /* synchronizer */,
+    int64_t /* expected_interval_nanos */, int64_t /* vsync_offset_nanos */) {}
+
+void gvr_display_synchronizer_update(
+    gvr_display_synchronizer* /* synchronizer */,
+    gvr_clock_time_point /* vsync_time */, int32_t /* rotation */) {}
+
+void gvr_set_display_synchronizer(
+    gvr_context* /* gvr */, gvr_display_synchronizer* /* synchronizer */) {}
+
+void gvr_set_error(gvr_context* gvr, int32_t error_code) {
+  if (gvr->last_error_ != GVR_ERROR_NONE) {
+    ALOGW("Overwriting existing error code: %d (%s)", gvr->last_error_,
+          gvr_get_error_string(gvr->last_error_));
+  }
+  gvr->last_error_ = error_code;
+}
+
+void gvr_pause(gvr_context* gvr) {
+  if (gvr == nullptr) {
+    ALOGW("gvr_pause called with a null gvr_context. This is a bug.");
+    return;
+  }
+  for (gvr_swap_chain* swap_chain : gvr->swap_chains_) {
+    if (swap_chain->graphics_context_)
+      dvrGraphicsSurfaceSetVisible(swap_chain->graphics_context_, 0);
+  }
+}
+
+void gvr_resume(gvr_context* gvr) {
+  if (gvr == nullptr) {
+    ALOGW("gvr_resume called with a null gvr_context. This is a bug.");
+    return;
+  }
+  for (gvr_swap_chain* swap_chain : gvr->swap_chains_) {
+    if (swap_chain->graphics_context_)
+      dvrGraphicsSurfaceSetVisible(swap_chain->graphics_context_, 1);
+  }
+}
+
+void gvr_dump_debug_data(gvr_context* /* gvr */) {}
+
+bool gvr_using_vr_display_service(gvr_context* /* gvr */) { return true; }
+
+void gvr_request_context_sharing(gvr_context* /* gvr */,
+                                 gvr_egl_context_listener /* handler */,
+                                 void* /* user_data */) {}